本篇參考:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Functions
https://developer.mozilla.org/zh-CN/docs/Glossary/Scope
https://trailhead.salesforce.com/help?article=Salesforce-Certified-JavaScript-Developer-I-Exam-Guide
最近在准備備考salesforce javascript dev1,按照官方的guide的考綱進行學習,發現好多的概念和功能曾經自己是會的,但是概念理解的不深入,好多東西一變形自己就不太清楚了,所以在查看完MDN增強學習以后做一些總結,可以為了以后更好的去理解和學習。
一. 基礎數據類型與 typeof
javascript 定義了8種數據類型。
像我們常用的 Array / Set / Map / JSON等等,這些都不是基礎的數據類型,都是屬於 Object。那么給你一個變量,如何知道它屬於哪個類型呢?這個時候可以使用 typeof去做最簡單的區分。
typeof用於返回一個未經計算的操作數的類型。根據不同的數據類型會返回不同的結果。下面的表為數據類型以及返回結果之間的關系。
類型 | 結果 |
Undefined | "undefined" |
Null | "object" |
Boolean | "boolean" |
Number | "number" |
BigInt(ECMAScritp2020新增) | "bigint" |
String | "string" |
Symbol(ECMAScript2015新增) | "symbol" |
宿主對象(由js環境提供) | 取決於具體實現 |
Function對象(按照ECMA-262規范實現【Call】) | "function" |
其他任何對象 | "object" |
舉幾個例子進行更好的理解:
// 數值 typeof 37 === 'number'; typeof NaN === 'number'; // 盡管它是 "Not-A-Number" (非數值) 的縮寫 // 字符串 typeof ' ' === 'string'; typeof (typeof 1) === 'string'; // typeof 總是返回一個字符串 typeof String(1) === 'string'; // String 將任意值轉換為字符串,比 toString 更安全 // 布爾值 typeof true === 'boolean'; typeof Boolean(1) === 'boolean'; // Boolean() 會基於參數是真值還是虛值進行轉換 typeof !!(1) === 'boolean'; // 兩次調用 ! (邏輯非) 操作符相當於 Boolean() // Symbols typeof Symbol('foo') === 'symbol'; // Undefined typeof undefined === 'undefined'; typeof declaredButUndefinedVariable === 'undefined'; // Object // 使用 Array.isArray 或者 Object.prototype.toString.call // 區分數組和普通對象 typeof [1, 2, 4] === 'object'; typeof null === 'object'; typeof new Date() === 'object'; // 函數 typeof function() {} === 'function'; typeof class C {} === 'function' // 下面的例子令人迷惑,非常危險,沒有用處。避免使用它們。因為當使用 new關鍵字去聲明變量時,只有 Function 會返回function,其他都會返回 object。 typeof new Boolean(true) === 'object'; typeof new Number(1) === 'object'; typeof new String('abc') === 'object';
二. Falsy 值 情況總結
針對Boolean布爾類型大家肯定都不陌生,布爾類型只有兩個值,一個是true,也叫Truthy, 一個是false,也叫 Falsy。我們在用布爾類型時,好多時候都不是直接賦值一個變量是 true / false,而是通過表達式通過上下文強制轉換將值轉換成布爾值。下面整理一下所有的 Falsy的情況,除了以下的情況,便都是Truthy。
值 | 解釋 |
false | false關鍵字 |
0 | 數值 0 |
-0 | 在數值中分成 +0 、-0,-0也被代表false |
On | 當 BigInt 作為布爾值使用時, 遵從其作為數值的規則. 0n 是 falsy 值. |
"", ", `` | 這是一個空字符串 (字符串的長度為零). JavaScript 中的字符串可用雙引號 "" , 單引號 '' , 或 模板字面量 `` 定義。 |
null | null - 缺少值 |
undefined | undefined - 原始值 |
NaN | NaN - 非數值 |
舉一個例子更好的理解:我們看着 []沒有值或者 {}沒有值以為是 false,其實按照上面的表格,不包含他們,所以只要是不包含,都是 true的情況,執行以后的結果為 execute true
let test = []; if(test) { console.log('execute true'); } else { console.log('execute false'); }
三 . Function 與 Scope
函數在我們日常開發中極其常見。我們在函數聲明時通常使用兩種。函數聲明式 以及 函數表達式, 除了這兩種情況我們還可以使用 構造函數方式聲明一個函數。針對每一樣舉一個簡單例子。
函數表達式:下面聲明了一個階乘函數,用來算 3!的值,我們可以看到前面使用一個變量 = function 形式,function可以有名字,也可以沒有名字。比如下面的square函數就沒有函數名稱。
const factorial = function fac(n) { return n<2 ? 1 : n*fac(n-1) }; console.log(factorial(3)); const square = function(number) { return number * number; }; let x = square(4); // x gets the value 16
函數聲明式:對上面的square函數進行一下變形,這種函數聲明也是我們用的特別多的。
function square(number) { return number * number; }
使用構造函數聲明
const sum = new Function('a', 'b', 'return a + b'); console.log(sum(2, 6));
說完函數聲明以后,接下來就是函數嵌套以及作用域的問題。你可以在一個函數里面嵌套另外一個函數。嵌套(內部)函數對其容器(外部)函數是私有的。它自身也形成了一個閉包。一個閉包是一個可以自己擁有獨立的環境與變量的表達式(通常是函數)。
既然嵌套函數是一個閉包,就意味着一個嵌套函數可以”繼承“容器函數的參數和變量。換句話說,內部函數包含外部函數的作用域。
可以總結如下:
- 內部函數只可以在外部函數中訪問。
- 內部函數形成了一個閉包:它可以訪問外部函數的參數和變量,但是外部函數卻不能使用它的參數和變量。
閉包的詳細描述可以查看上面的針對函數的鏈接。通過嵌套函數了解一下三種函數的作用域區別。
let param = 'test out'; function outer() { let param = 'test inner'; function functionUsingExpression() { console.log(param); } let functionUsingDefine = function() { console.log(param); }; let functionWithConstructor = new Function('\tconsole.log(param);'); functionUsingExpression(); functionUsingDefine(); functionWithConstructor(); } outer();
輸出結果:
通過結果可以發現當我們使用函數表達式和函數聲明式方式情況下,使用當前scope的變量,當我們使用構造函數方式聲明的函數時,不繼承當前的scope,需要使用全局的變量。
總結:篇中針對考綱做了簡單地三個總結。篇中有錯誤地方歡迎指出,有不懂歡迎留言。