3 基本概念

本章內(nèi)容

  • 語法
  • 數(shù)據(jù)類型
  • 流控制語句
  • 理解函數(shù)

3.1 語法

3.1.1 區(qū)分大小寫

區(qū)分大小寫

3.1.2 標(biāo)識符

  • 第一個字符必須是一個字母、下劃線(_)或1一個美元符號($);
  • 其他字符可以是字母、下劃線、美元符號或數(shù)字。
    按照慣例,ECMAScript 標(biāo)識符采用駝峰大小寫格式。

3.1.3 注釋

// 單行注釋
/*
    這是一個多行(塊級)注釋
*/

3.1.4 嚴(yán)格模式

"use strict";
function doSomething () {
  "use strict";
  //函數(shù)體
}

3.1.5 語句

ECMAScript中的語句以一個分號結(jié)尾。

var sum = a + b
var diff = a - b;

雖然語句結(jié)尾的分號不是必需的,但我們建議任何時候都不要省略它。

最佳實踐是始終在控制語句中使用代碼塊

if (test) {
  alert(test);
}

3.2 關(guān)鍵字和保留字

3.3 變量

var message;
var message = "hi";
var message = "hi";
message = 100;    //有效,但不推薦
function test () {
  var message = "hi"; // 局部變量
}
test();
alert(message); // 錯誤!

3.4 數(shù)據(jù)類型

ECMAScript 中有5種基本數(shù)據(jù)類型:UndefinedNull、Boolean、NumberString。還有一種復(fù)雜數(shù)據(jù)類型——Object。

3.4.1 typeof 操作符

對于一個值使用typeof操作符可能返回下列某個字符串:

  • "undefined"——如果這個值未定義
  • "boolean"——如果這個值是布爾值
  • "string"——如果這個值是字符串
  • "number"——如果這個值是數(shù)值
  • “object”——如果這個值是對象或null
  • "function"——如果這個值是函數(shù)
var message = "some string";
alert(typeof message);  // "string"
alert(typeof(message));  // "string"
alert(typeof 95);  // "number"

注意,typeof是一個操作符而不是函數(shù),因此例子中的圓括號不是必需的。

3.4.2 Undefined 類型

Undefined類型只有一個值,即特殊的 undefined。

var message;
alert(message == undefined);  //true
var message;

// 下面這個變量未聲明
// var age

alert(message);  // "undefined"
alert(age);  // 產(chǎn)生錯誤
var message

// var age

alert(typeof message);  // "undefined"
alert(typeof age);  // "undefined"

3.4.3 Null 類型

只有一個值null

var car = null;
alert(typeof car);  // "object"

如果定義的變量準(zhǔn)備在將來用于保存對象,那么最好將該變量初始化為null而不是其他值。

if (car != null) {
  // 對 car 對象執(zhí)行某些操作
}

實際上,undefined值是派生自null值的。

alert(null == undefined);  //true

沒有必要把一個變量的值顯式地設(shè)置為undefined。
只要意在保存對象的變量還沒有真正保持隊形,就應(yīng)該明確保存null值。

3.4.4 Boolean 類型

var found = true;
var lost = false;

TrueFalse都不是Boolean值,只是標(biāo)識符。

ECMAScript中所有類型的值都有與這兩個Boolean值等價的值,可以調(diào)用轉(zhuǎn)型函數(shù)Boolean()。

var message = "Hello world!";
var messageAsBoolean = Boolean(message);
數(shù)據(jù)類型 轉(zhuǎn)換為true的值 轉(zhuǎn)換為false的值
Boolean true false
String 任何非空字符串 空字符串
Number 任何非零數(shù)字值 0和NaN
Object 任何對象 null
Undefined n/a (不適用) undefined
var message = "Hello world";
if (message) {
  alert("Value is true");
}

3.4.5 Number 類型

var intNum = 55;

八進制字面值的第一位必須是0。八進制字面量在嚴(yán)格模式下是無效的。

var octalNum1 = 070;  //八進制的56
var octalNum2 = 079;
var octalNum3 = 08;  //無效的八進制數(shù)值——解析為8

十六進制字面值的前兩位必須是 0x。

var hexNum1 = 0xA;  //十六進制的10
var hexNum2 = 0xlf;  //十六進制的31

在進行算術(shù)計算時,所有以八進制和十六進制表示的數(shù)值最終都將被轉(zhuǎn)換成十進制數(shù)值。

1.浮點數(shù)值

var floatNum1 = 1.1;
var floatNum2 = 0.1;
var floatNum3 = .1;  //有效,但不推薦
var floatNum1 = 1.;  //小數(shù)點后面沒有數(shù)字——解析為1
var floatNum2 = 10.0;  //整數(shù)——解析為10
var floatNum = 3.125e7;  //等于31250000

在默認(rèn)情況下,ECMAScript會將那些小數(shù)點后面帶有6個零以上的浮點數(shù)值轉(zhuǎn)換為以e表示法表示的數(shù)值(0.0000003會被轉(zhuǎn)換成3e-7)。
浮點數(shù)值的最高精度是17位小數(shù),但在進行算術(shù)計算時其精確度遠(yuǎn)遠(yuǎn)不如整數(shù)。例如,0.1加0.2結(jié)果不是0.3,而是0.30000000000000004。

2.數(shù)值范圍

計算結(jié)果得到一個超出JavaScript數(shù)值范圍的值,那么這個數(shù)值將被自動轉(zhuǎn)換成特殊的Infinity值。負(fù)數(shù)會被轉(zhuǎn)換成-Infinity,正數(shù)會被轉(zhuǎn)換成Infinity。

var result =   Number.MAX_VALUE + Number.MAX_VALUE;
alert(isFinite(result));  //false

3.NaN

這個數(shù)值用于表示一個本來要返回數(shù)值的操作數(shù)未返回數(shù)值的情況(這樣就不會拋出錯誤了)。在ECMAScript中,任何數(shù)值除以0會返回NaN,不會影響其他代碼的執(zhí)行。
任何涉及NaN的操作都會返回NaN,這個特點在多步計算中有可能導(dǎo)致問題。
NaN與任何值都不想等,包括NaN本身。

alert(NaN == NaN);  //false
alert(isNaN(NaN));  //true
alert(isNaN(10));  //false
alert(isNaN("10"));  //false
alert(isNaN("blue"));  //true(不能轉(zhuǎn)換成數(shù)值)
alert(isNaN(true));  //false(可以被轉(zhuǎn)換成數(shù)值1)

4.數(shù)值轉(zhuǎn)換

有3個函數(shù)可以把非數(shù)值轉(zhuǎn)換為數(shù)值:Number()、parseInt()parseFloat()。
Number()函數(shù)的轉(zhuǎn)換規(guī)則如下。

  • 如果是Boolean值,truefalse將被轉(zhuǎn)換為10
  • 如果是數(shù)字值,只是簡單的傳入和返回。
  • 如果是null值,返回0
  • 如果是undefined,返回NaN。
  • 如果是字符串,遵循下列規(guī)則:
    如果是字符串中只包含數(shù)字,則將其轉(zhuǎn)換為十進制數(shù)值;(忽略前導(dǎo)零)
    如果字符串中包含有效的浮點格式,則將其轉(zhuǎn)換為對應(yīng)的浮點數(shù)值;(忽略前導(dǎo)0)
    如果字符串中包含有效的十六進制格式,則將其轉(zhuǎn)換為相同大小的十進制整數(shù)值;
    如果字符串是空的,則將其轉(zhuǎn)換為0;
    如果字符串中包含除上述格式之外的字符,則將其轉(zhuǎn)換為NaN。
  • 如果是對象,則調(diào)用對象的valueOf()方法,然后依照前面的規(guī)則轉(zhuǎn)換返回的值。如果轉(zhuǎn)換的結(jié)果是NaN,則調(diào)用對象的toString(),然后再次依照前面的規(guī)則轉(zhuǎn)換返回的字符串值。
var num1 = Number("Hello world!");  //NaN
var num2 = Number("");  //0
var num3 = Number("000011");  //11
var num4 = Number(true);  //1

一元操作符的操作與Number()函數(shù)相同

parseInt()函數(shù)在轉(zhuǎn)換字符串時,更多的是看其是否符合數(shù)值模式。它會忽略字符串前面的空格,直至找到第一個非空格字符。如果第一個字符不是數(shù)字字符或者負(fù)號,會返回NaN;如果第一個字符是數(shù)字字符,會繼續(xù)解析,知道解析完所有后需字符或遇到一個非數(shù)字字符。

var num1 = parseInt("1234blue1213");  //1234
var num2 = parseInt("");  //NaN
var num3 = parseInt("0xA");  //10 (十六進制數(shù))
var num4 = parseInt(22.5);  //22
var num = parseInt("0xAF", 16);  //175

var num = parseInt("AF", 16);  //175
var num2 = parseInt("AF");  //NaN

parseFloat也是從第一個字符開始解析每個字符。一直解析到字符串末尾,或者解析到遇見一個無效的浮點數(shù)字字符為止。
始終都會忽略前導(dǎo)的零。只解析十進制值。

var num1 = parseFloat("1234blue");  //1234
var num2 = parseFloat("0xA");  //0
var num3 = parseFloat("22.5");  //22.5
var num4 = parseFloat("22.34.5");  //22.34
var num5 = parseFloat("0908.5");  //908.5
var num6 = parseFloat("3.12e7");  //31250000

3.4.6 String 類型

var firstName = "Nicholas";
var lastName = 'Zakas';

1.字符字面量

String數(shù)據(jù)類型包含一些特殊的字符字面量,也叫轉(zhuǎn)義序列。

2.字符串的特點

要改變某個變量保存的字符串,首先要銷毀原來的字符串,然后再用另一個包含新值的字符串填充該變量。

var lang = "Java";
lang =lang + "Script";

3.轉(zhuǎn)換為字符串

把一個值轉(zhuǎn)換為一個字符串有兩種方式。第一種是使用幾乎每個值都有的toString()方法。這個方法唯一要做的就是返回相應(yīng)值得字符串表現(xiàn)。

var age =11;
var ageAsString = age.toString();  //字符串“11”
var found = true;
var foundAsString = found.toString();  //字符串”true“

數(shù)值、布爾值、對象和字符串值都有toString()方法。但nullundefined值沒有這個方法。
toString()可以輸出以二進制、八進制、十六進制,乃至其他任意有效進制格式標(biāo)識的字符串值。

var num = 10;
alert (num.toString());  //"10"
alert (num.toString(2));  //"1010"
alert (num.toString(8));  //"12"
alert (num.toString(10));  //"10"
alert (num.toString(10));  //"a"

在不知道要轉(zhuǎn)換的值是不是nullundefined的情況下,還可以使用轉(zhuǎn)型函數(shù)String(),這個函數(shù)能將任何類型的值轉(zhuǎn)換為字符串。

  • 如果值有toString()方法,則調(diào)用該方法(沒有參數(shù))并返回相應(yīng)的結(jié)果;
  • 如果值是null,則返回”null“;
  • 如果值是undefined,則返回”undefined“。

3.4.7 Object 類型

ECMAScript中的對象其實就是一組數(shù)據(jù)和功能的集合。

var o = new Object();
var o = new Object;//有效,但不推薦省略圓括號

Object的每個實例都具有下列屬性和方法。

  • Constructor:保存著用于創(chuàng)建當(dāng)前對象的函數(shù)。對于前面的例子而言,構(gòu)造函數(shù)就是Object()。
  • hasOwnProperty(propertyName):用于檢查給定的屬性在當(dāng)前對象實例中是否存在。其中,作為參數(shù)的屬性名必須以字符串形式指定。
  • isPrototypeOf(object):用于檢查傳入的對象是否是另一個對象的原型。
  • propertyIsEnumerable(propertyName):用于檢查給定的屬性是否能夠使用for-in語句來枚舉。作為參數(shù)的屬性名必須以字符串形式指定。
  • toLocaleString():返回對象的字符串表示,該字符串與執(zhí)行環(huán)境的地區(qū)對應(yīng)。
  • toString():返回對象的字符串表示。
  • valueOf():返回對象的字符串、數(shù)值或布爾值表示。通常與toString()方法的返回值相同。

由于在ECMAScript中Object是所有對象的基礎(chǔ),因此所有對象都具有這些基本的屬性和方法。

3.5 操作符

ECMAScript 操作符的與眾不同之處在于,它們能夠適用于很多值,例如字符串、數(shù)字值、布爾值,甚至對象。在應(yīng)用于對象時,相應(yīng)的操作符通常都會調(diào)用對象的valueOf()和(或)toString()方法,以便取的可以操作的值。

3.5.1 一元操作符

1.遞增和遞減操作符

var age = 29;
++age;
var age = 29;
--age;

執(zhí)行前置遞增和遞減操作時,變量的值都是在語句被求值以前改變的。

var age = 29;
var anotherAge = --age + 2;
alert(age);  //輸出28
alert(anotherAge);  //輸出30

后置型遞增和遞減操作是在包含它們的語句被求值之后才執(zhí)行的。

var num1 = 2;
var num2 = 20;
var num3 = num1-- + num2;  //等于22
var num4 = num1 + num2;  //等于21

在應(yīng)用于不同的值時,遞增和遞減操作符遵循下列規(guī)則。

  • 在應(yīng)用與一個包含有效數(shù)字字符的字符串時,先將其轉(zhuǎn)換為數(shù)字值,在執(zhí)行加減1的操作。字符串變量變成數(shù)值變量。
  • 在應(yīng)用于一個不包含有效數(shù)字字符的字符串時,將變量的值設(shè)置為NaN。字符串變量變成數(shù)值變量。
  • 在應(yīng)用于布爾值false時,先將其轉(zhuǎn)換為0再執(zhí)行加減1的操作。布爾值變量變成數(shù)值變量。
  • 在應(yīng)用于布爾值true時,先將其轉(zhuǎn)換為1在執(zhí)行加減1的操作。布爾值變量變成數(shù)值變量。
  • 在應(yīng)用于浮點數(shù)值時,執(zhí)行加減1的操作。
  • 在應(yīng)用于對象時,先調(diào)用對象的valueOf()方法以取得一個可供操作的值。然后對該值應(yīng)用前述規(guī)則。如果結(jié)果是NaN,則在調(diào)用toString()方法后再應(yīng)用前述規(guī)則。對象變量變成數(shù)值變量。
var s1 = "2";
var s2 = "z";
var b = false;
var f = 1.1;
var o = {
  valueOf: function() {
    return -1;
  }
};

s1++;  //3
s2++;  //NaN
b++;  //1
f--;  //0.10000000000000009
o--;  //-2

2.一元加和減操作符

一元操作符以一個加號表示,放在數(shù)值前面,對數(shù)值不會產(chǎn)生任何影響。

var num = 25;
num = +num;  //25

不過,在對非數(shù)值應(yīng)用一元加操作符時,該操作符會像Number()轉(zhuǎn)型函數(shù)一樣對這個值執(zhí)行轉(zhuǎn)換。

var s1 = "01";
var s2 = "1.1";
var s3 = "z";
var b = false;
var f = 1.1;
var o = {
  valueOf: function() {
    return -1;
  }
};

s1 = +s1;  //1
s2 = +s2;  //1.1
s3 = +s3;  //NaN
b = +b;  //0
f = +f;  //1.1
o = +o;  //-1

一元減操作符主要用于表示負(fù)數(shù)。

var num = 25;
num = -num;  //-25

應(yīng)用于飛數(shù)值時,一元減操作符遵循與一元加操作符相同的規(guī)則,最后再將得到的數(shù)值轉(zhuǎn)換為負(fù)數(shù)。

3.5.2 位操作符

在 ECMAScript中,當(dāng)對數(shù)值應(yīng)用位操作符時,后臺會發(fā)生如下轉(zhuǎn)換過程:64位的數(shù)值被轉(zhuǎn)換成32位數(shù)值,然后執(zhí)行位操作,最后再將32位的結(jié)果轉(zhuǎn)換回64位數(shù)值。這個轉(zhuǎn)換過程導(dǎo)致了一個嚴(yán)重的副效應(yīng),即在對特殊的NaNInfinity值應(yīng)用位操作時,這兩個值都會被當(dāng)成0來處理。
如果對非數(shù)值應(yīng)用位操作符,會先使用Number()函數(shù)將該值轉(zhuǎn)換為一個數(shù)值,然后再應(yīng)用位操作。得到的結(jié)果將是一個數(shù)值。

1.按位非 (NOT)

var num1 = 25;  //二進制
var num2 = ~num1;  //二進制 
alert(num2);  //-26

這也驗證了按位非操作的本質(zhì):操作數(shù)的負(fù)值減1。

2.按位與(AND)

從本質(zhì)上講,按位與操作就是將兩個數(shù)值的每一位對齊,然后根據(jù)下表中的規(guī)則,對相同位置上的兩個數(shù)執(zhí)行AND操作:

第一個數(shù)值的位 第二個數(shù)值的位 結(jié)果
1 1 1
1 0 0
0 1 0
0 0 0
var result = 25 & 3;
alert(result);  //  1

3.按位或 (OR)

按位或操作遵循下面這個真值表。

第一個數(shù)值的位 第二個數(shù)值的位 結(jié)果
1 1 1
1 0 1
0 1 1
0 0 0
var result = 25 | 3;
alert(result);  //27

4.按位異或 (XOR)

按位異或操作符由一個插入符號(^)表示,也有倆操作數(shù)。以下是按位異或的真值表。

第一個數(shù)值的位 第二個數(shù)值的位 結(jié)果
1 1 0
1 0 1
0 1 1
0 0 0
var result = 25 ^ 3;
alert (result);  //26

5.左移

左移操作符由兩個小于號(<<)表示,這個操作符會將數(shù)值的所有位向左移動指定的位數(shù)。

var oldValue = 2;  //等于二進制的10
var newValue = oldValue << 5;  //等于二進制的1000000,十進制的64

左移操作會以0來填充這些空位,以便得到的結(jié)果是一個完整的32位二進制數(shù)。
注意,左移不會影響操作數(shù)的符號位。換句話說,如果將-2向左移動5位,結(jié)果將是-64,而非64。

6.有符號的右移

有符號的右移操作符由兩個大于號(>>)表示,這個操作符會將數(shù)值向右移動,但保留符號位。

var oldValue = 64;  //等于二進制的1000000
var newValue = oldValue >> 5;  //等于二進制的10,即十進制的2

7.無符號右移

無符號右移操作符由3個大于號(>>>)表示。這個操作符會將數(shù)值的所有32位都向右移動。對正數(shù)來說,無符號右移結(jié)果與有符號右移相同。

var oldValue = 64;
var newValue = oldValue >>> 5;  //等于二進制的10,即十進制的2

對負(fù)數(shù)來說,無符號右移是以0來填充空位,不會保留符號位的值。

var oldValue = -64;  
var newValue = oldValue >>> 5;  //等于十進制的134217726

3.5.3 布爾操作符

布爾操作符一共有3個:非(NOT)、與(AND)和或(OR)。

1.邏輯非

邏輯非操作符由一個嘆號(?。┍硎?,可以應(yīng)用于ECMAScript中的任何值。邏輯非操作符首先會將它的操作數(shù)轉(zhuǎn)換為一個布爾值,然后再對其求反。邏輯非操作符遵循下列規(guī)則:

  • 如果操作數(shù)是一個對象,返回fasle;
  • 如果操作數(shù)是一個空字符串,返回true;
  • 如果操作數(shù)是一個非空字符串,返回false
  • 如果操作數(shù)是數(shù)值0,返回true
  • 如果操作數(shù)是任意非0數(shù)值(包括Infinity),返回false;
  • 如果操作數(shù)是null,返回true;
  • 如果操作數(shù)是NaN,返回true;
  • 如果操作數(shù)是undefined,返回true。
alert(!false);  //true
alert(!"blue");  //false
alert(!0);  //true
alert(!NaN);  //true
alert(!"");   //true
alert(!12345);  //false

邏輯非操作符也可以用于將一個值轉(zhuǎn)換為與其對應(yīng)的布爾值。而同時使用兩個邏輯非操作符,實際上就會模擬Boolean()轉(zhuǎn)型函數(shù)的行為。

alert(!!"blue");  //true
alert(!!0);  //false
alert(!!NaN);  //false
alert(!!"");  //false
alert(!!12345);  //true

2.邏輯與

邏輯與操作符由兩個和號(&&)表示,有兩個操作數(shù),如下面的例子所示:

var result = true && false;

邏輯與的真值表如下:

第一個操作數(shù) 第一個操作數(shù) 結(jié)果
true true true
true false false
false true false
false false false

邏輯與操作可以應(yīng)用于任何類型的操作數(shù),而不僅僅是布爾值。在有一個操作數(shù)不是布爾值的情況下,邏輯與操作就不一定返回布爾值;此時,他遵循下列規(guī)則:

  • 如果第一個操作數(shù)是對象,則返回第二個操作數(shù);
  • 如果第二個操作數(shù)是對象,則只有在第一個操作數(shù)的求值結(jié)果為true的情況下才會返回該對象;
  • 如果兩個操作數(shù)都是對象, 則返回第二個操作數(shù);
  • 如果有一個操作數(shù)是NaN,則返回NaN;
  • 如果有一個操作數(shù)是undefined,則返回undefined。

邏輯與操作術(shù)語短路操作,即如果第一個操作數(shù)能夠決定結(jié)果,那么就不會再對第二個操作數(shù)求值。如果第一個操作數(shù)是false, 則無論第二個操作數(shù)是什么值,結(jié)果都不會是true了。

var found = true;
var result = (found && someUndefinedVariable);  //這里會發(fā)生錯誤
alert(result);  //這一行不會執(zhí)行
var found = false;
var result = (found && someUndefinedVariable);  //不會發(fā)生錯誤
alert(result);  //會執(zhí)行("false")

3.邏輯或

邏輯或操作符由兩個豎線符號(||)表示,由兩個操作數(shù)。

var result = true || false;

邏輯或的真值表如下:

第一個操作數(shù) 第二個操作數(shù) 結(jié)果
true true true
true false true
false true true
false false false

如果有一個操作數(shù)不是布爾值,邏輯或也不一定返回布爾值;此時,它遵循下列規(guī)則:

  • 如果第一個操作數(shù)是對象,則返回第一個操作數(shù);
  • 如果第一個操作數(shù)的求值結(jié)果為false,則返回第二個操作數(shù);
  • 如果兩個操作數(shù)都是對象,則返回第一個操作數(shù);
  • 如果兩個操作數(shù)都是null,則返回null;
  • 如果兩個操作數(shù)都是NaN,則返回NaN
  • 如果兩個操作數(shù)都是undefined,則返回undefined

邏輯或操作符也是短路操作符。也就是說,如果第一個操作數(shù)的求值結(jié)果為true,就不會對第二個操作數(shù)求值了。

var found = true;
var result = (found || someUndefinedVariable);  //不會發(fā)生錯誤
alert(result);  //會執(zhí)行 ("true")
var found = false;
var result = (found || someUndefinedVariable);  //這里會發(fā)生錯誤
alert(result);  //這一行不會執(zhí)行

我們可以利用邏輯或的這一行為來避免為變量賦nullundefined值。例如:

var myObject = preferredObject || backupObject;

3.5.4 乘性操作符

ECMAScript定義了3個乘性操作符:乘法、除法和求模。如果參與乘法計算的某個操作數(shù)不是數(shù)值,后臺會先使用Number()轉(zhuǎn)型函數(shù)將其轉(zhuǎn)換為數(shù)值。也就是說,空字符串將被當(dāng)作0,布爾值true將被當(dāng)作1。

1.乘法

乘法操作符由一個星號(*)表示,用于計算兩個數(shù)值的乘積。

var result = 34 * 56;

在處理特殊值的情況下,乘法操作符遵循下列特殊的規(guī)則:

  • 如果操作數(shù)都是數(shù)值,執(zhí)行常規(guī)的乘法計算。如果乘積超過了ECMAScript數(shù)值的表示范圍,則返回Infinity-Infinity;
  • 如果有一個操作數(shù)是NaN,則結(jié)果是NaN;
  • 如果是Infinity與0相乘,則結(jié)果是NaN;
  • 如果是Infinity與非0數(shù)值相乘,則結(jié)果是Infinity-Infinity,取決于有符號操作數(shù)的符號;
  • 如果有一個操作數(shù)不是數(shù)值,則在后臺調(diào)用Number()將其轉(zhuǎn)換為數(shù)值,然后再應(yīng)用上面的規(guī)則。

2.除法

除法操作符由一個斜線符號(/)表示,執(zhí)行第二個操作數(shù)除第一個操作數(shù)的計算,如下面的例子所示:

var result = 66 / 11;

規(guī)則如下:

  • 如果操作數(shù)都是數(shù)值,執(zhí)行常規(guī)的除法計算。如果商超過了ECMAScript數(shù)值的表示范圍,則返回Infinity-Infinity
  • 如果有一個操作數(shù)是NaN,則結(jié)果是NaN;
  • 如果是InfinityInfinity除,則結(jié)果是NaN;
  • 如果是零被零出,則結(jié)果是NaN;
  • 如果是非零的有限數(shù)被零除,則結(jié)果是Infinity-Infinity;
  • 如果是Infinity被任何非零數(shù)值除,則結(jié)果是Infinity-Infinity;
  • 如果有一個操作數(shù)不是數(shù)值,則在后臺調(diào)用Number()將其轉(zhuǎn)換為數(shù)值,然后在應(yīng)用上面的規(guī)則。

3.求模

求模(余數(shù))操作符由一個百分號(%)表示,用法如下:

var result = 26 % 5;  //等于1

求模操作符會遵循下列特殊規(guī)則來處理特殊的值:

  • 如果操作數(shù)都是數(shù)值,執(zhí)行常規(guī)的除法計算,返回除得的余數(shù);
  • 如果被除數(shù)是無窮大值而除數(shù)是有限大的數(shù)值,則結(jié)果是NaN
  • 如果被除數(shù)是有限大的數(shù)值而除數(shù)是零,則結(jié)果是NaN;
  • 如果是InfinityInfinity除,則結(jié)果是被除數(shù);
  • 如果被除數(shù)是有限大的數(shù)值而除數(shù)是無窮大的數(shù)值,則結(jié)果是被除數(shù);
  • 如果被除數(shù)是零,則結(jié)果是零;
  • 如果有一個操作數(shù)不是數(shù)值,則在后臺調(diào)用Number()將其轉(zhuǎn)化為數(shù)值,然后在應(yīng)用上面的規(guī)則。

3.5.5 加性操作符

在ECMAScript中,這兩個操作符有一系列的特殊行為。

1.加法

var result = 1 + 2;

如果兩個操作符都是數(shù)值,執(zhí)行常規(guī)的加法計算,然后根據(jù)下列規(guī)則返回結(jié)果:

  • 如果有一個操作數(shù)是NaN,則結(jié)果是NaN;
  • 如果是InfinityInfinity,則結(jié)果是Infinity
  • 如果是-Infinity-Infinity,則結(jié)果是-Infinity
  • 如果是+0加+0,則結(jié)果是+0;
  • 如果是-0加-0,則結(jié)果是-0;
  • 如果是+0加-0,則結(jié)果是+0;

不過,如果有一個操作數(shù)是字符串,那么就要應(yīng)用如下規(guī)則:

  • 如果兩個操作數(shù)都是字符串,則將第二個操作數(shù)與第一個操作數(shù)拼接起來;
  • 如果只有一個操作數(shù)是字符串,則將另一個操作數(shù)轉(zhuǎn)換為字符串,然后再將兩個字符串拼接起來。

如果有一個操作數(shù)是對象、數(shù)值或布爾值,則調(diào)用它們的toString()方法取得相應(yīng)的字符串值,然后再應(yīng)用前面關(guān)于字符串的規(guī)則。對于undefinednull,則分別調(diào)用String()函數(shù)并取得字符串"undefined"和"null"。

var result1 = 5 + 5;  //連個數(shù)值相加
alert(result1);  //10
var result2 = 5 + "5";  //一個數(shù)值和一個字符串相加
alert(result2);  //"55"
var num1 =5;
var num2 =10;
var message = "The sum of 5 and 10 is" + num1 + num2;
alert(message);  //"The sum of 5 and 10 is 510"
var num1 = 5;
var num2 = 10;
var message = "The sum of 5 and 10 is" + (num1 + num2);
alert(message);  //"The sum of 5 and 10 is 15"

2.減法

var result = 2 - 1;

同樣需要遵循一些特殊規(guī)則,如下所示:

  • 如果兩個操作符都是數(shù)值,則執(zhí)行常規(guī)的算術(shù)減法操作并返回結(jié)果;
  • 如果有一個操作數(shù)是NaN,則結(jié)果是NaN;
  • 如果是InfinityInfinity,則結(jié)果是NaN
  • 如果是-Infinity-Infinity,則結(jié)果是NaN;
  • 如果是Infinity-Infinity,則結(jié)果是Infinity
  • 如果是-InfinityInfinity,則結(jié)果是-Infinity;
  • 如果是+0減+0,則結(jié)果是+0;
  • 如果是+0減-0,則結(jié)果是-0;
  • 如果是-0減-0,則結(jié)果是+0;
  • 如果有一個操作數(shù)是字符串、布爾值、nullundefined,則先在后臺調(diào)用Number()函數(shù)將其轉(zhuǎn)換為數(shù)值,然后再根據(jù)前面的規(guī)則執(zhí)行減法計算。如果轉(zhuǎn)換的結(jié)果是NaN,則減法的結(jié)果就是NaN;
  • 如果有一個操作符是對象,則調(diào)用對象的valueOf()方法以取得表示該對象的數(shù)值。如果得到的值是NaN,則減法的結(jié)果就是NaN。如果對象沒有valueOf()方法,則調(diào)用其toString()方法并將得到的字符串轉(zhuǎn)換為數(shù)值。
var result1 = 5 - true;  //4
var result2 = NaN - 1;  //NaN
var result3 = 5 - 3;  //2
var result4 = 5 - "";  //5
var result5 = 5 - "2";  //3
var result6 = 5 - null;  //5

3.5.6 關(guān)系操作符

小于(<)、大于(>)、小于等于(<=)和大于等于(>=)這幾個關(guān)系操作符用于對兩個值進行比較,這幾個操作符都返回一個布爾值。

var result1 = 5 > 3;  //true
var result2 = 5 < 3;  //false

當(dāng)關(guān)系操作符的操作數(shù)使用了非數(shù)值時,也要進行數(shù)據(jù)轉(zhuǎn)換或完成某些奇怪的操作。

  • 如果連個操作數(shù)都是數(shù)值,則執(zhí)行數(shù)值比較。
  • 如果兩個操作數(shù)都是字符串,則比較兩個字符串對應(yīng)的字符編碼值。
  • 如果一個操作數(shù)是數(shù)值,則將一個操作數(shù)轉(zhuǎn)換為一個數(shù)值,然偶執(zhí)行數(shù)值比較。
  • 如果一個操作數(shù)是對象,則調(diào)用這個對象的valueOf()方法,用得到的結(jié)果按照前面的規(guī)則執(zhí)行比較。如果對象沒有valueOf()方法,則調(diào)用toString方法,并用得到的結(jié)果根據(jù)前面的規(guī)則執(zhí)行比較。
  • 如果一個操作數(shù)是布爾值,則先將其轉(zhuǎn)換為數(shù)值,然后在執(zhí)行比較。

在使用關(guān)系操作符比較兩個字符串時,會執(zhí)行一種奇怪的操作。很多人都會認(rèn)為,在比較字符串值時,小于的意思是“在字母表中的位置靠前”,而大于則意味著“在字母表中的位置靠后”,但實際上完全不是那么回事。在比較字符串時,實際比較的是兩個字符串中對應(yīng)位置的每個字符的字符編碼值。經(jīng)過這么一番比較后,再返回一個布爾值。由于大寫字母的字符編碼全部小于小寫字母的字符編碼,因此我們就會看到如下所示的奇怪現(xiàn)象:

var result = "Brick" < "alpahabet";  //true

要真正按照字母表順序比較字符串,就必須把兩個操作數(shù)轉(zhuǎn)換為相同的大小寫形式,然后在執(zhí)行比較,如下所示:

var result = "Brick.toLowerCase()" < "alphabet".toLowerCase();  //false
var result = "23" < "3";  //true
var result = "23" < 3;  //false
var result = "a" < 3;  //false,因為“a”被轉(zhuǎn)換成了NaN
var result1 = NaN < 3;  //false
var result2 = NaN >= 3;  //false

按照常理,如果一個值不小于另一個值,則一定是大于或等于那個值。然而,在與NaN進行比較時,這兩個比較操作的結(jié)果都返回了fasle

3.5.7 相等操作符

在比較字符串、數(shù)值和布爾值的的相等性時,問題還比較簡單。但在涉及到對象的比較時,問題就變得復(fù)雜了。最后,ECMAScript的解決方案就是提供兩組操作符:相等和不相等——先轉(zhuǎn)換在比較,全等和不全等——僅比較而不轉(zhuǎn)換。

1.相等和不相等

會先轉(zhuǎn)換操作數(shù),然后再比較它們的相等性。在轉(zhuǎn)換不同的數(shù)據(jù)類型時,相等和不相等操作符遵循下列基本規(guī)則:

  • 如果有一個操作數(shù)是布爾值,則在比較相等性之前先將其轉(zhuǎn)換為數(shù)值——false轉(zhuǎn)換為0,而true轉(zhuǎn)換為1;
  • 如果一個操作數(shù)是字符串,另一個操作數(shù)是數(shù)值,在比較相等性之前先將字符串轉(zhuǎn)換為數(shù)值;
  • 如果一個操作數(shù)是對象,另一個操作數(shù)不是,則調(diào)用對象的valueOf()方法,用得到的基本類型值按照前面的規(guī)則進行比較;

這兩個操作符在進行比較時則要遵循下列規(guī)則。

  • nullundefined是相等的。
  • 要比較相等性之前,不能將nullundefined轉(zhuǎn)換成其他任何值。
  • 如果有一個操作數(shù)是NaN,則相等操作符返回false,而不相等操作符返回true。重要提示:即使兩個操作數(shù)都是NaN,相等操作符也返回false;按照規(guī)則,NaN不等于NaN。
  • 如果兩個操作數(shù)都是對象,則比較它們是不是同一個對象。如果兩個操作數(shù)都指向同一個對象,則相等操作符返回true;否則,返回false。

下表列出了一些特殊情況及比較結(jié)果:

表達式
null == undefined true
"NaN" == NaN false
5 == NaN false
NaN == NaN false
NaN != NaN true
false == 0 true
true == 1 true
true == 2 false
undefined == 0 false
null == 0 false
"5" == 5 true

2.全等和不全等

只在兩個操作數(shù)未經(jīng)轉(zhuǎn)換就相等的情況下返回true。

var result1 = ("55" == 55);  //true,因為轉(zhuǎn)換后相等
var result2 = ("55" === 55);  //false,因為不同的數(shù)據(jù)類型不相等
var result1 = ("55" != 55);  //false,因為轉(zhuǎn)換后相等
var result2 = ("55" !== 55);  //true,因為不同的數(shù)據(jù)類型不相等

3.5.8 條件操作符

variable = boolean_expression ? true_value : false_value;
var max = (num1 > num2) ? num1: num2;

3.5.9 賦值操作符

var num = 10;
var num = 10;
num += 10;

每個主要算術(shù)操作符(以及個別的其他操作符)都有對應(yīng)的復(fù)合賦值操作符。這些操作符如下所示:

  • 乘/賦值 (*=);
  • 除/賦值 (/=);
  • 模/賦值 (%=);
  • 加/賦值 (+=);
  • 減/賦值 (-=);
  • 左移/賦值 (<<=);
  • 有符號右移/賦值 (>>=);
  • 無符號右移/賦值 (>>>=)。

3.5.10 逗號操作符

使用逗號操作符可以在一條語句中執(zhí)行多個操作。

var num1 =1, num2 = 2, num3 = 3;

逗號操作符還可以用于賦值。在用于賦值時,逗號操作符總會返回表達式中的最后一項。

var num = (5, 1, 4, 8, 0);  //num的值為0

由于0是表達式中的最后一項,因此num的值就是0。

3.6 語句

從本質(zhì)上看,語句定義了ECMAScript中的主要語法,語句通常使用一或多個關(guān)鍵字來完成給定任務(wù)。

3.6.1 if 語句

if (condition) statement1 else statement2
if (i > 25)
  alert("Greater than 25.");  //單行語句
esle {
  alert("Less than or equal to 25.");  //代碼塊中的語句
}

不過,業(yè)界普遍推崇的最佳實踐是始終使用代碼塊,即使要執(zhí)行的只有一行代碼。
另外,也可以把整個if語句寫在一行代碼中:

if (condition1) statement1 else if (condition2) statement2 else statement3

但我們推薦的做法則是像下面這樣:

if (i > 25) {
  alert("Greater than 25.");
} else if (i < 0) {
  alert("Less than 0.");
} else {
  alert("Between 0 and 25, inclusive.");
}

3.6.2 do-while 語句

do-while語句是一種后測試循環(huán)語句,即只有在循環(huán)體中的代碼執(zhí)行之后,才會測試出口條件。

do {
  statement
} while (expression);
var i = 0;
do {
  i += 2;
} while (i < 10);
alert(i);

3.6.3 while 語句

while語句屬于前測試循環(huán)語句,也就是說,在循環(huán)體內(nèi)的代碼被執(zhí)行之前,就會對出口條件求值。

while(expression) statement
var i = 0;
while (i < 10) {
  i +=2;
}

3.6.4 for語句

for語句也是一種前測試循環(huán)語句,但它具有在執(zhí)行循環(huán)之前初始化變量和定義循環(huán)后要執(zhí)行的代碼的能力。

for (initialization; expression; post-loop-expression) statement
var count = 10;
for (var i = 0; i < count; i++) {
  alert(i);
}

這個for循環(huán)語句與下面的while語句的功能相同:

var count = 10;
var i = 0;
while (i < count) {
  alert(i);
  i++;
}

變量初始化可以在外部執(zhí)行,由于ECMAScript中不存在塊級作用域,因此在循環(huán)內(nèi)部定義的變量也可以在外部訪問到。
此外,for語句中的初始化表達式、控制表達式和循環(huán)后表達式都是可選的。將這兩個表達式全部省略,就會創(chuàng)建一個無限循環(huán)。

for (; ;) {  //無限循環(huán)
  doSomething();
}

而只給出控制表達式實際上就把for循環(huán)轉(zhuǎn)換成了while循環(huán)。

var count = 10;
var i = 0;
for (; i < count; ) {
  alert(i);
  i++;
}

3.6.5 for-in 語句

for-in語句是一種精準(zhǔn)的迭代語句,可以用來枚舉對象的屬性。

for (property in expression) statement
for (var propName in window) {
  document.write(propName);
}

ECMAScript對象的屬性沒有順序。因此,通過for-in循環(huán)輸出的屬性名的順序是不可預(yù)測的。
但是,如果表示要迭代的對象的變量值為nullundefined,for-in語句會拋出錯誤。ECMAScript5更正了這一行為;對這種情況不再拋出錯誤,而只是不執(zhí)行循環(huán)體。建議在使用for-in循環(huán)之前,先檢測確認(rèn)該對象的值不是nullundefined。

3.6.6 label語句

使用label語句可以在代碼中添加標(biāo)簽,以便將來使用。

label: statement
start: for(var i=0; i < count; i++) {
  alert(i);
}

這個例子中定義的start標(biāo)簽可以在將來由breakcontinue語句引用。加標(biāo)簽的語句一般都要與for語句等循環(huán)語句配合使用。

3.6.7 break和continue語句

breakcontinue語句用于在循環(huán)中精確控制代碼的執(zhí)行。其中,break語句會立即退出循環(huán),強制繼續(xù)執(zhí)行循環(huán)后面的語句。而continue語句雖然也是立即退出循環(huán),但退出循環(huán)后會從循環(huán)的頂部繼續(xù)執(zhí)行。

var num = 0;
for (var i = 1; i < 10; i++) {
  if(i % 5 == 0) {
    break;
  }
  num++;
}
alert(num);  //4
var num = 0;
for (var i = 1; i < 10; i++) {
  if(i % 5 == 0) {
    continue;
  }
  num++;
}
alert(num);  //8

breakcontinue語句都可以與label語句聯(lián)合使用,從而返回代碼中特定的位置。

var num = 0;
outermost:
for (var i = 0; i < 10; i++) {
  for(var j = 0; j < 10; j++) {
    if(i == 5 && j == 5) {
      break outermost;
    }
    num++;
  }
}
alert(num);  //55

添加這個標(biāo)簽的結(jié)果將導(dǎo)致break語句不僅會退出內(nèi)部的for語句,而且也會退出外部的for語句。

3.6.8 with語句

with語句的作用是將代碼的作用域設(shè)置到一個特定的對象中。

with (expression) statement;

定義with語句的目的主要是為了簡化多次編寫同一個對象的工作。

var qs = location.search.substring(1);
var hostName = location.hostname;
var url = location.href; 
with(location) {
  var qs = search.substring(1);
  var hostName = host.name;
  var url = href;
}

嚴(yán)格模式下不允許使用with語句,否則將視為語法錯誤。
不建議使用with語句。

3.6.9 switch語句

ECMAScript中switch語句的語法與其他基于C的語言非常接近。

switch (expression) {
  case value: statement
    break;
  case value: statement
    break;
  case value: statement
    break;
  case value: statement
    break;
    default: statement
}

假如確實需要混合幾種情形,不要忘了在代碼中添加注釋,說明你是有意省略了break關(guān)鍵字。

switch(i) {
  case 25:
    /*合并兩種情形*/
  case 35:
    alert("25 or 35");
    break;
  case 45:
    alert("45");
    break;
  default:
    alert("other");
}

可以在switch語句中使用任何數(shù)據(jù)類型,無論是字符串,還是對象都沒有問題。。每個case的值不一定是常量,可以是變量,甚至是表達式。

switch語句在比較值時使用的是全等操作符,因此不會發(fā)生類型轉(zhuǎn)換。

3.7 函數(shù)

ECMAScript中的函數(shù)使用function關(guān)鍵字來聲明,后跟一組參數(shù)以及函數(shù)體。

function functionName(arg0, arg1, ..., argN) {
  statements
}
function sayHi(name, message) {
  alert("hello " + name + "," + message);
}

實際上,任何函數(shù)在任何時候都可以通過return語句后跟要返回的值來實現(xiàn)返回值。

function sum(num1, num2) {
  return num1 + num2;
}

return語句也可以不帶有任何返回值。在這種情況下,函數(shù)在停止執(zhí)行后將返回undefined值。這種用法一般用在需要提前停止函數(shù)執(zhí)行而又不需要返回值的情況下。

推薦的做法是要么讓函數(shù)始終都返回一個值,要么永遠(yuǎn)都不要返回值。

嚴(yán)格模式對函數(shù)有一些限制:

  • 不能把函數(shù)命名為evalarguments;
  • 不能把參數(shù)命名為evalarguments;
  • 不能出現(xiàn)兩個命名參數(shù)同名的情況。

如果發(fā)生以上情況,就會導(dǎo)致語法錯誤,代碼無法執(zhí)行。

3.7.1 理解函數(shù)

在函數(shù)體內(nèi)可以通過arguments對象來訪問這個參數(shù)數(shù)組,從而獲取傳遞給函數(shù)的每一個參數(shù)。
arguments對象只是與數(shù)組類似,因為可以使用方括號語法訪問它的每一個元素,使用length屬性來確定傳遞進來多少個參數(shù)。

function sayHi() {
  alert("hello " + arguments[0] + "," + arguments[1]);
}

這個重寫后的函數(shù)中不包含命名的參數(shù)。這個事實說明:命名的參數(shù)只提供便利,但不是必需的。

通過訪問arguments對象的length屬性可以獲知有多少個參數(shù)傳遞給了函數(shù)。

function howManyArgs() {
  alert(arguments.length);
}

howManyArgs("string", 45);  //2
howManyArgs();  //0
howManyArgs(12);  //1

開發(fā)人員可以利用這一點讓函數(shù)能夠接收任意個參數(shù)并分別實現(xiàn)適當(dāng)?shù)墓δ堋?/p>

function doAdd() {
  if(arguments.length == 1) {
    alert(arguments[0] + 10);
  } else if (arguments.length == 2) {
    alert(arguments[0] + arguments[1]);
  }
}

doAdd(10);  //20
doAdd(30, 20);  //50

另一個與參數(shù)相關(guān)的重要方面,就是arguments對象可以與命名參數(shù)一起使用。

function doAdd(num1, num2) {
  if(arguments.length ==1) {
    alert(num1 + 10);
  } else if (arguments.length == 2) {
    alert(arguments[0] + num2);
  }
}

關(guān)于arguments的行為,還有一點比較有意思。那就是它的值永遠(yuǎn)與對應(yīng)命名參數(shù)的值保持同步。

function doAdd(num1, num2) {
  arguments[1] = 10;
  alert(arguments[0] + num2);
}

每次執(zhí)行這個函數(shù)都會重寫第二個參數(shù),將第二個參數(shù)的值修改為10.因為arguments對象中的值會自動反映到對應(yīng)的命名參數(shù)。它們的內(nèi)存空間是獨立的,但它們的值會同步。但這種影響是單向的:修改命名參數(shù)不會改變arguments中對應(yīng)的值。如果只傳入了一個參數(shù),那么為arguments[1]設(shè)置的值不會反應(yīng)到命名參數(shù)中。這是因為arguments對象的長度是由傳入的參數(shù)個數(shù)決定的,不是由定義函數(shù)時的命名參數(shù)的個數(shù)決定的。
關(guān)于參數(shù)還要記住最后一點:沒有傳遞值的命名參數(shù)將自動被賦予undefined值。
嚴(yán)格模式中,像前面例子中那樣的賦值會變得無效,即使把arguments[1]設(shè)置為10,num2的值仍然還是undefined。其次,重寫arguments的值會導(dǎo)致語法錯誤。

ECMAScript中的所有參數(shù)傳遞的都是值,不可能通過引用傳遞參數(shù)。

3.7.2 沒有重載

ECMAScript函數(shù)不能像傳統(tǒng)意義上那樣實現(xiàn)重載。
如果在ECMAScript中定義了兩個名字相同的函數(shù),則該名字只屬于后定義的函數(shù)。

function addSomeNumber(num) {
  return num + 100;
}

function addSomeNumber(num) {
  return num + 200;
}
var result = addSomeNumber(100);  //300 

3.8 小結(jié)

以下簡要總結(jié)了ECMAScript中基本的要素。

  • ECMAScript中的基本數(shù)據(jù)類型包括UndefinedNullBooelan、NumberString。
  • 與其他語言不同,ECMAScript沒有為整數(shù)和浮點數(shù)值分別定義不同的數(shù)據(jù)類型,Number類型可用于表示所有數(shù)值。
  • Object類型,該類型是這門語言中所有對象的基礎(chǔ)類型。
  • 嚴(yán)格模式為這門語言中容易出錯的地方施加了限制。
  • ECMAScript提供了很多與C及其其他類C語言中相同的基本操作符,包括算數(shù)操作符、布爾操作符、關(guān)系操作符、相等操作符及賦值操作符等。
  • 從其他語言借鑒了很多流控制語句,例如if語句、for語句和switch語句等。

ECMAScript中的函數(shù)與其他語言中的函數(shù)有諸多不同之處。

  • 無須指定函數(shù)的返回值。
  • 實際上,未指定返回值的函數(shù)返回的是一個特殊的undefined值。
  • ECMAScript中也沒有函數(shù)簽名的概念,因為其函數(shù)參數(shù)是以一個包含零或多個值的數(shù)組的形式傳遞的。
  • 可以向ECMAScript函數(shù)傳遞任意數(shù)量的參數(shù),并且可以通過arguments對象來訪問這些參數(shù)。
  • 由于不存在函數(shù)簽名的特性,ECMAScript函數(shù)不能重載。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容