JavaScript快速入門(五)——運算式運算

來源:互聯網
上載者:User

JavaScript快速入門(五)——運算式運算
賦值運算賦值運算的形式為左值 = 右值。如果同個運算式中有多個賦值運算,則從右至左運算。例如:

a = b = c; // 和下面兩行等價b = c;a = b;
另外一種賦值運算的形式叫做複合賦值運算子,形式為左值 op= 右值,其中op=表示部分運算子和=的結合,a op= b和 a = a op b等價。例如下面兩句是等價的:
a += b;a = a + b;
其中op可以是下列運算子之一: +,-,*,/,%,<<,>>,>>>,&,|,^
數值運算數值運算的運算元都是數值類型,運算子是+,-,*,/,%中的一個,形式為a op b,目標類型也是數值類型。例如:
var a = 3 + 5; // a == 8
特別的,++,--分別表示遞增和遞減,形式為a op或者op a,a++效果等同與a = a + 1。例如:
var a = 0;a++; // a = 1
要特別注意的是,++a跟a++是不一樣的,在複雜運算裡面。++a表示先將a遞增再將更新過的a值參與運算,而a++表示先將原來的a值參與運算再遞增。例如:
var a = 1;var b = 1 + (a++); // b == 2console.log(a); // 2b = 1 + (++a);  // b == 4console.log(a); // 3
當然,如果一條語句裡只有遞增語句,則不需要區分。
var a = 1;a++; // a == 2++a; // a == 3
位元運算位元運算的運算元和目標類型都是數值類型,運算子為~,&,|,^,<<,>>等中的一個。特別注意的是,位元運算是針對位元進行運算,即會先將數值轉化為二進位,運算結果也是位元,當然,我們看到的時候已經被轉化為十進位數了,如果沒有特別指定的話。從ECMAScript的整數說起

ECMAScript 整數有兩種類型,即有符號整數(允許用正數和負數)和不帶正負號的整數(只允許用正數)。在 ECMAScript 中,所有整數字面量預設都是有符號整數,這意味著什麼呢?

有符號整數使用 31 位表示整數的數值,用第 32 位表示整數的符號,0 表示正數,1 表示負數。數值範圍從 -2147483648 到 2147483647。

可以以兩種不同的方式儲存二進位形式的有符號整數,一種用於儲存正數,一種用於儲存負數。正數是以真二進位形式儲存的,前 31 位中的每一位都表示 2 的冪,從第 1 位(位 0)開始,表示 20,第 2 位(位 1)表示 21。沒用到的位用 0 填充,即忽略不計。例如,展示的是數 18 的標記法。

18 的二進位版本只用了前 5 位,它們是這個數位有效位。把數字轉換成二進位字串,就能看到有效位:

var iNum = 18;alert(iNum.toString(2));//輸出 "10010"

這段代碼只輸出 "10010",而不是 18 的 32 位表示。其他的數位並不重要,因為僅使用前 5 位即可確定這個十進位數值。如所示:

負數也儲存為二進位代碼,不過採用的形式是二進位補碼。計算數字二進位補碼的步驟有三步:

  1. 確定該數位非負版本的二進位表示(例如,要計算 -18的二進位補碼,首先要確定 18 的二進位表示)
  2. 求得二進位反碼,即要把 0 替換為 1,把 1 替換為 0
  3. 在二進位反碼上加 1

    要確定 -18 的二進位表示,首先必須得到 18 的二進位表示,如下所示:

    0000 0000 0000 0000 0000 0000 0001 0010

    接下來,計算二進位反碼,如下所示:

    1111 1111 1111 1111 1111 1111 1110 1101

    最後,在二進位反碼上加 1,如下所示:

    1111 1111 1111 1111 1111 1111 1110 1101                                      1---------------------------------------1111 1111 1111 1111 1111 1111 1110 1110

    因此,-18 的二進位表示即 1111 1111 1111 1111 1111 1111 1110 1110。記住,在處理有符號整數時,開發人員不能訪問 31 位。

    有趣的是,把負整數轉換成二進位字串後,ECMAScript 並不以二進位補碼的形式顯示,而是用數字絕對值的標準二進位代碼前面加負號的形式輸出。例如:

    var iNum = -18;alert(iNum.toString(2));//輸出 "-10010"

    這段代碼輸出的是 "-10010",而非二進位補碼,這是為避免訪問位 31。為了簡便,ECMAScript 用一種簡單的方式處理整數,使得開發人員不必關心它們的用法。

    另一方面,不帶正負號的整數把最後一位作為另一個數位處理。在這種模式中,第 32 位不表示數位符號,而是值 231。由於這個額外的位,不帶正負號的整數的數值範圍為 0 到 4294967295。對於小於 2147483647 的整數來說,不帶正負號的整數看來與有符號整數一樣,而大於 2147483647 的整數則要使用位 31(在有符號整數中,這一位總是 0)。

    把不帶正負號的整數轉換成字串後,只返回它們的有效位。

    注意:所有整數字面量都預設儲存為有符號整數。只有 ECMAScript 的位元運算符才能建立不帶正負號的整數。

    NOT運算(~)

    非運算 NOT 由否定號(~)表示,它是一元運算子(運算元只有一個),形式為~a。

    位元運算 NOT 是三步的處理過程:

    1. 把運算數轉換成 32 位元字
    2. 把位元轉換成它的二進位反碼
    3. 把位元轉換成浮點數

      例如:

      var iNum1 = 25;//25 等於 00000000000000000000000000011001var iNum2 = ~iNum1;//轉換為 11111111111111111111111111100110alert(iNum2);//輸出 "-26"

      位元運算 NOT 實質上是對數字求負,然後減 1,因此 25 變 -26。用下面的方法也可以得到同樣的方法:

      var iNum1 = 25;var iNum2 = -iNum1 -1;alert(iNum2);//輸出 -26

      AND運算(&)

      與運算 AND 由和號(&)表示。它把每個數字中的數位對齊,然後用下面的規則對同一位置上的兩個數位進行 AND 運算(若且唯若兩個數位都是1時才返回1):

      第一個數字中的數位 第二個數字中的數位 結果
      1 1 1
      1 0 0
      0 1 0
      0 0 0

      例如,要對數字 25 和 3 進行 AND 運算,代碼如下所示:

      var iResult = 25 & 3;alert(iResult);//輸出 "1"

      25 和 3 進行 AND 運算的結果是 1。為什嗎?分析如下:

       25 = 0000 0000 0000 0000 0000 0000 0001 1001  3 = 0000 0000 0000 0000 0000 0000 0000 0011---------------------------------------------AND = 0000 0000 0000 0000 0000 0000 0000 0001

      可以看出,在 25 和 3 中,只有一個數位(位 0)存放的都是 1,因此,其他數位產生的都是 0,所以結果為 1。

      OR運算(|)

      或運算 OR 由符號(|)表示。在計算每位時,OR 運算子採用下列規則(若且唯若兩個數位都是0時才返回0):

      第一個數字中的數位 第二個數字中的數位 結果
      1 1 1
      1 0 1
      0 1 1
      0 0 0

      仍然使用 AND 運算子所用的例子,對 25 和 3 進行 OR 運算,代碼如下:

      var iResult = 25 | 3;alert(iResult);//輸出 "27"

      25 和 3 進行 OR 運算的結果是 27:

      25 = 0000 0000 0000 0000 0000 0000 0001 1001 3 = 0000 0000 0000 0000 0000 0000 0000 0011--------------------------------------------OR = 0000 0000 0000 0000 0000 0000 0001 1011

      可以看出,在兩個數字中,共有 4 個數位存放的是 1,這些數位被傳遞給結果。二進位代碼 11011 等於 27。

      XOR運算(^)

      異或運算 XOR 由符號(^)表示。XOR 不同於 OR,當有且只有一個數位存放的是 1 時,它才返回 1。真值表如下:

      第一個數字中的數位 第二個數字中的數位 結果
      1 1 0
      1 0 1
      0 1 1
      0 0 0

      對 25 和 3 進行 XOR 運算,代碼如下:

      var iResult = 25 ^ 3;alert(iResult);//輸出 "26"

      25 和 3 進行 XOR 運算的結果是 26:

       25 = 0000 0000 0000 0000 0000 0000 0001 1001  3 = 0000 0000 0000 0000 0000 0000 0000 0011---------------------------------------------XOR = 0000 0000 0000 0000 0000 0000 0001 1010

      可以看出,在兩個數字中,共有 4 個數位存放的是 1,這些數位被傳遞給結果。二進位代碼 11010 等於 26。

      左移運算(<<)

      左移運算由兩個小於符號表示(<<)。它把數字中的所有數位向左移動指定的數量。例如,把數字 2(等於二進位中的 10)左移 5 位,結果為 64(等於二進位中的 1000000):

      var iOld = 2;//等於二進位 10var iNew = iOld << 5;//等於二進位 1000000 十進位 64

      注意:在左移數位時,數字右邊多出 5 個空位。左移運算用 0 填充這些空位,使結果成為完整的 32 位元字。

      注意:左移運算保留數位符號位。例如,如果把 -2 左移 5 位,得到的是 -64,而不是 64。“符號仍然儲存在第 32 位中嗎?”是的,不過這在 ECMAScript 後台進行,開發人員不能直接存取第 32 個數位。即使輸出二進位字串形式的負數,顯示的也是負號形式(例如,-2 將顯示 -10。)

      右移運算(>>)

      有符號右移運算

      有符號右移運算子由兩個大於符號表示(>>)。它把 32 位元字中的所有數位整體右移,同時保留該數的符號(正號或負號)。有符號右移運算子恰好與左移運算相反。例如,把 64 右移 5 位,將變為 2:

      var iOld = 64;//等於二進位 1000000var iNew = iOld >> 5;//等於二進位 10 十進位 2

      同樣,移動數位後會造成空位。這次,空位位於數位左側,但位於符號位之後。ECMAScript 用符號位的值填充這些空位,建立完整的數字,如所示:

      無符號右移運算

      無符號右移運算子由三個大於符號(>>>)表示,它將無符號 32 位元的所有數位整體右移。對於正數,無符號右移運算的結果與有符號右移運算一樣。

      用有符號右移運算中的例子,把 64 右移 5 位,將變為 2:

      var iOld = 64;//等於二進位 1000000var iNew = iOld >>> 5;//等於二進位 10 十進位 2

      對於負數,情況就不同了。

      無符號右移運算用 0 填充所有空位。對於正數,這與有符號右移運算的操作一樣,而負數則被作為正數來處理。

      由於無符號右移運算的結果是一個 32 位的正數,所以負數的無符號右移運算得到的總是一個非常大的數字。例如,如果把 -64 右移 5 位,將得到 134217726。如何得到這種結果的呢?

      要實現這一點,需要把這個數字轉換成無符號的等價形式(儘管該數字本身還是有符號的),可以通過以下代碼獲得這種形式:

      var iUnsigned64 = -64 >>> 0;

      然後,用 Number 類型的 toString() 擷取它的真正的位表示,採用的基為 2:

      alert(iUnsigned64.toString(2));

      這將產生 11111111111111111111111111000000,即有符號整數 -64 的二進位補碼錶示,不過它等於不帶正負號的整數 4294967232。

      出於這種原因,使用無符號右移運算子要小心。

      邏輯運算邏輯運算分為兩種,一種會改變目標資料類型,另一種則不會。前者的典型代表是邏輯非運算,無論運算元是什麼類型,執行邏輯非運算後,都會被轉化為bool值。例如:
      var a = "123";var b = !a; // false
      而另一種形式則不改變目標類型,且支援布爾短路,包括“邏輯與”(&&)和“邏輯或”(||)運算。所謂布爾短路,指的是指判斷第一個運算元就決定運算結果,而不需要處理第二個運算元。具體運算規則如下:第一個運算元為真時,邏輯或運算返回第一個運算元(注意,沒有改變類型),邏輯與運算返回第二個運算元第一個運算元為假時,邏輯或運算返回第二個運算元,邏輯與運算返回第一個運算元我們來舉幾個特殊點的例子:
      function and(a, b) {    return a && b;}function or(a, b) {    return a || b;}var a = and("str", false); // a === falsevar b = or("str", false);  // b === "str"var c = and(0, "str2");    // c === 0var d = or(0, "str2");     // d === "str2"
      這種運算最常見的用法是處理實參。我們知道,JavaScript中的實參列表和形參列表可以長度不等,那麼,如何處理不等的部分呢?我們舉個例子:
      function add(a, b) {    return a + b;}var a = add(5); // NaN
      結果是NaN,這明顯不是我們想要的結果,我們更願意它返回5。我們可以利用邏輯運算:
      function add(a, b) {    b = b || 0;    return a + b;}var a = add(5);     // 5var b = add(5, 2); // 7
      如果形參長度大於實參長度,超過的部分將是undefined。而b = b || 0這句能在b為undefined(布爾值為false)的時候,把0賦給b,使得b仍然為數值類型,並參與運算。當然,這樣處理還是很簡陋的,比如當傳入的b為非Null 字元串的時候,這個函數還是會出錯,所以正確的做法應該是判斷是不是數值類型,但在排除API使用者亂來的情況下,邏輯運算不失為一種好辦法。

      字串運算JavaScript中,有且只有一種字串運算,那就是字串串連。當然,字串也可以參與其他運算,比如比較、等值、賦值等運算,但我們把它們放到其他分類去講。string類型裡內建的方法,例如切割字串等等,也不屬於我們這裡講的運算式運算。字串串連運算對應的運算子號是“+”。請注意,“+”是一個多義性符號,它既可以用於數值加法運算,也可以用於一元運算子,還能用於字串串連。具體用於那種運算,由運算元的數量和類型決定。當存在兩個或以上的運算元,且開頭兩個運算元其中一個是字串類型時,會將其他非字串的轉化為字串,目標類型為字串。例如:
      var a = "str" + "ing"; // a === "string"var b = "str" + 0;       // b === "str0"var c = 0 + "str";        // c === "0str"var d = "str" + undefined; // d === "strundefined"var e = null + "str" + undefined; // e === "nullstrundefined"var f = null + undefined + "str"; // f == NaN


      比較運算等值檢測等值檢測的目的在於判斷兩個變數是否相同或相等。我們說相同與不相同,是指運算子“===”和“!==”的運算效果;說相等與不相等,是指運算子“==”和“!=”的運算效果。我們可以用個表格來表示:
      比較運算中的等值檢測
      名稱 運算子 說明
      相等 == 比較兩個運算式,看是否相等
      不等 != 比較兩個運算式,看是否不相等
      嚴格相等 === 比較兩個運算式,看值是否相等並具有相同的資料類型
      不嚴格相等 !== 比較兩個運算式,看是否具有不相等的值或資料類型不同
      等值檢測中相等運算規則
      等值檢測中的相等運算規則
      類型 運算規則
      兩個值類型進行比較 轉換成相同資料類型的值進行資料等值比較
      值類型與參考型別比較 將參考型別的資料轉換為值類型,再進行資料等值比較
      兩個參考型別比較 比較引用的地址
      對值類型和參考型別概念模糊的可以去看之前的JavaScript變數一文。等值檢測中相同運算規則
      等值檢測中相同運算規則
      類型 運算規則
      兩個值類型進行比較 資料類型不同,則必然不相同
      資料類型相同時,進行數值等值比較
      值類型與參考型別比較 必然不相同
      兩個參考型別比較 比較引用的地址
      我們可以看到,兩個參考型別比較,相同和相等並沒有什麼區別。我們看個例子:
      var str1 = new String("str");var str2 = new String("str");console.log(str1 == str2); // falseconsole.log(str1 === str2); // false
      序列檢測序列檢測這個概念咋一聽很拗口,換個說法其實就是比較大小。比較的運算子有四個:>、>=、<、<=,意義不用說大家都明白。可以進行序列檢測的資料類型有三種,boolean、string和number。它們的序列值如下表所示:
      可比較序列的類型 序列值
      boolean 0~1
      string 0~255(*注1)
      number NEGATIVE_INFINITY~POSITIVE_INFINITY(*注2)
      *注1:在一般語言中,字元(char)這種資料類型是按ASCII碼排序的。JavaScript中不存在字元類型,但字串中的每一個字元,都將作為單一字元參與序列檢測。*注2:表示負無窮到正無窮,實際上是有界限的,只不過這個界限達到了10^308層級(可以通過Number.MAX_VALUE查看),我們一般認為達不到。值NaN沒有序列值,任何值(包括NaN本身)與NaN進行序列檢測都將得到false序列檢測的運算規則如下表:
      序列檢測的運算規則
      類型 運算規則
      兩個值類型進行比較 直接比較資料在序列中的大小
      值類型與參考型別比較 將參考型別的資料轉換為值類型資料,再比較資料在序列中的大小
      兩個參考型別比較 無意義,總是返回false

      函數調用這部分內容在上一節的JavaScript函數中有詳細解說,就不細表了。有一點要說的是,運算子“( )”,只能在函數或指向某函數的變數後,否則,將會觸發異常。
      特殊作用的運算子在JavaScript中有一些運算子,不直接產生運算效果,而是用於影響運算效果,這一類運算子的操作對象通常是“運算式”,而非“運算式的值”。另外的一些運算子不直接針對變數的值運算,而是針對變數運算。詳細的運算子和它們的作用如下表:
      目標 運算子 作用 備忘
      運算元 typeof 返回表示資料類型的字串
      運算元 instanceof 返回繼承關係
      運算元 in 返回成員關係
      運算元 delete 刪除成員
      運算式 void 避免運算式返回值 使運算式總是返回值undefined
      運算式 ?: 按條件執行兩個運算式之一 也稱三目條件運算子
      運算式 () 運算式分組和調整運算次序 也稱優先順序運算子
      運算式 , 運算式順序地連續執行 也稱多重求值或逗號運算子

      運算優先順序運算優先順序在複雜運算中有著舉足輕重的作用,例如我們看個運算式:
      void 1+2
      我們知道void的作用是讓運算式總是返回undefined,那麼,void操作的對象究竟是1還是1+2呢?換句話說,void和+哪個的優先順序更高?我們不妨假設,如果void的優先順序更高,那麼,void操作的數將是1,操作結果變成( void 1 ) + 2,也就是undefined+2,結果將是NaN。而如果相反,+的優先順序更高,那麼,結果將是void (1 + 2),也就是void 3也就是undefined。那麼,究竟是哪種呢?事實是NaN,也就是說,void的優先順序更高。我們將詳細列出JavaScript中常見的運算子及它們的優先關係。注意,表格從上到下,優先順序越來越低。
      JavaScript中運算子的優先順序
      優先順序 運算子 描述
      最高 . [ ] ( ) 對象成員存取 數組下標 函數調用
      ++ - ~ ~ delete new typeof void 一元運算子
      * / % 乘法 除法 模數
      + - + 加法 減法 字串串連
      << >> >>> 移位
      < <= > >= instanceof 序列檢測 繼承關係
      == != === !== 等值檢測
      & 按位與
      ^ 按位異或
      | 按位或
      && 邏輯與
      || 邏輯或
      ?: 三元條件
      = op= 賦值 運算賦值
      最低 , 多重求值

      同一優先順序的不同或相同運算子同時出現在一個語句中時,按從左至右執行。當然,類似CSS中的!important,JavaScript中也有一個強制改變優先順序的符號,就是( ),括弧內的運算會優先於括弧外的運算。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.