You don't know JS 讀書筆記(一)

前言git

這裏記錄着本身閱讀You don't know JS系列叢書的一些心得體會,也算是本身對JavaScript知識的一個總結吧。 高能預警:文章較長且瑣碎,請自備板凳瓜子~github

Types(類型)

Variables don’t have types, but the values in them do。數組

這句話的意思是說:變量是沒有類型的,變量裏面存的值纔是有類型的。好比我聲明一個變量var a;,此時a是不具備任何類型信息的。若是我給a賦值一個字符串a = "Hello, World", 那麼typeof a獲得的信息string表示的是a裏面的值"Hello, World"的類型信息。若是我如今從新給a賦值,a = 0,由於a裏面存的值的類型已經發生變化,那麼typeof a獲得的信息也變成相應的number。這和靜態語言好比C/C++/Java是不同的,C/C++/Java在定義變量就指定了變量的類型,每一個變量只能存儲和本身類型匹配的值。安全

打個簡單的比方,JavaScript的變量就像是一個瑞士軍包,啥都能裝,能裝書、裝水、裝衣服,對了還能裝逼,種類不限(通用)。可是C/C++/Java的變量就像是錢包,它設計之初就是爲了裝錢,因此它只能裝錢(專用),若是要裝其餘的東西好比各類卡啊什麼的,就要把這些卡也看成錢裝進去,這就是所謂的強制類型轉換app

Many developers will assume 「undefined」 and 「undeclared」 are roughly the same thing, but in JavaScript, they’re quite different. undefined is a value that a declared variable can hold.「Undeclared」means a variable has never been declared.ide

這句話的意思是:undefinedundeclared是兩個徹底不一樣的概念,不少人會混淆二者。在JavaScript中,undefined表示一個變量已經聲明,可是尚未爲其賦值,此時變量裏面裝的值就是undefined。好比:函數

var a;
console.log(a);//undefined

可是undeclared表示一個變量從未被申明過,也就是在用這個變量以前,它從未在前面的代碼中出現過(申明過),徹底是忽然出現的,此時對這個變量的讀寫操做都會致使解釋器報錯並中止運行。好比:ui

console.log(b);//Uncaught ReferenceError: b is not defined(…)

有時候爲了判斷某個變量(好比a)是否爲undefined,通常的作法是if(a != undefined),可是這樣存在一個問題,若是a沒有申明過呢?這樣就會形成解釋器報錯,爲了防止這種狀況發生,咱們能夠利用類型判斷操做符typeof來進行安全的判斷:if(typeof a != undefined)typeof對與沒有申明的變量也能安全的處理,並返回undefinedlua

Values(值)

Using delete on an array value will remove that slot from the array, but even if you remove the final element, it does not update the length property, so be careful!spa

這句話的意思是說:再利用delete操做符刪除數組裏面的某個元素時, 其實將那個元素裏面的值給清空了(置爲undefined),可是那個元素(slot)還在數組裏,數組的長度並無發生變化。 好比:

var arr = [1,2,3,4,5];
delete arr[0];//arr => [undefined × 1, 2, 3, 4, 5]
for(var i = 1; i < arr.length; i ++) {
  delete arr[i];
}// arr => [undefined × 5]

 

補充一點,假設你想建立一個數組,要求裏面的元素全是undefined,若是你這樣作:

var array = new Array(10);

 

實際上是不對的。由於這樣獲得的數組實際上並無10個插槽(slot),它是空的,只是它的length屬性爲10而已。若是在控制檯裏面查看,你會獲得這樣的結果:[undefined × 10]。想要真正獲得10個元素全爲undefined的數組,你應該這樣作:

var array = Array.apply(null, {length:10});

在控制檯中查看array能夠發現爲[undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined],和上面獲得的結果明顯不一樣。

JavaScript strings are immutable, while arrays are quite mutable. A further consequence of immutable strings is that none of the string methods that alter its contents can modify in-place, but rather must create and return new strings. By contrast, many of the array methods that change array contents actually do modify in place.

這句話的意思是:JavaScript的字符串是不可變的(相似於C/C++的字符串),而數組是可變的。字符串的不可變帶來的影響就是其方法並不能直接修改字符串的內容,而是從新返回一個新的字符串。與此不一樣的是,數組的方法能夠直接修改內容。

Simple scalar primitives (strings, numbers, etc.) are assigned/passed by value-copy, but compound values (objects, etc.) are assigned/ passed by reference-copy. References are not like references/pointers in other languages—they’re never pointed at other variables/references, only at the underlying values.

基本類型(string,number,boolean)賦值/傳值是進行的值傳遞,而混合類型(object,array等)是進行的引用賦值/傳值,還有一點須要注意的是JavaScript的引用不像其餘語言的引用,它是指向值自己。據個例子:

var obj = {
  x: 1
};
function foo(obj) {
  obj = {x: 2};
}
foo();
console.log(x); // Object {x: 1}
foo()函數給obj從新賦值了,可是並無改變外層定義的obj。

 

Native(原生類型)

Primitive values don’t have properties or methods, so to access .length or .toString() you need an object wrapper around the value. Thankfully, JS will automatically box (aka wrap) the primitive value to fulfill such accesses

這句話的意思是:基本數據類型並無屬性或方法,當你須要在基本數據類型上執行諸如.length.toString()的操做的時候,你須要一個對象Object來包裝這個基本數據類型。使人欣慰的是,在執行這樣的操做的視乎,JavaScript會自動將其進行包裝。

因此,對於一個字符串,咱們是能夠直接獲取字符串的長度的,也能夠執行許多字符串的方法,好比.indexOf()等等。

Coercion(自動類型轉換)

自動類型轉換比較複雜,爲了說明他們各自的轉換規則,我繪製了一張腦圖來講明(圖片較大,請保存下來用1:1的比例查看): 

接下來講一下會引起飲食類型轉換的兩個操做,+-運算。

首先說一下+運算。 ECMA-262#11.6.1 對the Addition operator ( + )有以下描述:

The addition operator either performs string concatenation or numeric addition. The production AdditiveExpression : AdditiveExpression + MultiplicativeExpression is evaluated as follows:

  1. Let lref be the result of evaluating AdditiveExpression.
  2. Let lval be GetValue(lref).
  3. Let rref be the result of evaluating MultiplicativeExpression.
  4. Let rval be GetValue(rref).
  5. Let lprim be ToPrimitive(lval).
  6. Let rprim be ToPrimitive(rval).
  7. If Type(lprim) is String or Type(rprim) is String, then Return the String that is the result of concatenating ToString(lprim) followed by ToString(rprim)
  8. Return the result of applying the addition operation to ToNumber(lprim) and ToNumber(rprim). See the Note below 11.6.3.

  9. NOTE 1 No hint is provided in the calls to ToPrimitive in steps 5 and 6. All native ECMAScript objects except Date objects handle the absence of a hint as if the hint Number were given; Date objects handle the absence of a hint as if the hint String were given. Host objects may handle the absence of a hint in some other manner.

  10. NOTE 2 Step 7 differs from step 3 of the comparison algorithm for the relational operators (11.8.5), by using the logical-or operation instead of the logical-and operation.

上面一段話比較晦澀難懂,大概意思是當執行相加操做時,若是左操做數或右操做數不是基本數據類型(primitive)時,會對其進行ToPrimitive轉換(具體轉換過程可見上面的腦圖),這樣,左操做數和右操做數都是基本數據類型了,可是若是左右兩邊的數據類型不一致該怎麼辦呢?這就涉及到一個優先級的問題,低優先級的數據類型會主動轉換爲和高優先級同樣的數據類型,而後再進行相加操做。它們的優先級關係爲:string > num > boolean,因此就會存在兩種相加操做:字符串拼接和數字相加。具體的流程能夠見下圖:

舉例說明:

1 "1" + 1;//"11"
2 1 + true;// 2
3 "1" + true// "1true"

 

對於-操做就單純的多了,只是進行數值相減。ECMA#11.6.2上的描述爲:

The production AdditiveExpression : AdditiveExpression - MultiplicativeExpression is evaluated as follows:

  1. Let lref be the result of evaluating AdditiveExpression.
  2. Let lval be GetValue(lref).
  3. Let rref be the result of evaluating MultiplicativeExpression.
  4. Let rval be GetValue(rref).
  5. Let lnum be ToNumber(lval).
  6. Let rnum be ToNumber(rval).
  7. Return the result of applying the subtraction operation to lnum and rnum. See the note below 11.6.3.

大概意思爲對於非數值類型的左右操做數進行ToNumber(詳情見上面的腦圖),而後再進行數值相減運算。流程以下圖所示:

舉例說明:

"1" - 1;//0
"1" - true //0
1 - "true" // 0

 原文地址:http://natumsol.github.io/2015/12/03/you-don-t-know-js-notes-series1/

相關文章
相關標籤/搜索