《深入理解JavaScript》筆記

參考:深入理解JavaScript



最下面有幾點疑問,路過的朋友幫忙解答下

七、JavaScript 的語法

  1. 多行注釋 ,被/* */包裹的任意區(qū)域,它不能嵌套使用
function (a /* int */, b /* str */) {}
  1. 表達式 將會產生一個值,它可以寫在任何需要值的地方。
  2. 語句 表示了一種行為,如循環(huán)和if語句,一個程序基本上就是語句的序列。

凡是在JavaScript期望語句的地方都可以寫表達式,這樣的語句叫做表達式語句。反之則不然:不能在需要表達式的地方使用語句。

  1. 有兩種像語句的表達式類型,它們的語法類型是 二義 的。
  • 對象字面量(表達式)看上去像塊(語句):
{
  foo: bar(3, 5)
}
  • 具名函數表達式看上去像是函數聲明(語句):
function foo() {}

為了避免二義性,在解析過程中,JavaScirpt不能使用對象字面和函數表達式作為語句,即表達式語句不能以 花括號function關鍵字 內容開頭。

  1. eval 在語句的上下文中解析它的參數。如果希望 eval 返回一個對象,需要用小括號將對象字面兩括起來。
eval('{ x: 123 }')
// output: 123
eval('({ x: 123 })')
//output: { x: 123 }
  1. 在調用 數字變量 的方法時,區(qū)分是浮點數的小數點還是調用方法的點運算符是非常重要的。因此不可以寫類似 1.toString() 這樣的代碼,必須使用以下一種方式:
1..toString()
1 .toString()  // space before dot
(1).toString()
1.0.toString()
  1. 可以在 JavaScript 文件或者 <script> 標簽的第一行加入以下代碼來啟用嚴格模式:
'use strict'
 ...

也可以為每個函數啟用嚴格模式:

function foo() {
  'use strict'
   ...
}

啟用嚴格模式需要注意的問題:

  • 啟用嚴格模式可能會破壞 現有的 代碼
  • 變量必須被聲明
  • 函數必須在作用域的頂部聲明
  • arguments對象擁有更少的屬性
  • 無方法的函數中 this 的值為 undefined
  • 設置或者刪除不可改變的屬性(對屬性的非法操作)會拋出異常
  • 嚴格模式中, eval 更加簡潔
  • with 語句不能再被調用
  • 沒有八進制數字

八、值

  1. 靜態(tài)與動態(tài)。
    在編程語言的語義和類型體系環(huán)境中,靜態(tài)一般是指 “編譯時” 或 “非運行時”,動態(tài)指的是 “運行時”。
  2. 靜態(tài)類型動態(tài)類型
    在靜態(tài)類型語言中,變量、參數和對象成員(JavaScript 稱他們?yōu)閷傩裕┒加芯幾g器編譯時能識別的類型。編譯器可以通過這些信息執(zhí)行類型檢查和優(yōu)化編譯的代碼。
    即使在動態(tài)類型語言中,變量依然有一個動態(tài)的類型,是指在執(zhí)行的某一時刻變量值的類型。
    JavaScript 是動態(tài)類型語言;變量的類型在編譯的時候是不確定的。
  3. 靜態(tài)類型檢查語言 會在編譯期間進行檢查,動態(tài)類型檢查語言 會在執(zhí)行期間進行檢查。一種語言可以同時做靜態(tài)類型檢查和動態(tài)類型檢查。
    • 原始值 包括布爾值、數字、字符串、nullundefined
    • 其它值都是 對象,包括 簡單對象、數組、正則表達式

兩者之間最主要的區(qū)別是類別內是如何互相比較的。每一個對象有唯一的標識符并且只嚴格和自身相等:

let obj1 = {}
let obj2 = {}
obj1 === obj2  // false
let obj3 = obj1
obj1 === obj3  // true

相反,所有原始值,只要編碼值相同,則被認為相等

  1. 原始值具有以下特點:
    a. 按值進行比較
    b. 不可改變:其屬性不能被改變、添加或移除

    let str = 'string'
    str.length = 3
    str.length //  output: 6
    
    str.add = 'add'
    str.add //  output: undefined
    

    c. 固定類型的組合:你不能夠自定義原始值

  2. 對象的特點:
    a. 按引用進行比較

    // two different empty objects
    { } === { }  // output: false
    

    b. 默認可變

    對象屬性可以很自由地被改變、添加和移除

    c. 用戶可擴展

    構造函數可以被看做是自定義類型的補充

  3. JavaScript 有兩個“空值”用來表示信息缺失,undefinednull

    • undefined 表示“沒有值”,不存在的元數據。
    • null 表示“空值”,意思是“沒有對象”。在用到對象的時候它表示空值。

    例如,訪問一個 JSON 節(jié)點時返回值的意義如下

    • undefined 表示刪除一個對象屬性或者數組元素
    • null 表示將屬性或者元素設置為空

    undefinednull 是僅有的在訪問任何屬性拋出異常時都會得到的值

    function returnFoo(x) { return x.foo }
    returnFoo(true)  //  output: undefined
    returnFoo(0) //  output: undefined
    returnFoo(null)
    // output:  Cannot read property 'foo' of null
    returnFoo(undefined)
    // output:  Cannot read property 'foo' of undefined
    
  4. undefined 出現的場景

    • 未初始化的變量
    • 缺失的參數
    • 訪問一個不存在的屬性
    • 函數中沒有顯式地返回任何值
  5. null 出現場景

    • null 是原型鏈最頂端的元素
    Ojbect.getPrototypeOf(Object.prototype)
    //  output:  null
    
  • 當字符串中沒有匹配到正則表達式的結果時,RegExp.prototype.exec() 會返回null
    /x/.exec('aaa')
    //  output:  null
    
  1. undefinednull 的歷史
    JavaScript 采用了 Java 中將變量分為原始值和對象的處理方式。同時也使用 Java 中表示“非對象”的值 null。遵循 C語言 的先例,null 在強制轉換為數字時會變?yōu)?( Java 不會這樣)

     Number(null)
    //  output:  0
    5 + null
    // output:  5
    

值得注意的是,JavaScript 的第一版沒有異常處理。因此,在遇到未初始化的變量和缺失的參數等異常情況時需要通過一個值來表示。null 是一個很好的選擇,但是 Brendan Eich 想要在這個時候避免兩種情況。

  • 這個值不應該具有指向性,因為它表達的不僅僅是一個對象

  • 這個值的強制轉換不應該為 0,因為這會使錯誤難以發(fā)現
    因此,Eichundefined 作為另外一個空值加進了 JavaScript。它會強制轉換為 NaN

     Number(undefined)
     //output:  NaN
     5 + undefined
     //output:  NaN
    
  1. 布爾值、數字和字符串這三種原始值都有相應的構造函數:Boolean、NumberString。這些構造函數有兩種用法:

    • 作為構造函數,它們 創(chuàng)建的對象 / 實例(稱為 包裝對象 )和它們包裝的原始值有很大的不同

       typeof new  String('str')
       //output:  'object'
       new String('str') === 'str'
       //output:  false
      
    • 作為函數,它們會將值轉換為相應的原始值。這是推薦的轉換方法

       String(123)
       //output:  '123' 
       String(new String('str'))  === 'str'
      // true
      

      包裝實例是對象,而在 JavaScript 中沒有比較對象的方法,即使是通過寬松相等 ==。

       var a = new String('str')
       var b = new String('str')
       a == b
      //  false
      
  2. 原始值沒有私有方法,但是它們會從各自的包裝器中 借調 方法

     'str'.charAt === String.prototype.charAt
     //output:  true
    'str'.trim ==== String.prototype.trim
    //output:  true                
    

    寬松模式和嚴格模式會以不同的方式處理“借調”過程。
    在寬松模式中,原始值會在運行過程中轉換為包裝器:

    String.prototype.method = function () {
       console.log(this)  // String {"str"}
       console.log(typeof this)  //  object
       console.log(this instanceof String)  //  true
    }
    'str'.method()  //  call the above method
    

    在嚴格模式中,對包裝器原型方法的調用是透明的:

    String.prototype.method = function () {
      "use strict"
      console.log(this)  //  str
      console.log(typeof this)  //  string
      console.log(this instanceof String)  //  false
    }
    'str'.method()  // call the above method
    
  3. 轉換為布爾值:Boolean()

    Boolean(NaN)
    //  false
    
  4. 轉換為數字:Number()

    Number(undefined)
    //  NaN
    Number(null)
    //  0
    Number(false)
    //  0
    Number(true)
    //  1
    Number('123')
    // 123
    
  5. 轉換為字符串:String()

    String(undefined)
    //  'undefined'
    String(null)
    //  'null'
    String(false)
    //  'false'
    
  6. Object() 把對象會轉換為它們自身,undefinednull 會轉換成空對象,而原始值會轉換為包裝后的原始值。

    var obj = { foo: 123 }
    Object(obj) === obj
    //  true
    Object(null)
    //  {}
    Object(undefined)
    //  {}
    Object('abc') instanceof String
    //  true
    Object(NaN) instanceof Number
    //  true
    

九、運算符

  1. 連等賦值 x = y = 0,可以看這個案例。

  2. 復合賦值運算符,var1 op= var2,var1 = var1 op var2,這兩個表達式是等價的,其中 op 是一種二元運算符。以下列出所有的復合賦值運算符:

    • 算數運算符:+=、-+、×=/=、%=
    • 位運算符:<<=、>>=、>>>=&=、^=、|=。
    • 字符拼接:+=
  3. 寬松相等 ( == ) 和不等 ( != ) 會先嘗試將兩個不同類型的值進行轉換,再使用嚴格相等進行比較。
    如果運算數是如下類型:
    (1) undefinednull,則它們被認為是寬松相等的

    undefined == null  //  true
    

    (2) 一個字符串和一個數字,則將字符串轉換為數字,使用嚴格相等比較兩個運算數。
    (3) 一個布爾值和一個非布爾值,則將布爾值轉換為一個數字,然后(再次)進行寬松比較。

    ' '  == false  //  true
    '0' == false  //  true
    '1' == true  //  true
    '2' == true  //  false
    '2' == false  //  false
    

    (4) 一個對象和一個數字或者字符串,則嘗試轉換此對象為一個原始值(ToPrimitive() —— 將值轉換為原始值),然后(再次)進行寬松比較。
    (5) 其它情況寬松比較的結果為 false。

    特殊數字NaN和本身不相等
    NaN === NaN
    // false
    嚴格不等x !== y等價于!(x === y)



疑問1:第九章運算符下第三點,"寬松相等 ( == ) 和不等 ( != ) 會先嘗試將兩個不同類型的值進行轉換,再使用嚴格相等進行比較。",譬如:

 '1' == 1  //  true

但是比較:0 == null,我們知道Number(null)等于0,結果為什么卻是false,如果把null強制轉換為數字類型,0 == Number(null),結果為true。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容