JavaScript權威指南(4)——表示式和運算子

夕陽下的奔跑發表於2019-07-20

表示式和運算子

原始表示式

  1. 原始表示式包括常量或直接量、關鍵字和變數

物件和陣列的初始化表示式

  1. 這些表示式可以巢狀

函式定義表示式

  1. 函式表示式可稱為函式直接量

屬性訪問表示式

  1. 表示式後跟句點和識別符號,或者使用方括號

呼叫表示式

  1. 對呼叫表示式進行求值時,先計算函式表示式,再計算參數列達式,得到一組引數值

物件建立表示式

  1. 和函式呼叫表示式類似,多了一個關鍵字new

運算子概述

  1. JavaScript運算子

JavaScript權威指南(4)——表示式和運算子

JavaScript權威指南(4)——表示式和運算子

  1. 運算元的個數:大多數是二元運算子,還有一元運算子(-x),三元運算子(?:)
  2. 運算元型別和結果型別——運算子會根據需要對運算元進行型別轉換
  3. 左值——表示式只能出現在賦值運算子的左側
  4. 運算子的副作用——賦值,如++,--,delete,如果在函式體或者建構函式內部運用了這些運算子併產生了副作用的時候,可以說函式呼叫表示式和物件建立表示式是有副作用的
  5. 運算子優先順序——賦值運算的優先順序非常低,可以用圓括號強行指定運算次序
  6. 運算子的結合性——上表中L指從左至右結合,R指從右至左結合
  7. 運算順序——按照從左至右的順序來計算表示式

算術表示式

  1. 如果運算元是NaN值,算術運算的結果也是NaN
  2. “+”優先考慮字串連線,如果其中一個運算元是字串或者轉換為字串的物件,另一個運算元將會轉換為字串,加法將進行字串的連線操作
    1. 如果其中一個運算元是物件,則物件遵循物件到原始值的轉換規則轉換為原始類值:日誌通過toString執行轉換,其他物件則通過valueOf執行轉換。多數物件不具備可用的valueOf,會通過toString執行轉換
    2. 在進行了物件到原始值的轉換後,如果其中一個運算元是字串,另一個也會轉換為字串,進行字串連線
    3. 否則,兩個運算元都轉換為數字(或NaN),進行加法操作
  3. 一元運算子——優先順序高,且都是右結合(一元+,-,++,--)
  4. 位運算子——&,|,^,~,<<,>>,>>>無符號右移

關係表示式

  1. ===嚴格相等運算子,==相等運算子,允許型別轉換
  2. JavaScript物件的比較是引用的比較,而不是值的比較
  3. ===的比較過程:
    1. 如果兩個值型別不同,則不相等
    2. 如果兩個值都是null或或者undefined,則不相等
    3. 如果連個值都是true或者都是false,則相等
    4. 如果其中一個是NaN,或者兩個都是NaN,則不相等,NaN和任何值都不相等,包括它本身。通過x!==x來判斷x是否為NaN,只有在x為NaN的時候,才為true
    5. 如果兩個值為數字,且數值相等,則相等,如果一個是0,另一個是-0,則相等
    6. 如果兩個值是字串,且所含對應位上的16位數完全相等,則相等。如果它們的長度或內容相等,則它們不等。兩個字串可能含義完全一樣且所顯示出的字元也一樣,但具有不同編碼的16位值。JavaScript並不對Unicode進行標準化的轉換,因此像這樣的字串通過“===”和“==”運算子的比較結果也不相等。
    7. 如果兩個引用值指向同一個物件、陣列或函式,則相等。如果指向不同的物件,則不等。
  4. ==的比較過程
    1. 如果兩個運算元的型別相同,則和===的規則一樣,如果嚴格相等,那麼結果為相等
    2. 型別不同,“==”也可能認為它們相等,需要遵守如下規則和型別轉換:
      1. 一個值是null,另一個是undefined,則它們相等
      2. 如果一個是數字,另一個是字串,先將字串轉換為數字,然後再比較
      3. 如果一個是true,先轉換為1再比較,如果是false,轉換為0
      4. 如果一個是物件,另一個是數字或字串,則將物件轉換為原始值,再進行比較。內建型別先嚐試使用valueOf,再使用toString。日期類只使用toString
      5. 其他型別均不相等
  5. 比較運算子——只有數字和字串才能執行比較操作,型別轉換規則
    1. 物件轉換為原始值
    2. 如果一個運算元不是字串,那麼兩個運算元都轉換為數字進行數值比較
    3. 0和-0相等,Infinity比其他數字大,-Infinity比其他數字小,如果一個運算元是NaN,那麼總是返回false
  6. in運算子
  7. instanceof運算子——原型鏈

邏輯表示式

  1. &&當運算元都是布林值,執行與操作
  2. &&可以對真值和假值進行與操作,如果都是真值則返回一個真值,否則返回一個假值
  3. &&的短路行為
  4. ||對布林值進行運算。如果其中一個或兩個運算元是真值,它返回一個真值。如果兩個是假值,則返回幾個假值。
  5. !x,如果x是真值,返回false,如果是假值,返回true

賦值表示式

  1. (a==b) == 0,=優先順序較低,需要用圓括號
  2. =的結合性是從右到做——一個表示式中出現多個賦值運算子,運算順序是從右到左
  i=j=k=0   //三個變數初始化為0
複製程式碼
  1. 帶操作的賦值運算

    Operator Example Equivalent

    >>= a >>= b a = a >> b
    >>>= a >>>= b a = a >>> b
    &= a &= b a = a & b
    |= a |= b a = a | b
    ^= a ^= b a = a ^ b

表示式計算

  1. eval()是一個函式,被當做運算子來對待。①用於動態執行的程式碼通常來講是不能分析,直譯器無法對它做進一步的優化;②它可以被賦予其他名字,如var f =eval則直譯器將無法放心地優化任何呼叫f()的函式。如果eval是一個運算子,可以避免該問題。
  2. eval()只有一個引數。
    1. 如果引數不是字串,則直接返回這個引數。
    2. 如果是字串,會將字串當成JavaScript程式碼進行編譯,如果編譯失敗則丟擲一個語法錯誤異常。
    3. 如果編譯成功,則開始執行這段程式碼,並返回字串的最後一個表示式或語句的值
    4. 如果最後一個表示式或語句沒有值,則返回undefined
    5. 如果字串丟擲一個異常,這個異常將把該呼叫傳遞給eval()
  3. **eval()**使用了呼叫它的變數作用域環境——查詢變數的值和定義新變數和函式的操作和區域性作用於中程式碼完全一樣。如果在最頂層程式碼中呼叫eval(),則會作用於全域性變數和全域性函式
  4. 需要保證傳遞給eval()的字串在語義上講的通——不能通過eval()往函式中任意貼上程式碼片段,比如,eval("return;")是沒有意義的。
  5. 全域性eval()——ES 3規定任何直譯器不允許對eval()賦予別名,如果eval()函式通過別名呼叫的話,會丟擲一個EvalError異常
  6. 大多數實現:當通過別名呼叫時,eval()會將其字串當成頂層的全域性程式碼來執行。執行的程式碼可能會定義新的全域性變數和全域性函式,或者給全域性變數賦值,但卻不能使用或修改主調函式中的區域性變數(這樣不會影響到函式內的程式碼優化)
  7. ES 5的規則——直接的eval,直接呼叫eval()時,總是在呼叫它的上下文作用域內執行。其他的間接呼叫則使用全域性物件作為其上下文作用域,並且無法讀、寫、定義區域性變數和函式。
 var geval = eval; // Using another name does a global eval
 var x = "global", y = "global"; // Two global variables
 function f() { // This function does a local eval
     var x = "local"; // Define a local variable
     eval("x += 'changed';"); // Direct eval sets local variable
     return x; // Return changed local variable
 }
 function g() { // This function does a global eval
     var y = "local"; // A local variable
     geval("y += 'changed';"); // Indirect eval sets global variable
     return y; // Return unchanged local variable
 }
 console.log(f(), x); // Local variable changed: prints "localchanged global":
 console.log(g(), y); // Global variable changed: prints "local globalchanged":
複製程式碼
  1. 嚴格eval():在嚴格模式下呼叫eval()時,或者eval()執行的程式碼段以“use strict”指令開始,這裡的eval()是私有上下文環境中的區域性eval。在嚴格模式下,eval執行的程式碼可以查詢或更改區域性變數,但不能在區域性作用域中定義新單變數或函式

其他運算子

  1. 條件運算子?:——三元運算子
  2. typeof運算子
    JavaScript權威指南(4)——表示式和運算子
  3. delete運算子——用來刪除物件屬性或者陣列元素
    1. delete希望運算元是一個左值,如果不是,delete不進行操作並返回true
    2. delete成功,返回true,否則返回false
    3. 並不是所有的屬性都可刪除,一些內建核心和客戶端屬性是不能刪除的
    4. 使用者通過var語句宣告的變數不能刪除
    5. 通過function語句定義的函式和函式引數也不能刪除
    6. ES 5中如果delete的運算元是非法的,比如變數、函式或函式引數,將丟擲一個語法錯誤
    7. 在嚴格模式下,delete刪除不可配置的屬性會丟擲一個型別錯誤異常;非嚴格模式下,只是返回false
  var o = {x:1, y:2}; // Define a variable; initialize it to an object
  delete o.x; // Delete one of the object properties; returns true
  typeof o.x; // Property does not exist; returns "undefined"
  delete o.x; // Delete a nonexistent property; returns true
  delete o; // Can't delete a declared variable; returns false.
  // Would raise an exception in strict mode.
  delete 1; // Argument is not an lvalue: returns true
  this.x = 1; // Define a property of the a global object without var
  delete x; // Try to delete it: returns true in non-strict mode
複製程式碼
  1. void運算子——常用在javascript:URL中,void讓瀏覽器不必顯示這個表示式的計算結果。如:
  <a href="javascript:void window.open();">Open New Window</a>
複製程式碼
  1. 逗號運算子

相關文章