四、JavaScript 引用類(lèi)型

??引用類(lèi)型的值(對(duì)象)是引用類(lèi)型的一個(gè)實(shí)例华畏。

??在 ECMAscript 中鹏秋,引用類(lèi)型是一種數(shù)據(jù)結(jié)構(gòu),用于將數(shù)據(jù)和功能組織在一起亡笑。

??引用類(lèi)型有時(shí)候也被稱(chēng)為對(duì)象定義侣夷,因?yàn)樗鼈兠枋龅氖且活?lèi)對(duì)象所具有的屬性和方法。

??對(duì)象是某個(gè)特定引用類(lèi)型的實(shí)例仑乌。新對(duì)象是使用 new 操作符后跟一個(gè)構(gòu)造函數(shù)來(lái)創(chuàng)建百拓,構(gòu)造函數(shù)本身就是一個(gè)函數(shù),只不過(guò)該函數(shù)是出于創(chuàng)建新對(duì)象的目的而定義的晰甚。

let person = new Object();

??這行代碼創(chuàng)建了 Object 引用類(lèi)型的一個(gè)新實(shí)例衙传,然后把該實(shí)例保存在了變量 person 中。使用的構(gòu)造函數(shù)是 Object厕九,它只為新對(duì)象定義了默認(rèn)的屬性和方法蓖捶。

1、Object 類(lèi)型

??到目前為止止剖,我們看到的大多數(shù)引用類(lèi)型值都是 Object 類(lèi)型的實(shí)例腺阳。而且落君,Object 也是 ECMAscript 中使用最多的一個(gè)類(lèi)型。
??創(chuàng)建 Object 實(shí)例的方式有兩種亭引。
??第一種是使用 new 操作符后跟 Object 構(gòu)造函數(shù):

let person = new Object();
person.name = 'Jack';
person.age = 21;

??另一種是使用對(duì)象字面量表示法绎速。對(duì)象字面量是對(duì)象定義的一種簡(jiǎn)寫(xiě)形式,目的在于簡(jiǎn)化創(chuàng)建包含大量屬性的對(duì)象的過(guò)程焙蚓。示例:

let person = {
   name: 'Jack',
   age: 21
};

??對(duì)象字面量也是向函數(shù)傳遞大量可選參數(shù)的首選方式纹冤,例如:

function displayInfo(args) {
    let output = '';
    if (typeof args.name === 'string') {
        output += `Name: ${args.name}\n`;
    }
    if (typeof args.age === 'number') {
        output += `Age: ${args.age}\n`;
    }
    console.log(output);
}
displayInfo({
    name: 'Jack',
    age: 21
});
displayInfo({
    name: 'Jack'
});

??這種傳遞參數(shù)的模式最適合需要向函數(shù)傳入可選參數(shù)的情形。一般來(lái)講购公,命名參數(shù)雖然容易處理萌京,但在有多個(gè)可選參數(shù)的情況下就會(huì)顯示不夠靈活。最好的做法是對(duì)那些必需值使用命名參數(shù)宏浩,而使用對(duì)象字面量來(lái)封裝多個(gè)可選參數(shù)知残。

??一般來(lái)說(shuō),訪(fǎng)問(wèn)對(duì)象屬性時(shí)使用點(diǎn)表示法比庄。但在 JavaScript 中求妹,也可以使用方括號(hào)表示法來(lái)訪(fǎng)問(wèn)對(duì)象的屬性。使用方括號(hào)表示法時(shí)佳窑,將要訪(fǎng)問(wèn)的屬性以字符串的形式放在方括號(hào)中制恍。示例:

console.log(person['name']); // 'Jack'
console.log(person.name); // 'Jack'

??方括號(hào)語(yǔ)法的主要有點(diǎn)是可以通過(guò)變量來(lái)訪(fǎng)問(wèn)屬性,例如:

let propertyName = 'name';
console.log(person[porpertyName]); // 'Jack'

??如果屬性名中包含會(huì)導(dǎo)致語(yǔ)法錯(cuò)誤的字符神凑,或者屬性名使用的是關(guān)鍵字或保留字净神,也可以使用方括號(hào)表示法。

建議:除非必須使用變量來(lái)訪(fǎng)問(wèn)屬性溉委,否則我們建議使用點(diǎn)表示法鹃唯。

2、Array 類(lèi)型

??除 Object 之外薛躬, Array 類(lèi)型恐怕是 ECMAscript 中最常用的類(lèi)型了俯渤。
ECMAscript 中的數(shù)組與其他語(yǔ)言的不同:

  • ECMAscript 數(shù)組的每一項(xiàng)可以保存任何類(lèi)型的數(shù)據(jù)
  • ECMAscript 數(shù)組的大小是可以動(dòng)態(tài)調(diào)整的,即可以隨著數(shù)據(jù)的添加自動(dòng)增長(zhǎng)以容納新增數(shù)據(jù)型宝。

創(chuàng)建數(shù)組的基本方式有兩種八匠。第一種使用 Array 構(gòu)造函數(shù),示例:

let colors = new Array();

??如果預(yù)先知道數(shù)組要保存的項(xiàng)目數(shù)量趴酣,也可以給構(gòu)造函數(shù)傳遞該數(shù)量梨树,而該數(shù)量會(huì)自動(dòng)變成 length 屬性的值。例如:

// 創(chuàng)建 length 值為 20 的數(shù)組
let colors = new Array(20);

??也可以向 Array 構(gòu)造函數(shù)傳遞數(shù)組中應(yīng)該包含的項(xiàng)岖寞。例如:

// 創(chuàng)建包含 3 個(gè)字符串值的數(shù)組
let colors = new Array('red', 'blue', 'green');

??給構(gòu)造函數(shù)傳遞一個(gè)值時(shí)抡四,如果傳遞的是數(shù)值,則會(huì)按照該數(shù)值創(chuàng)建包含給定項(xiàng)數(shù)的數(shù)組;如果傳遞的是其他類(lèi)型的參數(shù)指巡,則會(huì)創(chuàng)建包含那個(gè)值的只有一項(xiàng)的數(shù)組淑履。
??使用 Array 構(gòu)造函數(shù)時(shí)可以省略 new 操作符。

??創(chuàng)建數(shù)組的第二種基本方法是使用數(shù)組字面量表示法藻雪。數(shù)組字面量由一對(duì)包含數(shù)組項(xiàng)的方括號(hào)表示秘噪,多個(gè)數(shù)組項(xiàng)之間以逗號(hào)隔開(kāi),示例:

// 創(chuàng)建一個(gè)包含 3 個(gè)字符串的數(shù)組
let colors = ['red', 'blue', 'green']; 

// 創(chuàng)建一個(gè)空數(shù)組
let name = [];

// 不要這樣勉耀!會(huì)創(chuàng)建一個(gè)包含 2 或 3(IE8 及之前版本)項(xiàng)的數(shù)組
let values = [1, 2, ];

// 不要這樣指煎!會(huì)創(chuàng)建一個(gè)包含 5 或 6(IE8 及之前版本)項(xiàng)的數(shù)組
let options = [ , , , , , ]; 

??如上述最后一行代碼所示,在像這種省略值的情況下便斥,每一項(xiàng)都將獲得 undefined 值至壤;這個(gè)結(jié)果與調(diào)用 Array 構(gòu)造函數(shù)時(shí)傳遞項(xiàng)數(shù)在邏輯上是相同的。但是由于 IE(IE8 及之前版本)的實(shí)現(xiàn)與其它瀏覽器不一致枢纠,因此我們不建議使用這種語(yǔ)法像街。

??在讀取和設(shè)置數(shù)組的值是,要使用方括號(hào)并提供相應(yīng)的基于 0 的數(shù)字索引京郑。示例:

let colors = ['red', 'blue', 'green']; // 定義一個(gè)字符串?dāng)?shù)組
console.log(colors[0]);    // 顯示第一項(xiàng)
colors[2] = 'black';       // 修改第三項(xiàng)
colors[3] = 'brown';       // 新增第四項(xiàng)

方括號(hào)中的索引表示要訪(fǎng)問(wèn)的值宅广。
數(shù)組的項(xiàng)數(shù)保存在其 length 屬性中葫掉。
??數(shù)組的 length 屬性不是只讀的些举,通過(guò)設(shè)置這個(gè)屬性,可以從數(shù)組的末尾移除項(xiàng)或向數(shù)組中添加新項(xiàng)俭厚。示例:

let colors = ['red', 'blue', 'green']; // 創(chuàng)建一個(gè)包含 3 個(gè)字符串的數(shù)組
colors.length = 2;
console.log(colors[2]);  // undefined

??如果將其 length 屬性設(shè)置為大于數(shù)組項(xiàng)數(shù)的值户魏,則新增的每一項(xiàng)都會(huì)取得 undefined 值,示例:

let colors = ['red', 'blue', 'green']; // 創(chuàng)建一個(gè)包含 3 個(gè)字符串的數(shù)組
colors.length = 4;
console.log(colors[3]);  // undefined

??利用 length 屬性也可以方便地在數(shù)組末尾添加新項(xiàng)挪挤, 示例:

let colors = ['red', 'blue', 'green']; // 創(chuàng)建一個(gè)包含 3 個(gè)字符串的數(shù)組
colors[colors.length] = 'black'; // (在位置 3)添加一種顏色
colors[colors.length] = 'brown'; // (在位置 4)添加一種顏色

??數(shù)組最多可以包含 4 294 967 295 個(gè)項(xiàng)叼丑。如果想添加的項(xiàng)數(shù)超過(guò)這個(gè)上限,就會(huì)發(fā)生異常扛门。而創(chuàng)建一個(gè)初始大小與這個(gè)上限值接近的數(shù)組鸠信,咋可能會(huì)導(dǎo)致運(yùn)行時(shí)間超長(zhǎng)的腳本錯(cuò)誤。

2.1论寨、檢測(cè)數(shù)組

使用 Array.isArray() 方法檢測(cè)某個(gè)值是不是數(shù)組星立,示例:

if (Array.isArray(value)) {
    // 對(duì)數(shù)組執(zhí)行某些操作
}

??支持 Array.isArray() 方法的瀏覽器有 IE9+、Firefox 4+葬凳、Safari 5+绰垂、Opera 10.5+ 和 chrome。

2.2火焰、轉(zhuǎn)換方法

??調(diào)用數(shù)組的 toString() 方法會(huì)返回由數(shù)組中的每個(gè)值的字符串形式拼接而成的一個(gè)以逗號(hào)分隔的字符串劲装,而調(diào)用 valueOf() 方法返回的還是數(shù)組。示例:

let colors = ['red', 'blue', 'green']; // 創(chuàng)建一個(gè)包含 3 個(gè)字符串的數(shù)組
console.log(colors.toString()); // red,blue,green
console.log(colors.valueOf()); // ['red', 'blue', 'green']
console.log(colors); // ['red', 'blue', 'green']

??數(shù)組繼承的 toLocaleString()、toString() 方法占业,在默認(rèn)情況下都會(huì)以逗號(hào)分隔的字符串形式返回?cái)?shù)組項(xiàng)绒怨。
??使用 join() 方法,可以使用不同的分隔符來(lái)構(gòu)建這個(gè)字符串谦疾。join() 方法只接收一個(gè)參數(shù)窖逗,即用作分隔符的字符串,然后返回包含所有數(shù)組項(xiàng)的字符串餐蔬。示例:

let colors = ['red', 'blue', 'green'];
console.log(colors.join(','));  // red,blue,green
console.log(colors.join('||'));  // red||blue||green

??如果不給 join() 方法傳入任何值碎紊,或者傳入 undefined,則默認(rèn)使用逗號(hào)作為分隔符樊诺。IE7及更早版本會(huì)錯(cuò)誤的使用字符串 'undefined' 作為分隔符仗考。

??如果數(shù)組中的某一項(xiàng)值是 null 或 undefined,那么該值在 join()词爬、toLocaleString()秃嗜、toString() 方法返回的結(jié)果中以空字符串表示。

2.3顿膨、棧方法

??棧是一種 LIFO(Last-In-First-Out锅锨,后進(jìn)先出)的數(shù)據(jù)結(jié)構(gòu)。棧中項(xiàng)的插入(叫做推入)和移除(叫做彈出)恋沃,只發(fā)生在一個(gè)位置——棧的頂部必搞。
??ECMAscript 為數(shù)組專(zhuān)門(mén)提供了 push() 和 pop() 方法,以便實(shí)現(xiàn)類(lèi)似棧的行為囊咏。
??push() 方法可以接收任意數(shù)量的參數(shù)恕洲,把它們逐個(gè)添加到數(shù)組末尾,并返回修改后數(shù)組的長(zhǎng)度梅割。而 pop() 方法則從數(shù)組末尾移除最后一項(xiàng)霜第,減少數(shù)組的 length 值,然后返回移除的項(xiàng)户辞。示例:

let colors = new Array();                // 創(chuàng)建一個(gè)數(shù)組
let count = colors.push('red', 'green'); // 推入兩項(xiàng)
console.log(count); //2

count = colors.push('black');            // 推入另一項(xiàng)
console.log(count); //3

let item = colors.pop();                 // 取得最后一項(xiàng)
console.log(item); // 'black'
console.log(colors.length); //2

2.4泌类、隊(duì)列方法

??隊(duì)列數(shù)據(jù)結(jié)構(gòu)的訪(fǎng)問(wèn)規(guī)則是FIFO(First-In-First-Out,先進(jìn)先出)底燎。隊(duì)列在列表末端添加項(xiàng)刃榨,從列表的前端移除項(xiàng)。
??shift() 方法能夠移除數(shù)組中的第一個(gè)項(xiàng)并返回該項(xiàng)书蚪,同時(shí)將數(shù)組長(zhǎng)度減 1喇澡。結(jié)合使用 shift() 和 push() 方法,可以像使用隊(duì)列一樣使用數(shù)組殊校。示例:

let colors = new Array();                 // 創(chuàng)建一個(gè)數(shù)組
let count = colors.push('red', 'green');  // 推入兩項(xiàng)
console.log(count);  // 2

count = colors.push('black');             // 推入另一項(xiàng)
console.log(count);  // 3

let item = colors.shift();                // 取得第一項(xiàng)
console.log(item);  // 'red'
console.log(colors.length);  // 2 

??unshift() 方法與 shift() 方法用途相反晴玖,它能在數(shù)組前端添加任意個(gè)項(xiàng)并返回新數(shù)組的長(zhǎng)度。同時(shí)使用 unshift() 和 pop() 方法,可以從相反的方向來(lái)模擬隊(duì)列呕屎,即在數(shù)組的前端添加項(xiàng)让簿,從數(shù)組末端移除項(xiàng)。示例:

let colors = new Array();                    // 創(chuàng)建一個(gè)數(shù)組
let count = colors.unshift('red', 'green');  // 推入兩項(xiàng)
console.log(count);  // 2 

count = colors.unshift('black');             // 推入另一項(xiàng)
console.log(count);  // 3

let item = colors.pop();                     // 取得最后一項(xiàng)
console.log(item);  // 'green'
console.log(colors.length);  // 2 

2.5秀睛、重排序方法

??數(shù)組中存在兩個(gè)可以直接用來(lái)重排序的方法: reverse() 和 sort() 方法尔当。
??reverse() 方法會(huì)反轉(zhuǎn)數(shù)組項(xiàng)的順序。示例:

let values = [1, 2, 3, 4, 5];
values.reverse();
console.log(values); // [5, 4, 3, 2, 1];

??默認(rèn)情況下蹂安,sort() 方法按升序排列數(shù)組項(xiàng)——即最小的值位于最前面椭迎,最大值排在最后面。為了實(shí)現(xiàn)排序田盈,sort() 方法會(huì)調(diào)用每個(gè)數(shù)組項(xiàng)的 toString() 轉(zhuǎn)型方法畜号,然后比較得到的字符串,以確定如何排序允瞧。即使數(shù)組中的每一項(xiàng)都是數(shù)值备韧,sort() 方法比較的也是字符串州叠,示例:

let values = [0, 1, 5, 10, 15];
values.sort();
console.log(values); // [0, 1, 10, 15, 5];

??sort() 方法可以(僅可以)接收一個(gè)比較函數(shù)作為參數(shù),以便我們制定數(shù)組的排序午笛。接收函數(shù)的返回值判斷數(shù)組的排序拒课。

a 和 b 比較之后:

  • 返回一個(gè)小于 0 的值酌儒, a 在 b 之前轧叽。
  • 返回 0罗洗,a、b 的順序不變廊驼。
  • 返回一個(gè)大于 0 的值据过,a 在 b 之后。

??對(duì)于數(shù)值類(lèi)型或者其 valueOf() 方法會(huì)返回?cái)?shù)值類(lèi)型的對(duì)象類(lèi)型妒挎,可以使用下面的比較函數(shù),示例:

function compare(a, b) {
    return a - b;
}
let values = [0, 1, 5, 10, 15];
values.sort(compare);
console.log(values); // [0, 1, 10, 15, 5];

??對(duì)于其它對(duì)象類(lèi)型西饵,可以使用下列比較函數(shù)酝掩,指定返回值:

function compare(value1, value2) {
    if (value1 < value2) {
         return -1;
     } else if (value1 > value2) {
         return 1;
     } else {
         return 0;
     } 
} 

reverse() 和 sort() 方法的返回值是經(jīng)過(guò)排序之后的數(shù)組。

2.6眷柔、操作方法

??concat() —— 可以基于當(dāng)前數(shù)組中的所有項(xiàng)創(chuàng)建一個(gè)新數(shù)組期虾。

??具體來(lái)說(shuō),這個(gè)方法會(huì)先創(chuàng)建當(dāng)前數(shù)組的一個(gè)副本然后將接收到的參數(shù)添加到這個(gè)副本的末尾驯嘱,最后返回新構(gòu)建的數(shù)組镶苞。在沒(méi)有給 concat() 方法傳遞參數(shù)的情況下,它只是復(fù)制當(dāng)前數(shù)組并返回副本鞠评。如果傳遞給 concat() 方法的是一或多個(gè)數(shù)組茂蚓,則該方法會(huì)將這些數(shù)組中的每一項(xiàng)都添加到結(jié)果數(shù)組中。如果傳遞的值不是數(shù)組,這些值就會(huì)被簡(jiǎn)單地添加到結(jié)果數(shù)組的末尾聋涨。

let colors = ['red', 'green', 'blue'];
let colors2 = colors.concat('yellow', ['black', 'brown']);

console.log(colors);  // ['red', 'green', 'blue']
console.log(colors2); // ['red', 'green', 'blue', 'yellow', 'black', 'brown']
??slice() —— 它能夠基于當(dāng)前數(shù)組中的一或多個(gè)項(xiàng)創(chuàng)建一個(gè)新數(shù)組晾浴。

??slice() 方法可以接受一或兩個(gè)參數(shù),即要返回項(xiàng)的起始和結(jié)束位置牍白。在只有一個(gè)參數(shù)的情況下脊凰,slice() 方法返回從該參數(shù)指定位置開(kāi)始到當(dāng)前數(shù)組末尾的所有項(xiàng)。如果有兩個(gè)參數(shù)茂腥,該方法返回起始和結(jié)束位置之間的項(xiàng)——但不包括結(jié)束位置的項(xiàng)狸涌。示例:

let colors = ['red', 'green', 'blue', 'yellow', 'black', 'brown'];
let colors2 = colors.slice(1);
let colors3 = colors.slice(1,4); 

console.log(colors2);  // ['green', 'blue', 'yellow', 'black', 'brown']
console.log(colors3);  // ['green', 'blue', 'yellow']

slice() 方法不會(huì)影響原始數(shù)組。

??如果 slice()方法的參數(shù)中有一個(gè)負(fù)數(shù)最岗,則用數(shù)組長(zhǎng)度加上該數(shù)來(lái)確定相應(yīng)的位置杈抢。例如,在一個(gè)包含 5 項(xiàng)的數(shù)組上調(diào)用 slice(-2, -1)與調(diào)用 slice(3, 4) 得到的結(jié)果相同仑性。如果結(jié)束位置小于起始位置惶楼,則返回空數(shù)組。

splice() —— 最強(qiáng)大的數(shù)組方法诊杆。

刪除
功能:可以刪除任意數(shù)量的項(xiàng)歼捐。
參數(shù):2 個(gè);要?jiǎng)h除的第一項(xiàng)的位置晨汹,要?jiǎng)h除的項(xiàng)數(shù)
示例:

let colors = ['red', 'green', 'blue', 'yellow'];
let colors2 = colors.splice(1, 2);  // 從位置 1 開(kāi)始刪除 2 項(xiàng)

console.log(colors);  // ['red', 'yellow']
console.log(colors2);  // ['green', 'blue']豹储, 返回的數(shù)組中包含 2 項(xiàng)

插入
功能:可以向指定位置插入任意數(shù)量的項(xiàng)。
參數(shù):3淘这;起始位置剥扣,0(要?jiǎng)h除的項(xiàng)數(shù)),要插入的項(xiàng)(如果要插入多個(gè)項(xiàng)铝穷,可以再傳入第四钠怯、第五,以至任意項(xiàng)曙聂。
示例:

let colors = ['red', 'green', 'blue', 'yellow'];
let colors2 = colors.splice(1, 0, 'black', 'orange');  // 從位置 1 開(kāi)始插入 2  項(xiàng)

console.log(colors);  // ['red', 'black', 'orange', 'green', 'blue', 'yellow']
console.log(colors2);  // []晦炊, 返回一個(gè)空數(shù)組

替換
功能:可以向指定位置插入任意數(shù)量的項(xiàng),且同時(shí)刪除任意數(shù)量的項(xiàng)宁脊。
參數(shù):3断国;起始位置,要?jiǎng)h除的項(xiàng)數(shù)榆苞,要插入的任意數(shù)量的項(xiàng)
示例:

let colors = ['red', 'green', 'blue', 'yellow'];
let colors2 = colors.splice(1, 1, 'pink', 'purple');  // 從位置 1 開(kāi)始刪除 1 項(xiàng)稳衬,插入 2 項(xiàng)

console.log(colors);  // ['red', 'pink', 'purple', 'blue', 'yellow']
console.log(colors2);  // ['green'], 返回的數(shù)組中包含 1 項(xiàng)

??splice() 方法始終會(huì)返回一個(gè)數(shù)組坐漏,該數(shù)組中包含從原始數(shù)組中刪除的項(xiàng)(如果沒(méi)有刪除任何項(xiàng)薄疚,則返回一個(gè)空數(shù)組)碧信。

2.7、位置方法

indexOf()
功能:返回要查找的項(xiàng)在數(shù)組中的位置输涕,從數(shù)組開(kāi)頭向后查找音婶。
參數(shù):2;要查找的項(xiàng)莱坎,(可選)查找起點(diǎn)位置的索引衣式。

lastIndexOf()
功能:返回要查找的項(xiàng)在數(shù)組中的位置,從數(shù)組末尾向前查找檐什。
參數(shù):2碴卧;要查找的項(xiàng),(可選)查找起點(diǎn)位置的索引乃正。

??這兩個(gè)方法都返回要查找的項(xiàng)在數(shù)組中的位置住册,或者在沒(méi)有找到的情況下返回 -1。使用全等操作符(===)進(jìn)行比較瓮具。

示例:

let numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];

console.log(numbers.indexOf(4)); // 3荧飞,從頭開(kāi)始向后的第一個(gè) 4
console.log(numbers.lastIndexOf(4)); // 5,從末尾開(kāi)始向前的第一個(gè) 4

console.log(numbers.indexOf(4, 4)); // 5名党,從第 4 位開(kāi)始向后的第一個(gè) 4
console.log(numbers.lastIndexOf(4, 4)); // 3叹阔,從第 4 位開(kāi)始向前的第一個(gè) 4

let person = { name: "Nicholas" };
let people = [{ name: "Nicholas" }];

let morePeople = [person];

console.log(people.indexOf(person)); // -1
console.log(morePeople.indexOf(person)); // 0 

2.8、迭代方法

??數(shù)組的每個(gè)迭代方法都接收 2 參數(shù):要在每一項(xiàng)上運(yùn)行的函數(shù)和(可選的)運(yùn)行該函數(shù)的作用域?qū)ο蟆绊?this 的值传睹。
??傳入這些這些方法中的函數(shù)會(huì)接受 3 個(gè)參數(shù):數(shù)組項(xiàng)的值耳幢、該項(xiàng)在數(shù)組中的位置、數(shù)組對(duì)象本身欧啤。

以下是 5 個(gè)迭代方法的作用:

  • every():對(duì)數(shù)組中的每一項(xiàng)運(yùn)行給定函數(shù)睛藻,如果該函數(shù)對(duì)每一項(xiàng)都返回 true ,則返回 true邢隧。
  • some():對(duì)數(shù)組中的每一項(xiàng)運(yùn)行給定函數(shù)店印,如果該函數(shù)對(duì)任一項(xiàng)返回 true,則返回 true府框。
  • filter():對(duì)數(shù)組中的每一項(xiàng)運(yùn)行給定函數(shù)吱窝,返回該函數(shù)會(huì)返回 true 的項(xiàng)組成的數(shù)組。
  • map():對(duì)數(shù)組中的每一項(xiàng)運(yùn)行給定函數(shù)迫靖,返回每次函數(shù)調(diào)用的結(jié)果組成的數(shù)組。
  • forEach():對(duì)數(shù)組中的每一項(xiàng)運(yùn)行給定函數(shù)兴使,這個(gè)方法沒(méi)有返回值系宜。

??以上方法都不會(huì)修改數(shù)組中包含的值。

??every() 和 some() 都用于查詢(xún)數(shù)組中的項(xiàng)是否滿(mǎn)足某個(gè)條件发魄。示例:

let numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];

let everyResult = numbers.every(function(item, index, array){
    return (item > 2);
});
console.log(everyResult); // false

let someResult = numbers.some(function(item, index, array){
 return (item > 2);
});
console.log(someResult); // true 

??filter() 函數(shù):利用指定的函數(shù)確定是否在返回的數(shù)組中包含某一項(xiàng)盹牧。

// 要返回一個(gè)所有數(shù)值都大于 2 的數(shù)組
let numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
let filterResult = numbers.filter(function(item, index, array){
 return (item > 2);
});
console.log(filterResult); // [3, 4, 5, 4, 3] 

??map() 函數(shù):返回一個(gè)數(shù)組俩垃,而這個(gè)數(shù)組的每一項(xiàng)都是在原始數(shù)組中的對(duì)應(yīng)項(xiàng)運(yùn)行傳入函數(shù)的結(jié)果。cif

// 給數(shù)組中的每一項(xiàng)乘以 2
let numbers = [1, 2, 3, 4, 5, 4, 3, 2, 1];
let mapResult = numbers.map(function(item, index, array){
 return item * 2;
});
console.log(mapResult); // [2, 4, 6, 8, 10, 8, 6, 4, 2] 

??forEach() 方法:對(duì)數(shù)組的每一項(xiàng)運(yùn)行傳入的函數(shù)汰寓,沒(méi)有返回值口柳。本質(zhì)上與使用 for 循環(huán)迭代數(shù)組一樣。

let numbers = [1,2,3,4,5,4,3,2,1];
numbers.forEach(function(item, index, array){
 // 執(zhí)行某些操作
}); 

2.9有滑、歸并方法

??reduce() 和 reduceRight() 是歸并數(shù)組的方法跃闹。兩個(gè)方法都會(huì)迭代數(shù)組的所有項(xiàng),然后構(gòu)建一個(gè)最終返回的值毛好。

??reduce() 方法從數(shù)組的第一項(xiàng)開(kāi)始望艺,逐個(gè)遍歷到最后。
??reduceRight() 方法從數(shù)組的最后一項(xiàng)開(kāi)始肌访,向前遍歷到第一項(xiàng)找默。

??這兩個(gè)方法都接收兩個(gè)參數(shù):在每一項(xiàng)上調(diào)用的函數(shù),(可選)最為歸并基礎(chǔ)的初始值吼驶。
??傳給 reduce() 和 reduceRight() 的函數(shù)接收 4 個(gè)函數(shù):前一個(gè)值惩激、當(dāng)前值、項(xiàng)的索引蟹演、數(shù)組對(duì)象风钻。這個(gè)函數(shù)的返回的任何值都會(huì)作為第一個(gè)參數(shù)自動(dòng)傳給下一項(xiàng)。
??第一次迭代發(fā)生在數(shù)組的第二項(xiàng)上轨帜,因此第一個(gè)參數(shù)是數(shù)組的第一項(xiàng)魄咕,第二個(gè)參數(shù)是數(shù)組的第二項(xiàng)。

// 求數(shù)組中所有值之和
let values = [1, 2, 3, 4, 5];
let sum = values.reduce(function(prev, cur, index, array){
 return prev + cur;
});
console.log(sum); // 15 

??第一次執(zhí)行回調(diào)函數(shù)蚌父, prev 是 1(數(shù)組的第一項(xiàng))哮兰, cur 是 2(數(shù)組的第二項(xiàng));第二次苟弛,prev 是 3(1 + 2 的結(jié)果)喝滞,cur 是 3(數(shù)組的第三項(xiàng))。這個(gè)過(guò)程會(huì)持續(xù)到吧數(shù)組中的每一項(xiàng)都訪(fǎng)問(wèn)一遍膏秫,最后返回結(jié)果右遭。

??reduceRight() 的作用類(lèi)似,只不過(guò)方向相反缤削。

// 求數(shù)組中所有值之和
let values = [1, 2, 3, 4, 5];
let sum = values.reduceRight(function(prev, cur, index, array){
 return prev + cur;
});
console.log(sum); // 15 

??上述例子中窘哈,第一次執(zhí)行回調(diào)函數(shù), prev 是 5(數(shù)組的最后一項(xiàng))亭敢, cur 是 4(數(shù)組的倒數(shù)第二項(xiàng))滚婉;

3、Date 類(lèi)型

??Date 類(lèi)型使用自 UTC(Coordinated Universal Time帅刀, 國(guó)際協(xié)調(diào)時(shí)間)1970 年 1 月 1 日午夜(零時(shí))開(kāi)始經(jīng)過(guò)的毫秒數(shù)來(lái)保存日期让腹。在使用這種數(shù)據(jù)存儲(chǔ)格式的條件下远剩,Date 類(lèi)型保存的日期能夠精確到 1970 年 1 月 1 日之前或之后的 285 616 年。

??創(chuàng)建一個(gè)日期對(duì)象骇窍,使用 new 操作符和 Date 構(gòu)造函數(shù)瓜晤,示例:

let now = new Date();

??調(diào)用 Date 構(gòu)造函數(shù)而不傳遞參數(shù)的情況下,新創(chuàng)建的對(duì)象自動(dòng)獲得當(dāng)前日期和時(shí)間腹纳。如果想根據(jù)特定的日期和時(shí)間創(chuàng)建日期對(duì)象痢掠,必須傳入表示改日期的毫秒數(shù)(即從 UTC 時(shí)間 1970 年 1 月 1 日午夜起至該日期止經(jīng)過(guò)的毫秒數(shù))。為了簡(jiǎn)化這一計(jì)算過(guò)程只估,使用以下兩個(gè)方法:Date.parse() 和 Date.UTC()志群。

??Date.parse() 方法接收一個(gè)表示日期的字符串參數(shù),然后嘗試根據(jù)這個(gè)字符串返回相應(yīng)日期的毫秒數(shù)蛔钙。日期格式通常為以下幾種類(lèi)型:

  • '月/日/年'锌云,如 12/25/2017;
  • '英文月名 日,年',如 December 25,2017;
  • '英文星期幾 英文月名 日 年 時(shí):分:秒 時(shí)區(qū)'吁脱,如 Monday December 25 2017 00:00:00 GMT-0700;
  • ISO 8601 擴(kuò)展格式 YYYY-MM-DDTHH:mm:ss.sssZ桑涎,如 2017-12-25T00:00:00。
// 2017 年 12 月 25 日創(chuàng)建一個(gè)日期對(duì)象
let someDate = new Date(Date.parse('May 25, 2004')); 
// 等價(jià)于
let someDate = new Date('May 25, 2004'); 

??如果傳入 Date.parse() 方法的字符串不能表示日期兼贡,那么會(huì)返回 NaN攻冷。如上所述,直接將表示日期的字符串傳遞給 Date 構(gòu)造函數(shù)遍希,也會(huì)在后臺(tái)調(diào)用 Date.parse()等曼。

??Date.UTC() 方法同樣也返回表示日期的毫秒數(shù)。

Date.UTC() 的參數(shù)分別是:

  • 年份(必需)
  • 基于 0 的月份(一月是 0凿蒜,二月是 1禁谦,以此類(lèi)推)(必需)
  • 月中的一天(1 到 31)
  • 小時(shí)數(shù)(0 到 23)
  • 分鐘
  • 毫秒數(shù)

??如果沒(méi)有提供月中的天數(shù),則假設(shè)天數(shù)為 1废封;如果省略其他參數(shù)州泊,則統(tǒng)統(tǒng)假設(shè)為 0。示例:

// GMT 時(shí)間 2000 年 1 月 1 日午夜零時(shí)
let y2k = new Date(Date.UTC(2000, 0));

// GMT 時(shí)間 2017 年 12 月 25 日下午 5:55:55
let allFives = new Date(Date.UTC(2017, 11, 25, 17, 55, 55)); 

??Date 構(gòu)造函數(shù)會(huì)模仿 Date.UTC()漂洋,但有一點(diǎn)明顯不同:日期和時(shí)間都基于本地時(shí)區(qū)而非 GMT 來(lái)創(chuàng)建遥皂。不過(guò),Date 構(gòu)造函數(shù)接收的參數(shù)仍然與 Date.UTC() 相同刽漂。因此演训,如果第一個(gè)參數(shù)是數(shù)值, Date() 構(gòu)造函數(shù)就會(huì)假設(shè)該值是日期中的年份贝咙,而第二個(gè)參數(shù)是月份仇祭,以此類(lèi)推,示例:

// 本地時(shí)間 2000 年 1 月 1 日午夜零時(shí)
let y2k = new Date(2000, 0);

// 本地時(shí)間 2017 年 12 月 25 日下午 5:55:55
let allFives = new Date(2017, 11, 25, 17, 55, 55); 

??Date.now() 方法:返回調(diào)用這個(gè)方法時(shí)的日期和時(shí)間的毫秒數(shù)颈畸。這個(gè)方法簡(jiǎn)化了使用 Date 對(duì)象分析代碼的工作乌奇。例如:

// 取得開(kāi)始時(shí)間
let start = Date.now();
// 調(diào)用函數(shù)
doSomething();
// 取得停止時(shí)間
let stop = Date.now();
let result = stop – start; 

// 等價(jià)于

// 取得開(kāi)始時(shí)間
let start = +new Date();
// 調(diào)用函數(shù)
doSomething();
// 取得停止時(shí)間
let stop = +new Date();
let result = stop - start; 

??使用 + 操作符把 Date 對(duì)象轉(zhuǎn)換為字符串。

3.1眯娱、繼承的方法

??與其它引用類(lèi)型一樣礁苗, Date 類(lèi)型也重寫(xiě)了 toLocaleString()、toString()徙缴、valueOf() 方法试伙。

??Date 類(lèi)型的 toLocaleString() 方法會(huì)按照與瀏覽器設(shè)置的地區(qū)相適應(yīng)的格式返回日期和時(shí)間。這大致意味著時(shí)間格式中會(huì)包含 AM 或 PM于样,但不會(huì)包含時(shí)區(qū)信息(當(dāng)然疏叨,具體的格式會(huì)因?yàn)g覽器而異)。

??Date 類(lèi)型的 toString() 方法則通常返回帶有時(shí)區(qū)信息的日期和時(shí)間穿剖,其中時(shí)間一般以軍用時(shí)間(即小時(shí)的范圍是 0 到 23)表示蚤蔓。

??下面給出了在不同瀏覽器中調(diào)用 toLocaleString() 和 toString() 方法,輸出 PST(Pacific Standard Time糊余,太平洋標(biāo)準(zhǔn)時(shí)間)時(shí)間 2007 年 2 月 1 日午夜零時(shí)的結(jié)果秀又。

// Internet Explorer 8
toLocaleString() — Thursday, February 01, 2007 12:00:00 AM
toString() — Thu Feb 1 00:00:00 PST 2007 
// Firefox 3.5
toLocaleString() — Thursday, February 01, 2007 12:00:00 AM
toString() — Thu Feb 01 2007 00:00:00 GMT-0800 (Pacific Standard Time)
// Safari 4
toLocaleString() — Thursday, February 01, 2007 00:00:00
toString() — Thu Feb 01 2007 00:00:00 GMT-0800 (Pacific Standard Time)
// Chrome 4
toLocaleString() — Thu Feb 01 2007 00:00:00 GMT-0800 (Pacific Standard Time)
toString() — Thu Feb 01 2007 00:00:00 GMT-0800 (Pacific Standard Time)
// Opera 10
toLocaleString() — 2/1/2007 12:00:00 AM
toString() — Thu, 01 Feb 2007 00:00:00 GMT-0800 

??顯然,這兩個(gè)方法在不同的瀏覽器中返回的日期和時(shí)間格式可謂大相徑庭贬芥。事實(shí)上吐辙,toLocaleString() 和 toString() 的這一差別僅在調(diào)試代碼時(shí)比較有用,而在顯示日期和時(shí)間時(shí)沒(méi)有什么價(jià)值蘸劈。

??Date 類(lèi)型的 valueOf() 方法昏苏,不返回字符串,而是返回日期的毫秒表示威沫。因此贤惯,可以方便使用比較操作符(小于或大于)來(lái)比較日期值。示例:

var date1 = new Date(2017, 0, 1); // 'January 1, 2017'
var date2 = new Date(2017, 1, 1); // 'February 1, 2017'
console.log(date1 < date2); // true
console.log(date1 > date2); // false 

3.2壹甥、日期格式化方法

Date() 類(lèi)型有一些專(zhuān)門(mén)用于將日期格式化為字符串的方法救巷,

  • toDateString() —— 以特定于實(shí)現(xiàn)的格式顯示星期幾、月句柠、日浦译、年;
  • toTimeString() —— 以特定于實(shí)現(xiàn)的格式顯示時(shí)溯职、分精盅、秒、時(shí)區(qū)谜酒;
  • toLocaleDateString() —— 以特定于地區(qū)的格式顯示星期幾叹俏、月、日僻族、年粘驰;
  • toLocaleTimeString() —— 以特定于地區(qū)的格式顯示時(shí)屡谐、分、秒蝌数;
  • toUTCString() —— 以特定于實(shí)現(xiàn)的格式完整的 UTC 日期愕掏。

??與 toLocaleString() 和 toString() 方法一樣段磨,以上這些字符串格式方法的輸出也是因?yàn)g覽器而異的绍傲,因此沒(méi)有哪一個(gè)方法能夠用來(lái)在用戶(hù)界面中顯示一致的日期信息。

3.3呜达、日期/時(shí)間組件方法

??以下是直接取得和設(shè)置日期值中特定部分的方法:

本地日期

方法 說(shuō)明
getTime() 返回毫秒數(shù)唆貌;與 valueOf() 方法返回值相同
getFullYear() 返回4位數(shù)的年份
getMonth() 返回月份滑潘,其中 0 表示一月,11 表示十二月
getDate() 返回月份中的天數(shù)(1 到 31)
getDay() 返回星期的星期幾(其中 0 表示星期日锨咙,6 表示星期六)
getHours() 返回小時(shí)數(shù)(0 到 23)
getMinutes() 返回分鐘數(shù)(0 到 59)
getSeconds() 返回秒數(shù)(0 到 59)
getMilliseconds() 返回毫秒數(shù)
getTimezoneOffset() 返回本地時(shí)間與 UTC 時(shí)間相差的分鐘數(shù)

UTC 日期

方法 說(shuō)明
getUTCFullYear() 返回UTC日期的4位數(shù)年份
getUTCMonth() 返回UTC日期中的月份语卤,其中0表示一月,11表示十二月
getUTCDate() 返回UTC日期月份中的天數(shù)(1到31)
getUTCDay() 返回UTC日期中星期的星期幾(其中0表示星期日蓖租,6表示星期六)
getUTCHours() 返回UTC日期中的小時(shí)數(shù)(0到23)
getUTCMinutes() 返回UTC日期中的分鐘數(shù)(0到59)
getUTCSeconds() 返回UTC日期中的秒數(shù)(0到59)
getUTCMilliseconds() 返回UTC日期中的毫秒數(shù)

設(shè)置本地日期

方法 說(shuō)明
setTime(毫秒) 以毫秒數(shù)設(shè)置日期粱侣,會(huì)改變整個(gè)日期
setFullYear(年) 設(shè)置日期的年份。傳入的年份值必須是 4 位數(shù)字
setMonth(月) 設(shè)置日期的月份蓖宦。傳入的月份值必須大于 0齐婴,超過(guò) 11 則增加年份
setDate(日) 設(shè)置日期月份中的天數(shù)。如果傳入的值超過(guò)了該月中應(yīng)有的天數(shù)稠茂,則增加月份
setHours(時(shí)) 設(shè)置日期中的小時(shí)數(shù)柠偶。傳入的值超過(guò)了 23 則增加月份中的天數(shù)
setMinutes(分) 設(shè)置日期中的分鐘數(shù)。傳入的值超過(guò) 59 則增加小時(shí)數(shù)
setSeconds(秒) 設(shè)置日期中的秒數(shù)睬关。傳入的值超過(guò)了 59 會(huì)增加分鐘數(shù)
setMilliseconds(毫秒) 設(shè)置日期中的毫秒數(shù)

設(shè)置 UTC 日期

方法 說(shuō)明
setUTCFullYear(年) 設(shè)置UTC日期的年份诱担。傳入的年份值必須是 4 位數(shù)字
setUTCMonth(月) 設(shè)置UTC日期的月份。傳入的月份值必須大于 0电爹,超過(guò)11則增加年份
setUTCDate(日) 設(shè)置UTC日期月份中的天數(shù)蔫仙。如果傳入的值超過(guò)了該月中應(yīng)有的天數(shù),則增加月份
setUTCHours(時(shí)) 設(shè)置UTC日期中的小時(shí)數(shù)丐箩。傳入的值超過(guò)了23則增加月份中的天數(shù)
setUTCMinutes(分) 設(shè)置UTC日期中的分鐘數(shù)摇邦。傳入的值超過(guò)59則增加小時(shí)數(shù)
setUTCSeconds(秒) 設(shè)置UTC日期中的秒數(shù)。傳入的值超過(guò)了59會(huì)增加分鐘數(shù)
setUTCMilliseconds(毫秒) 設(shè)置UTC日期中的毫秒數(shù)

4屎勘、RegExp 類(lèi)型

??ECMAScript 通過(guò) RegExp 類(lèi)型來(lái)支持正則表達(dá)式施籍。2 種創(chuàng)建正則表達(dá)式的方法:

  • 使用字面量形式來(lái)定義正則表達(dá)式
  • 使用 RegExp 構(gòu)造函數(shù)

使用字面量形式來(lái)定義正則表達(dá)式

let expression = / pattern / flags ; 

??其中的模式(pattern)部分可以是任何簡(jiǎn)單或復(fù)雜的正則表達(dá)式,可以包含字符類(lèi)概漱、限定符丑慎、分組、向前查找、反向引用竿裂。每個(gè)正則表達(dá)式都可帶有一或多個(gè)標(biāo)志(flags)玉吁,用以標(biāo)明正則表達(dá)式的行為。

正則表達(dá)式的匹配模式支持下列 3 個(gè)標(biāo)志:

  • g:表示全局(global)模式铛绰,即模式將被應(yīng)用于所有字符串诈茧,而非在發(fā)現(xiàn)第一個(gè)匹配項(xiàng)時(shí)立即停止;
  • i:表示不區(qū)分大小寫(xiě)(case-insensitive)模式捂掰,即在確定匹配項(xiàng)時(shí)忽略模式與字符串的大小寫(xiě);
  • m:表示多行(multiline)模式曾沈,即在到達(dá)一行文本末尾時(shí)還會(huì)繼續(xù)查找下一行中是否存在與模式匹配的項(xiàng)这嚣。

??因此,一個(gè)正則表達(dá)式就是一個(gè)模式與上述 3 個(gè)標(biāo)志的組合體塞俱。示例:

// 匹配字符串中所有 "at" 的實(shí)例
let pattern1 = /at/g; 

// 匹配第一個(gè) "bat" 或 "cat"姐帚,不區(qū)分大小寫(xiě)
let pattern2 = /[bc]at/i; 

// 匹配所有以 "at" 結(jié)尾的 3 個(gè)字符的組合,不區(qū)分大小寫(xiě)
let  pattern3 = /.at/gi; 

??與其他語(yǔ)言中的正則表達(dá)式類(lèi)似障涯,模式中使用的所有元字符都必須轉(zhuǎn)義罐旗。正則表達(dá)式中的元字符包括:

( [ { \ ^ $ | ) ? * + . ] } 

??這些元字符在正則表達(dá)式中都有一或多種特殊用途,因此如果想要匹配字符串中包含的這些字符唯蝶,就必須對(duì)它們進(jìn)行轉(zhuǎn)義九秀。示例:

// 匹配第一個(gè) "bat" 或 "cat",不區(qū)分大小寫(xiě)
let pattern1 = /[bc]at/i; 

// 匹配第一個(gè) "[bc]at" 粘我,不區(qū)分大小寫(xiě)
let patter2 =  /\[bc\]at/i; 

??上述例子中鼓蜒,pattern1 匹配第一個(gè) "bat" 或 "cat",不區(qū)分大小寫(xiě)征字。而要想直接匹配 "[bc]at" 的話(huà)都弹,就需要像定義 pattern2 一樣,對(duì)其中的兩個(gè)方括號(hào)進(jìn)行轉(zhuǎn)義匙姜。

// 匹配所有以 "at" 結(jié)尾的 3 個(gè)字符的組合畅厢,不區(qū)分大小寫(xiě)
let pattern3 = /.at/gi; 

// 匹配所有".at",不區(qū)分大小寫(xiě)
let pattern4 = /\.at/gi; 

??上述例子中氮昧,對(duì)于 pattern3 來(lái)說(shuō)框杜,句點(diǎn)表示位于"at"之前的任意一個(gè)可以構(gòu)成匹配項(xiàng)的字符。但如果想匹配".at"郭计,則必須對(duì)句點(diǎn)本身進(jìn)行轉(zhuǎn)義霸琴,如 pattern4 所示。

使用 RegExp 構(gòu)造函數(shù)來(lái)創(chuàng)建正則表達(dá)式

RegExp 構(gòu)造函數(shù)接收 2 個(gè)參數(shù):要匹配的字符串模式昭伸、可選的標(biāo)志字符串梧乘。

可以使用字面量定義的任何表達(dá)式,都可以使用構(gòu)造函數(shù)來(lái)定義。示例:

// 匹配第一個(gè) "bat" 或 "cat"选调,不區(qū)分大小寫(xiě)
let pattern1 = /[bc]at/i; 

// 與 pattern1 相同夹供,只不過(guò)是使用構(gòu)造函數(shù)創(chuàng)建的
let pattern2 = new RegExp("[bc]at", "i");

??要注意的是,傳遞給 RegExp 構(gòu)造函數(shù)的兩個(gè)參數(shù)都是字符串(不能把正則表達(dá)式字面量傳遞給 RegExp 構(gòu)造函數(shù))仁堪。
??由于 RegExp 構(gòu)造函數(shù)的模式參數(shù)是字符串哮洽,所以在某些情況下要對(duì)字符進(jìn)行雙重轉(zhuǎn)義。所有元字符都必須雙重轉(zhuǎn)義弦聂,那些已經(jīng)轉(zhuǎn)義過(guò)的字符也是如此鸟辅。例如:字符\在字符串中通常被轉(zhuǎn)義為\,而在正則表達(dá)式字符串中就會(huì)變成\\莺葫。

字面量模式 等價(jià)的字符串
/\[bc\]at/ "\\[bc\\]at"
/\.at/ "\\.at"
/name\/age/ "name\\/age"
/\d.\d{1,2}/ "\\d.\\d{1,2}"
/\w\\hello\\123/ "\w\\\\hello\\\\123"

4.1匪凉、RegExp 實(shí)例屬性

??RegExp 的每個(gè)實(shí)例都具有下列屬性,通過(guò)這些屬性可以取得有關(guān)模式的各種信息捺檬。

  • global:布爾值再层,表示是否設(shè)置了 g 標(biāo)志。
  • ignoreCase:布爾值堡纬,表示是否設(shè)置了 i 標(biāo)志聂受。
  • lastIndex:整數(shù),表示開(kāi)始搜索下一個(gè)匹配項(xiàng)的字符位置烤镐,從 0 算起蛋济。
  • multiline:布爾值,表示是否設(shè)置了 m 標(biāo)志职车。
  • source:正則表達(dá)式的字符串表示瘫俊,按照字面量形式而非傳入構(gòu)造函數(shù)中的字符串模式返回。

??通過(guò)這些屬性可以獲知一個(gè)正則表達(dá)式的各方面信息悴灵,但卻沒(méi)有多大用處扛芽,因?yàn)檫@些信息全都包含在模式聲明中。例如:

let pattern1 = /\[bc\]at/i;
console.log(pattern1.global); // false
console.log(pattern1.ignoreCase); // true
console.log(pattern1.multiline); // false
console.log(pattern1.lastIndex); // 0
console.log(pattern1.source); // "\[bc\]at"

let pattern2 = new RegExp("\\[bc\\]at", "i");
console.log(pattern2.global); // false
console.log(pattern2.ignoreCase); // true
console.log(pattern2.multiline); // false
console.log(pattern2.lastIndex); // 0
console.log(pattern2.source); // "\[bc\]at" 

4.1积瞒、RegExp 實(shí)例方法

RegExp 對(duì)象的方法:

  • exec()川尖,該方法是專(zhuān)門(mén)為捕獲組而設(shè)計(jì)的;
  • test(),判斷目標(biāo)字符串與某個(gè)模式是否匹配茫孔;
  • toLocaleString()叮喳,返回正則表達(dá)式的字面量;
  • toString()缰贝,返回正則表達(dá)式的字面量馍悟;
  • valueOf(),返回正則表達(dá)式本身剩晴。

exec()方法

??exec() 接受一個(gè)參數(shù)锣咒,即要應(yīng)用模式的字符串侵状,然后返回包含第一個(gè)匹配項(xiàng)信息的數(shù)組;或者在沒(méi)有匹配項(xiàng)的情況下返回 null毅整。
??exec() 返回的數(shù)組雖然是 Array 的實(shí)例趣兄,但包含兩個(gè)額外的屬性:index 和 input。其中悼嫉,index 表示匹配項(xiàng)在字符串中的位置艇潭,而 input 表示應(yīng)用正則表達(dá)式的字符串。
??在數(shù)組中戏蔑,第一項(xiàng)是與整個(gè)模式匹配的字符串蹋凝,其他項(xiàng)是與模式中的捕獲組匹配的字符串(如果模式中沒(méi)有捕獲組,則該數(shù)組只包含一項(xiàng))辛臊。示例:

let text = "mom and dad and baby";
let pattern = /mom( and dad( and baby)?)?/gi;

let matches = pattern.exec(text);
console.log(matches.index); // 0
console.log(matches.input); // "mom and dad and baby"
console.log(matches[0]); // "mom and dad and baby"
console.log(matches[1]); // " and dad and baby"
console.log(matches[2]); // " and baby" 

??對(duì)于 exec() 方法而言仙粱,即使在模式中設(shè)置了全局標(biāo)志(g),它每次也只會(huì)返回一個(gè)匹配項(xiàng)彻舰。在不設(shè)置全局標(biāo)志的情況下,在同一個(gè)字符串上多次調(diào)用 exec() 將始終返回第一個(gè)匹配項(xiàng)的信息候味。而在設(shè)
置全局標(biāo)志的情況下刃唤,每次調(diào)用 exec() 則都會(huì)在字符串中繼續(xù)查找新匹配項(xiàng),示例:

let text = "cat, bat, sat, fat";
let pattern1 = /.at/;

let matches = pattern1.exec(text);
console.log(matches.index); // 0
console.log(matches[0]); // cat
console.log(pattern1.lastIndex); // 0

matches = pattern1.exec(text);
console.log(matches.index); // 0
console.log(matches[0]); // cat
console.log(pattern1.lastIndex); // 0

let pattern2 = /.at/g;

let matches = pattern2.exec(text);
console.log(matches.index); // 0
console.log(matches[0]); // cat
console.log(pattern2.lastIndex); // 3 

matches = pattern2.exec(text);
console.log(matches.index); // 5
console.log(matches[0]); // bat
console.log(pattern2.lastIndex); // 8 

test()方法

??test() 接受一個(gè)字符串參數(shù)白群。在模式與該參數(shù)匹配的情況下返回 true尚胞;否則,返回 false帜慢。
??在只想知道目標(biāo)字符串與某個(gè)模式是否匹配笼裳,但不需要知道其文本內(nèi)容的情況下,使用這個(gè)方法非常方便粱玲。因此躬柬,test()方法經(jīng)常被用在 if 語(yǔ)句中,示例:

let text = "000-00-0000";
let pattern = /\d{3}-\d{2}-\d{4}/;
if (pattern.test(text)){
 console.log("The pattern was matched.");
} 

??在上述例子中抽减,我們使用正則表達(dá)式來(lái)測(cè)試了一個(gè)數(shù)字序列允青。如果輸入的文本與模式匹配,則顯示一條消息卵沉。這種用法經(jīng)常出現(xiàn)在驗(yàn)證用戶(hù)輸入的情況下颠锉,因?yàn)槲覀冎幌胫垒斎胧遣皇怯行В劣谒鼮槭裁礋o(wú)效就無(wú)關(guān)緊要了史汗。

toLocaleString() 和 toString() 方法
??RegExp 實(shí)例繼承的 toLocaleString()和 toString()方法都會(huì)返回正則表達(dá)式的字面量琼掠,與創(chuàng)建正則表達(dá)式的方式無(wú)關(guān)。例如:

let pattern = new RegExp("\\[bc\\]at", "gi");
console.log(pattern.toString()); // /\[bc\]at/gi
console.log(pattern.toLocaleString()); // /\[bc\]at/gi 

valueOf() 方法

正則表達(dá)式的 valueOf()方法返回正則表達(dá)式本身停撞。示例:

let pattern =  /\[bc\]at/gi; 

console.log(pattern.toString()); // /\[bc\]at/gi
console.log(typeof pattern.toString()); // string

console.log(pattern.valueOf()); // /\[bc\]at/gi 
console.log(typeof pattern.valueOf()); // object 

4.3瓷蛙、RegExp 構(gòu)造函數(shù)屬性

??RegExp 構(gòu)造函數(shù)包含一些屬性。這些屬性適用于作用域中的所有正則表達(dá)式,并且基于所執(zhí)行的最近一次正則表達(dá)式操作而變化速挑。關(guān)于這些屬性的另一個(gè)獨(dú)特之處谤牡,就是可以通過(guò)兩種方式訪(fǎng)問(wèn)它們。換句話(huà)說(shuō)姥宝,這些屬性分別有一個(gè)長(zhǎng)屬性名和一個(gè)短屬性名翅萤。

RegExp 構(gòu)造函數(shù)的屬性:

長(zhǎng)屬性名 短屬性名 說(shuō)明
input $_ 最近一次要匹配的字符串
lastMatch $& 最近一次的匹配項(xiàng)
lastParen $+ 最近一次匹配的捕獲組
leftContext $` input字符串中l(wèi)astMatch之前的文本
multiline $* 布爾值,表示是否所有表達(dá)式都使用多行模式
rightContext $' Input字符串中l(wèi)astMatch之后的文本

示例:

let text = "this has been a short summer";
let pattern = /(.)hort/g; 

if (pattern.test(text)){
    console.log(RegExp.input); // this has been a short summer
    console.log(RegExp.leftContext); // this has been a
    console.log(RegExp.rightContext); // summer
    console.log(RegExp.lastMatch); // short
    console.log(RegExp.lastParen); // s
    console.log(RegExp.multiline); // false
} 

??以上代碼創(chuàng)建了一個(gè)模式腊满,匹配任何一個(gè)字符后跟 hort套么,而且把第一個(gè)字符放在了一個(gè)捕獲組中。

RegExp 構(gòu)造函數(shù)的各個(gè)屬性返回了下列值:

  • input 屬性返回了原始字符串碳蛋;
  • leftContext 屬性返回了單詞 short 之前的字符串胚泌;
  • rightContext 屬性返回了 short 之后的字符串;
  • lastMatch 屬性返回最近一次與整個(gè)正則表達(dá)式匹配的字符串肃弟,即short玷室;
  • lastParen 屬性返回最近一次匹配的捕獲組,即例子中的 s笤受。

??例子使用的長(zhǎng)屬性名都可以用相應(yīng)的短屬性名來(lái)代替穷缤。只不過(guò),由于這些短屬性名大都不是有效的 ECMAScript 標(biāo)識(shí)符箩兽,因此必須通過(guò)方括號(hào)語(yǔ)法來(lái)訪(fǎng)問(wèn)它們津肛,示例:

let text = "this has been a short summer";
let pattern = /(.)hort/g; 

if (pattern.test(text)){
    console.log(RegExp.$_); // this has been a short summer
    console.log(RegExp["$`"]); // this has been a
    console.log(RegExp["$'"]); // summer
    console.log(RegExp["$&"]); // short
    console.log(RegExp["$+"]); // s
    console.log(RegExp["$*"]); // false
}

??除了上面介紹的幾個(gè)屬性之外,還有多達(dá) 9 個(gè)用于存儲(chǔ)捕獲組的構(gòu)造函數(shù)屬性汗贫。訪(fǎng)問(wèn)這些屬性的語(yǔ)法是 RegExp.$1身坐、RegExp.$2…RegExp.$9,分別用于存儲(chǔ)第一落包、第二……第九個(gè)匹配的捕獲組部蛇。在調(diào)用 exec() 或 test() 方法時(shí),這些屬性會(huì)被自動(dòng)填充妥色。示例:

let text = "this has been a short summer";
let pattern = /(..)or(.)/g;

if (pattern.test(text)){
    console.log(RegExp.$1); // sh
    console.log(RegExp.$2); // t
} 

??這里創(chuàng)建了一個(gè)包含兩個(gè)捕獲組的模式搪花,并用該模式測(cè)試了一個(gè)字符串。即使 test() 方法只返回一個(gè)布爾值嘹害,但 RegExp 構(gòu)造函數(shù)的屬性 $1 和 $2 也會(huì)被匹配相應(yīng)捕獲組的字符串自動(dòng)填充撮竿。

4.4、模式的局限性

ECMAScript 正則表達(dá)式不支持的特性:

  • 匹配字符串開(kāi)始和結(jié)尾的\A 和\Z 錨(但支持以插入符號(hào)(^)和美元符號(hào)($)來(lái)匹配字符串的開(kāi)始和結(jié)尾)
  • 向后查找(lookbehind)(但完全支持向前查找(lookahead))
  • 并集和交集類(lèi)
  • 原子組(atomic grouping)
  • Unicode 支持(單個(gè)字符除外笔呀,如\uFFFF)
  • 命名的捕獲組(但支持編號(hào)的捕獲組)
  • s(single幢踏,單行)和 x(free-spacing,無(wú)間隔)匹配模式
  • 條件匹配
  • 正則表達(dá)式注釋

5许师、Function 類(lèi)型

??每個(gè)函數(shù)都是 Function 類(lèi)型的實(shí)例房蝉,而且都與其他引用類(lèi)型一樣具有屬性和方法僚匆。由于函數(shù)是對(duì)象,因此函數(shù)名實(shí)際上也是一個(gè)指向函數(shù)對(duì)象的指針搭幻,不會(huì)與某個(gè)函數(shù)綁定咧擂。

定義函數(shù):

  • 使用函數(shù)聲明語(yǔ)法定義;
  • 定義變量并將其初始化為一個(gè)函數(shù)檀蹋;
  • 使用 Function 構(gòu)造函數(shù)松申。
function sum (num1, num2) {
    return num1 + num2;
} 

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

let sum = new Function("num1", "num2", "return num1 + num2"); // 不推薦

??上述第二個(gè)例子,定義了變量 sum 并將其初始化為一個(gè)函數(shù)俯逾。function 關(guān)鍵字后面沒(méi)有函數(shù)名贸桶,這是因?yàn)樵谑褂煤瘮?shù)表達(dá)式定義函數(shù)時(shí),沒(méi)有必要使用函數(shù)名——通過(guò)變量 sum 即可以引用函數(shù)桌肴。另外皇筛,還要注意函數(shù)末尾有一個(gè)分號(hào),就像聲明其他變量時(shí)一樣坠七。
??上述第三個(gè)例子水醋,從技術(shù)角度講,這是一個(gè)函數(shù)表達(dá)式彪置。但是离例,我們不推薦讀者使用這種方法定義函數(shù),因?yàn)檫@種語(yǔ)法會(huì)導(dǎo)致解析兩次代碼(第一次是解析常規(guī) ECMAScript 代碼悉稠,第二次是解析傳入構(gòu)造函數(shù)中的字符串),從而影響性能艘包。不過(guò)的猛,這種語(yǔ)法對(duì)于理解“函數(shù)是對(duì)象,函數(shù)名是指針”的概念倒是非常直觀(guān)的想虎。

??由于函數(shù)名僅僅是指向函數(shù)的指針卦尊,因此函數(shù)名與包含對(duì)象指針的其他變量沒(méi)有什么不同。換句話(huà)說(shuō)舌厨,一個(gè)函數(shù)可能會(huì)有多個(gè)名字岂却,示例:

function sum(num1, num2){
    return num1 + num2;
}
console.log(sum(10,10)); // 20

let anotherSum = sum;
console.log(anotherSum(10, 10)); // 20

sum = null;
console.log(anotherSum(10, 10)); // 20 

??以上代碼首先定義了一個(gè)名為 sum()的函數(shù),用于求兩個(gè)值的和裙椭。然后躏哩,又聲明了變量 anotherSum,并將其設(shè)置為與 sum 相等(將 sum 的值賦給 anotherSum)揉燃。此時(shí)扫尺,anotherSum 和 sum 就都指向了同一個(gè)函數(shù),因此 anotherSum()也可以被調(diào)用并返回結(jié)果炊汤。即使將 sum 設(shè)置為 null正驻,讓它與函數(shù)“斷絕關(guān)系”弊攘,但仍然可以正常調(diào)用anotherSum()。

注意姑曙,使用不帶圓括號(hào)的函數(shù)名是訪(fǎng)問(wèn)函數(shù)指針襟交,而非調(diào)用函數(shù)。

5.1伤靠、沒(méi)有重載(深入理解)

??將函數(shù)名想象為指針捣域,也有助于理解為什么 ECMAScript 中沒(méi)有函數(shù)重載的概念。

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

// 等價(jià)于

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

??聲明了兩個(gè)同名函數(shù)醋界,而結(jié)果則是后面的函數(shù)覆蓋了前面的函數(shù)竟宋。通過(guò)觀(guān)察重寫(xiě)之后的代碼,很容易看清楚到底是怎么回事兒——在創(chuàng)建第二個(gè)函數(shù)時(shí)形纺,實(shí)際上覆蓋了引用第一個(gè)函數(shù)的變量 addSomeNumber丘侠。

5.2、函數(shù)聲明與函數(shù)表達(dá)式

??解析器在向執(zhí)行環(huán)境中加載數(shù)據(jù)時(shí)逐样,對(duì)函數(shù)聲明和函數(shù)表達(dá)式并非一視同仁蜗字。解析器會(huì)率先讀取函數(shù)聲明,并使其在執(zhí)行任何代碼之前可用(可以訪(fǎng)問(wèn))脂新;至于函數(shù)表達(dá)式挪捕,則必須等到解析器執(zhí)行到它所在的代碼行智厌,才會(huì)真正被解釋執(zhí)行套鹅。示例:

console.log(sum(10,10));
function sum(num1, num2){
    return num1 + num2;
} 

??以上代碼可以正常運(yùn)行仓犬。因?yàn)樵诖a開(kāi)始執(zhí)行之前偶摔,解析器就已經(jīng)通過(guò)一個(gè)名為函數(shù)聲明提升(function declaration hoisting)的過(guò)程卒密,讀取并將函數(shù)聲明添加到執(zhí)行環(huán)境中旨椒。對(duì)代碼求值時(shí)腌乡,JavaScript 引擎在第一遍會(huì)聲明函數(shù)并將它們放到源代碼樹(shù)的頂部盛龄。所以斩启,即使聲明函數(shù)的代碼在調(diào)用它的代碼后面序调,JavaScript 引擎也能把函數(shù)聲明提升到頂部。

console.log(sum(10,10));
let sum = function(num1, num2){
    return num1 + num2;
}; 

??以上代碼會(huì)在運(yùn)行期間產(chǎn)生錯(cuò)誤兔簇,原因在于函數(shù)位于一個(gè)初始化語(yǔ)句中发绢,而不是一個(gè)函數(shù)聲明。換句話(huà)說(shuō)垄琐,在執(zhí)行到函數(shù)所在的語(yǔ)句之前边酒,變量 sum 中不會(huì)保存有對(duì)函數(shù)的引用;而且此虑,由于第一行代碼就會(huì)導(dǎo)致 “unexpected identifier”(意外標(biāo)識(shí)符)錯(cuò)誤甚纲,實(shí)際上也不會(huì)執(zhí)行到下一行。

??除了什么時(shí)候可以通過(guò)變量訪(fǎng)問(wèn)函數(shù)這一點(diǎn)區(qū)別之外朦前,函數(shù)聲明與函數(shù)表達(dá)式的語(yǔ)法其實(shí)是等價(jià)的介杆。

5.3鹃操、作為值的函數(shù)

??因?yàn)?ECMAScript 中的函數(shù)名本身就是變量,所以函數(shù)也可以作為值來(lái)使用春哨。也就是說(shuō)荆隘,不僅可以像傳遞參數(shù)一樣把一個(gè)函數(shù)傳遞給另一個(gè)函數(shù),而且可以將一個(gè)函數(shù)作為另一個(gè)函數(shù)的結(jié)果返回赴背。

將函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù)

function callSomeFunction(someFunction, someArgument){
    return someFunction(someArgument);
} 

??這個(gè)函數(shù)接受兩個(gè)參數(shù)椰拒。第一個(gè)參數(shù)應(yīng)該是一個(gè)函數(shù),第二個(gè)參數(shù)應(yīng)該是要傳遞給該函數(shù)的一個(gè)值凰荚。
示例:

function add10(num){
    return num + 10;
}
let result1 = callSomeFunction(add10, 10);

console.log(result1); // 20

function getGreeting(name){
    return "Hello, " + name;
}
let result2 = callSomeFunction(getGreeting, "Nicholas");

console.log(result2); // "Hello, Nicholas" 

??這里的 callSomeFunction() 函數(shù)是通用的燃观,即無(wú)論第一個(gè)參數(shù)中傳遞進(jìn)來(lái)的是什么函數(shù),它都會(huì)返回執(zhí)行第一個(gè)參數(shù)后的結(jié)果便瑟。
??要訪(fǎng)問(wèn)函數(shù)的指針而不執(zhí)行函數(shù)的話(huà)缆毁,必須去掉函數(shù)名后面的那對(duì)圓括號(hào)。因此上面例子中傳遞給 callSomeFunction() 的是 add10 和 getGreeting到涂,而不是執(zhí)行它們之后的結(jié)果脊框。

將函數(shù)作為另一個(gè)函數(shù)的結(jié)果返回
??可以從一個(gè)函數(shù)中返回另一個(gè)函數(shù),而且這也是極為有用的一種技術(shù)践啄。例如浇雹,假設(shè)有一個(gè)對(duì)象數(shù)組,我們想要根據(jù)某個(gè)對(duì)象屬性對(duì)數(shù)組進(jìn)行排序屿讽。而傳遞給數(shù)組 sort() 方法的比較函數(shù)要接收兩個(gè)參數(shù)昭灵,即要比較的值》ヌ福可是虎锚,我們需要一種方式來(lái)指明按照哪個(gè)屬性來(lái)排序。要解決這個(gè)問(wèn)題衩婚,可以定義一個(gè)函數(shù),它接收一個(gè)屬性名效斑,然后根據(jù)這個(gè)屬性名來(lái)創(chuàng)建一個(gè)比較函數(shù)非春。示例:

function createComparisonFunction(propertyName) {
    return function(object1, object2){
        let value1 = object1[propertyName];
        let value2 = object2[propertyName];

        if (value1 < value2){
            return -1;
        } else if (value1 > value2){
            return 1;
        } else {
            return 0;
        }
    };
} 

// 具體使用實(shí)例:
let data = [{name: "Zachary", age: 28}, {name: "Nicholas", age: 29}];

data.sort(createComparisonFunction("name"));
console.log(data[0].name); // Nicholas

data.sort(createComparisonFunction("age"));
console.log(data[0].name); // Zachary 

5.4、函數(shù)內(nèi)部屬性

在函數(shù)內(nèi)部缓屠,有兩個(gè)特殊的對(duì)象:

  • arguments
  • this

??arguments 是一個(gè)類(lèi)數(shù)組對(duì)象奇昙,包含著傳入函數(shù)中的所有參數(shù)。雖然 arguments 的主要用途是保存函數(shù)參數(shù)敌完,但這個(gè)對(duì)象還有一個(gè)名叫 callee 的屬性储耐,該屬性是一個(gè)指針,指向擁有這個(gè) arguments 對(duì)象的函數(shù)滨溉。示例:

// 階乘函數(shù) 
function factorial(num){
    if (num <=1) {
        return 1;
    } else {
        return num * factorial(num-1)
    }
} 

??定義階乘函數(shù)一般都要用到遞歸算法什湘;如上面的代碼所示长赞,在函數(shù)有名字,而且名字以后也不會(huì)變的情況下闽撤,這樣定義沒(méi)有問(wèn)題得哆。但問(wèn)題是這個(gè)函數(shù)的執(zhí)行與函數(shù)名 factorial 緊緊耦合在了一起。為了消除這種緊密耦合的現(xiàn)象哟旗,可以像下面這樣使用 arguments.callee贩据。

function factorial(num){
    if (num <=1) {
        return 1;
    } else {
        return num * arguments.callee(num-1)
    }
} 

??在這個(gè)重寫(xiě)后的 factorial()函數(shù)的函數(shù)體內(nèi),沒(méi)有再引用函數(shù)名 factorial闸餐。這樣饱亮,無(wú)論引用函數(shù)時(shí)使用的是什么名字,都可以保證正常完成遞歸調(diào)用舍沙。示例:

let trueFactorial = factorial;
factorial = function(){
    return 0;
};
console.log(trueFactorial(5)); // 120
console.log(factorial(5)); // 0 

??在此近上,變量 trueFactorial 獲得了 factorial 的值,實(shí)際上是在另一個(gè)位置上保存了一個(gè)函數(shù)的指針场勤。然后戈锻,我們又將一個(gè)簡(jiǎn)單地返回 0 的函數(shù)賦值給 factorial 變量。如果像原來(lái)的 factorial() 那樣不使用 arguments.callee和媳,調(diào)用 trueFactorial() 就會(huì)返回 0格遭。可是留瞳,在解除了函數(shù)體內(nèi)的代碼與函數(shù)名的耦合狀態(tài)之后拒迅,trueFactorial() 仍然能夠正常地計(jì)算階乘;至于 factorial()她倘,它現(xiàn)在只是一個(gè)返回 0 的函數(shù)璧微。

注意:嚴(yán)格模式下,訪(fǎng)問(wèn) arguments.callee 會(huì)導(dǎo)致錯(cuò)誤硬梁。

??this 引用的是函數(shù)據(jù)以執(zhí)行的環(huán)境對(duì)象——或者也可以說(shuō)是 this 值(當(dāng)在網(wǎng)頁(yè)的全局作用域中調(diào)用函數(shù)時(shí)前硫,this 對(duì)象引用的就是 window)。示例:

window.color = "red";
let o = { color: "blue" };
function sayColor(){
    console.log(this.color);
}

sayColor(); // "red"

o.sayColor = sayColor;
o.sayColor(); // "blue" 

??上面這個(gè)函數(shù) sayColor() 是在全局作用域中定義的荧止,它引用了 this 對(duì)象屹电。由于在調(diào)用函數(shù)之前,this 的值并不確定跃巡,因此 this 可能會(huì)在代碼執(zhí)行過(guò)程中引用不同的對(duì)象危号。當(dāng)在全局作用域中調(diào)用 sayColor() 時(shí),this 引用的是全局對(duì)象 window素邪;換句話(huà)說(shuō)外莲,對(duì) this.color 求值會(huì)轉(zhuǎn)換成對(duì) window.color 求值,于是結(jié)果就返回了 "red"兔朦。而當(dāng)把這個(gè)函數(shù)賦給對(duì)象 o 并調(diào)用 o.sayColor() 時(shí)偷线,this 引用的是對(duì)象 o磨确,因此對(duì) this.color 求值會(huì)轉(zhuǎn)換成對(duì) o.color 求值,結(jié)果就返回了 "blue"淋昭。

注意:函數(shù)的名字僅僅是一個(gè)包含指針的變量而已俐填。因此,即使是在不同的環(huán)境中執(zhí)行翔忽,全局的 sayColor() 函數(shù)與 o.sayColor() 指向的仍然是同一個(gè)函數(shù)英融。

??caller 是函數(shù)對(duì)象的屬性,這個(gè)屬性中保存著調(diào)用當(dāng)前函數(shù)的函數(shù)的引用歇式,如果是在全局作用域中調(diào)用當(dāng)前函數(shù)驶悟,它的值為 null。示例:

function outer(){
    inner();
}
function inner(){
    console.log(inner.caller);
}
outer(); 

??以上代碼會(huì)打印 outer() 函數(shù)的源代碼材失。因?yàn)?outer()調(diào)用了 inter()痕鳍,所以 inner.caller 就指向 outer()。
??為了實(shí)現(xiàn)更松散的耦合龙巨,也可以通過(guò) arguments.callee.caller 來(lái)訪(fǎng)問(wèn)相同的信息笼呆。示例:

function outer(){
    inner();
}
function inner(){
    console.log(arguments.callee.caller);
}
outer(); 

??arguments 也有一個(gè) arguments.caller 屬性,這個(gè)屬性始終返回 undefined旨别。定義這個(gè)屬性是為了分清 arguments.caller 和函數(shù)的 caller 屬性诗赌。以上變化都是為了加強(qiáng)這門(mén)語(yǔ)言的安全性,這樣第三方代碼就不能在相同的環(huán)境里窺視其他代碼了秸弛。

5.5铭若、函數(shù)屬性和方法

??ECMAScript 中的函數(shù)是對(duì)象,因此函數(shù)也有屬性和方法递览。每個(gè)函數(shù)都包含兩個(gè)屬性:length 和 prototype叼屠。

??length 屬性表示函數(shù)希望接收的命名參數(shù)的個(gè)數(shù)。示例:

function sayName(name){
    console.log(name);
}
function sum(num1, num2){
    return num1 + num2;
}
function sayHi(){
    console.log("hi");
}
console.log(sayName.length); // 1
console.log(sum.length); // 2
console.log(sayHi.length); // 0 

??對(duì)于 ECMAScript 中的引用類(lèi)型而言绞铃,prototype 是保存它們所有實(shí)例方法的真正所在镜雨。換句話(huà)說(shuō),諸如 toString() 和 valueOf() 等方法實(shí)際上都保存在 prototype 名下儿捧,只不過(guò)是通過(guò)各自對(duì)象的實(shí)例訪(fǎng)問(wèn)罷了冷离。

??每個(gè)函數(shù)都包含兩個(gè)非繼承而來(lái)的方法:apply() 和 call()。這兩個(gè)方法的用途都是在特定的作用域中調(diào)用函數(shù)纯命,實(shí)際上等于設(shè)置函數(shù)體內(nèi) this 對(duì)象的值。

??apply() 方法接收兩個(gè)參數(shù):一個(gè)是在其中運(yùn)行函數(shù)的作用域痹栖,另一個(gè)是參數(shù)數(shù)組亿汞。其中,第二個(gè)參數(shù)可以是 Array 的實(shí)例揪阿,也可以是 arguments 對(duì)象疗我。示例:

function sum(num1, num2){
    return num1 + num2;
}
function callSum1(num1, num2){
    return sum.apply(this, arguments); // 傳入 arguments 對(duì)象
}
function callSum2(num1, num2){
    return sum.apply(this, [num1, num2]); // 傳入數(shù)組
}
console.log(callSum1(10, 10)); //20
console.log(callSum2(10, 10)); //20 

??在上面這個(gè)例子中咆畏,callSum1() 在執(zhí)行 sum()函數(shù)時(shí)傳入了 this 作為 this 值(因?yàn)槭窃谌肿饔糜蛑姓{(diào)用的,所以傳入的就是 window 對(duì)象)和 arguments 對(duì)象吴裤。而 callSum2 同樣也調(diào)用了 sum() 函數(shù)旧找,但它傳入的則是 this 和一個(gè)參數(shù)數(shù)組。這兩個(gè)函數(shù)都會(huì)正常執(zhí)行并返回正確的結(jié)果麦牺。

??call() 方法與 apply() 方法的作用相同钮蛛,它們的區(qū)別僅在于接收參數(shù)的方式不同。對(duì)于 call() 方法而言剖膳,第一個(gè)參數(shù)是 this 值沒(méi)有變化魏颓,變化的是其余參數(shù)都直接傳遞給函數(shù)。換句話(huà)說(shuō)吱晒,在使用 call() 方法時(shí)甸饱,傳遞給函數(shù)的參數(shù)必須逐個(gè)列舉出來(lái),示例:

function sum(num1, num2){
    return num1 + num2;
}
function callSum(num1, num2){
    return sum.call(this, num1, num2);
}
console.log(callSum(10, 10)); // 20 

??在使用 call() 方法的情況下仑濒,callSum() 必須明確地傳入每一個(gè)參數(shù)叹话。結(jié)果與使用 apply() 沒(méi)有什么不同。
??至于是使用 apply() 還是 call()墩瞳,完全取決于你采取哪種給函數(shù)傳遞參數(shù)的方式最方便驼壶。如果你打算直接傳入 arguments 對(duì)象,或者包含函數(shù)中先接收到的也是一個(gè)數(shù)組矗烛,那么使用 apply() 肯定更方便辅柴;否則,選擇 call() 可能更合適瞭吃。(在不給函數(shù)傳遞參數(shù)的情況下碌嘀,使用哪個(gè)方法都無(wú)所謂。)

??事實(shí)上歪架,傳遞參數(shù)并非 apply() 和 call() 真正的用武之地股冗;它們真正強(qiáng)大的地方是能夠擴(kuò)充函數(shù)賴(lài)以運(yùn)行的作用域。示例:

window.color = "red";
let o = { color: "blue" };
function sayColor(){
    console.log(this.color);
}
sayColor(); // red
sayColor.call(this); // red
sayColor.call(window); // red
sayColor.call(o); // blue 

??sayColor() 是作為全局函數(shù)定義的和蚪,當(dāng)在全局作用域中調(diào)用它時(shí)止状,它確實(shí)會(huì)顯示 "red"——因?yàn)閷?duì) this.color 的求值會(huì)轉(zhuǎn)換成對(duì) window.color 的求值。
??而 sayColor.call(this) 和 sayColor.call(window)攒霹,則是兩種顯式地在全局作用域中調(diào)用函數(shù)的方式怯疤,結(jié)果當(dāng)然都會(huì)顯示 "red"。但是催束,當(dāng)運(yùn)行 sayColor.call(o) 時(shí)集峦,函數(shù)的執(zhí)行環(huán)境就不一樣了,因?yàn)榇藭r(shí)函數(shù)體內(nèi)的 this 對(duì)象指向了 o,于是結(jié)果顯示的是 "blue"塔淤。

??使用 call() 或 apply() 來(lái)擴(kuò)充作用域的最大好處摘昌,就是對(duì)象不需要與方法有任何耦合關(guān)系。在前面例子的第一個(gè)版本中高蜂,我們是先將 sayColor() 函數(shù)放到了對(duì)象 o 中聪黎,然后再通過(guò) o 來(lái)調(diào)用它的;而在這里重寫(xiě)的例子中备恤,就不需要先前那個(gè)多余的步驟了稿饰。

??bind() 方法會(huì)創(chuàng)建一個(gè)函數(shù)的實(shí)例,其 this 值會(huì)被綁定到傳給 bind() 函數(shù)的值烘跺。示例:

window.color = "red";
let o = { color: "blue" };
function sayColor(){
    console.log(this.color);
}
let objectSayColor = sayColor.bind(o);
objectSayColor(); // blue 

??在這里湘纵,sayColor() 調(diào)用 bind() 并傳入對(duì)象 o,創(chuàng)建了 objectSayColor() 函數(shù)滤淳。objectSayColor() 函數(shù)的 this 值等于 o梧喷,因此即使是在全局作用域中調(diào)用這個(gè)函數(shù),也會(huì)看到 "blue"脖咐。

??每個(gè)函數(shù)繼承的 toLocaleString() 和 toString() 方法始終都返回函數(shù)的代碼铺敌。返回代碼的格式則因?yàn)g覽器而異 —— 有的返回的代碼與源代碼中的函數(shù)代碼一樣,而有的則返回函數(shù)代碼的內(nèi)部表示屁擅,即由解析器刪除了注釋并對(duì)某些代碼作了改動(dòng)后的代碼偿凭。由于存在這些差異,我們無(wú)法根據(jù)這兩個(gè)方法返回的結(jié)果來(lái)實(shí)現(xiàn)任何重要功能派歌;不過(guò)弯囊,這些信息在調(diào)試代碼時(shí)倒是很有用。另外一個(gè)繼承的 valueOf() 方法同樣也只返回函數(shù)代碼胶果。

6匾嘱、基本包裝類(lèi)型

??為了便于操作基本類(lèi)型值,ECMAScript 還提供了 3 個(gè)特殊的引用類(lèi)型:Boolean早抠、Number 和 String霎烙。這些類(lèi)型與本章介紹的其他引用類(lèi)型相似,但同時(shí)也具有與各自的基本類(lèi)型相應(yīng)的特殊行為蕊连。實(shí)際上悬垃,每當(dāng)讀取一個(gè)基本類(lèi)型值的時(shí)候,后臺(tái)就會(huì)創(chuàng)建一個(gè)對(duì)應(yīng)的基本包裝類(lèi)型的對(duì)象甘苍,從而讓我們能夠調(diào)用一些方法來(lái)操作這些數(shù)據(jù)尝蠕。示例:

let s1 = "some text";
let s2 = s1.substring(2); 

??這個(gè)例子中的變量 s1 包含一個(gè)字符串,字符串當(dāng)然是基本類(lèi)型值载庭。而下一行調(diào)用了 s1 的 substring()方法看彼,并將返回的結(jié)果保存在了 s2 中扇谣。我們知道,基本類(lèi)型值不是對(duì)象闲昭,因而從邏輯上講它們不應(yīng)該有方法。
??其實(shí)靡挥,為了讓我們實(shí)現(xiàn)這種直觀(guān)的操作序矩,后臺(tái)已經(jīng)自動(dòng)完成了一系列的處理。當(dāng)?shù)诙写a訪(fǎng)問(wèn) s1 時(shí)跋破,訪(fǎng)問(wèn)過(guò)程處于一種讀取模式簸淀,也就是要從內(nèi)存中讀取這個(gè)字符串的值。而在讀取模式中訪(fǎng)問(wèn)字符串時(shí)毒返,后臺(tái)都會(huì)自動(dòng)完成下列處理:

  1. 創(chuàng)建 String 類(lèi)型的一個(gè)實(shí)例租幕;
  2. 在實(shí)例上調(diào)用指定的方法;
  3. 銷(xiāo)毀這個(gè)實(shí)例拧簸。

??可以將以上三個(gè)步驟想象成是執(zhí)行了下列 ECMAScript 代碼劲绪。

let s1 = new String("some text");
let s2 = s1.substring(2);
s1 = null; 

??經(jīng)過(guò)此番處理,基本的字符串值就變得跟對(duì)象一樣了盆赤。而且贾富,上面這三個(gè)步驟也分別適用于 Boolean 和 Number 類(lèi)型對(duì)應(yīng)的布爾值和數(shù)字值。

??引用類(lèi)型與基本包裝類(lèi)型的主要區(qū)別就是對(duì)象的生存期牺六。使用 new 操作符創(chuàng)建的引用類(lèi)型的實(shí)例颤枪,在執(zhí)行流離開(kāi)當(dāng)前作用域之前都一直保存在內(nèi)存中。而自動(dòng)創(chuàng)建的基本包裝類(lèi)型的對(duì)象淑际,則只存在于一行代碼的執(zhí)行瞬間畏纲,然后立即被銷(xiāo)毀。這意味著我們不能在運(yùn)行時(shí)為基本類(lèi)型值添加屬性和方法春缕。示例:

let s1 = "some text";
s1.color = "red";
console.log(s1.color); // undefined 

??在此盗胀,第二行代碼試圖為字符串 s1 添加一個(gè) color 屬性。但是淡溯,當(dāng)?shù)谌写a再次訪(fǎng)問(wèn) s1 時(shí)读整,其 color 屬性不見(jiàn)了。問(wèn)題的原因就是第二行創(chuàng)建的 String 對(duì)象在執(zhí)行第三行代碼時(shí)已經(jīng)被銷(xiāo)毀了咱娶。第三行代碼又創(chuàng)建自己的 String 對(duì)象米间,而該對(duì)象沒(méi)有 color 屬性。

??當(dāng)然膘侮,可以顯式地調(diào)用 Boolean屈糊、Number 和 String 來(lái)創(chuàng)建基本包裝類(lèi)型的對(duì)象。不過(guò)琼了,應(yīng)該在絕對(duì)必要的情況下再這樣做逻锐,因?yàn)檫@種做法很容易讓人分不清自己是在處理基本類(lèi)型還是引用類(lèi)型的值夫晌。

??對(duì)基本包裝類(lèi)型的實(shí)例調(diào)用 typeof 會(huì)返回 "object",而且所有基本包裝類(lèi)型的對(duì)象都會(huì)被轉(zhuǎn)換為布爾值 true昧诱。

??Object 構(gòu)造函數(shù)也會(huì)像工廠(chǎng)方法一樣晓淀,根據(jù)傳入值的類(lèi)型返回相應(yīng)基本包裝類(lèi)型的實(shí)例。示例:

let obj = new Object("some text");
console.log(obj instanceof String); // true 

??把字符串傳給 Object 構(gòu)造函數(shù)盏档,就會(huì)創(chuàng)建 String 的實(shí)例凶掰;而傳入數(shù)值參數(shù)會(huì)得到 Number 的實(shí)]例,傳入布爾值參數(shù)就會(huì)得到 Boolean 的實(shí)例蜈亩。

??要注意的是懦窘,使用 new 調(diào)用基本包裝類(lèi)型的構(gòu)造函數(shù),與直接調(diào)用同名的轉(zhuǎn)型函數(shù)是不一樣的稚配。示例:

let value = "25";
let number = Number(value); // 轉(zhuǎn)型函數(shù)
console.log(typeof number); // "number"
let obj = new Number(value); // 構(gòu)造函數(shù)
console.log(typeof obj); // "object" 

??在這個(gè)例子中畅涂,變量 number 中保存的是基本類(lèi)型的值 25树酪,而變量 obj 中保存的是 Number 的實(shí)例闪水。

??盡管我們不建議顯式地創(chuàng)建基本包裝類(lèi)型的對(duì)象,但它們操作基本類(lèi)型值的能力還是相當(dāng)重要的眷篇。而每個(gè)基本包裝類(lèi)型都提供了操作相應(yīng)值的便捷方法愤惰。

6.1苇经、Boolean 類(lèi)型

??Boolean 類(lèi)型是與布爾值對(duì)應(yīng)的引用類(lèi)型。要?jiǎng)?chuàng)建 Boolean 對(duì)象宦言,可以像下面這樣調(diào)用 Boolean 構(gòu)造函數(shù)并傳入 true 或 false 值扇单。示例:

let booleanObject = new Boolean(true); 

Boolean 類(lèi)型的實(shí)例

  • 重寫(xiě)了 valueOf() 方法,返回基本類(lèi)型值 true 或 false奠旺;
  • 重寫(xiě)了 toString() 方法蜘澜,返回字符串 "true" 和 "false";
  • 重寫(xiě)了 toLocaleString() 方法响疚,返回字符串 "true" 和 "false"鄙信。
let BooleanFalse= new Boolean(true); 

console.log(BooleanFalse.valueOf()); // false
console.log(typeof BooleanFalse.valueOf()); // boolean

console.log(BooleanFalse.toString()); // false
console.log(typeof BooleanFalse.toString()); // string

console.log(BooleanFalse.toLocaleString()); // false
console.log(typeof BooleanFalse.toLocaleString()); // string

??Boolean 對(duì)象在 ECMAScript 中的用處不大,因?yàn)樗?jīng)常會(huì)造成人們的誤解忿晕。其中最常見(jiàn)的問(wèn)題就是在布爾表達(dá)式中使用 Boolean 對(duì)象装诡,例如:

let falseObject = new Boolean(false);
let result = falseObject && true;
console.log(result); // true
let falseValue = false;
result = falseValue && true;
console.log(result); // false 

??在這個(gè)例子中,我們使用 false 值創(chuàng)建了一個(gè) Boolean 對(duì)象践盼。然后鸦采,將這個(gè)對(duì)象與基本類(lèi)型值 true 構(gòu)成了邏輯與表達(dá)式。在布爾運(yùn)算中咕幻,false && true 等于 false渔伯。可是肄程,示例中的這行代碼是對(duì) falseObject 而不是對(duì)它的值(false)進(jìn)行求值锣吼。前面討論過(guò)选浑,布爾表達(dá)式中的所有對(duì)象都會(huì)被轉(zhuǎn)換為 true,因此 falseObject 對(duì)象在布爾表達(dá)式中代表的是 true玄叠。結(jié)果古徒,true && true 當(dāng)然就等于 true 了。

??基本類(lèi)型與引用類(lèi)型的布爾值還有兩個(gè)區(qū)別:

  • typeof 操作符對(duì)基本類(lèi)型返回 "boolean"读恃,而對(duì)引用類(lèi)型返回 "object"描函。
  • 由于 Boolean 對(duì)象是 Boolean 類(lèi)型的實(shí)例,所以使用 instanceof 操作符測(cè)試 Boolean 對(duì)象會(huì)返回 true狐粱,而測(cè)試基本類(lèi)型的布爾值則返回 false。

示例:

let falseObject = new Boolean(false);
let falseValue = false;

console.log(typeof falseObject); // object
console.log(typeof falseValue); // boolean

console.log(falseObject instanceof Boolean); // true
console.log(falseValue instanceof Boolean); // false 

建議:永遠(yuǎn)不要使用 Boolean 對(duì)象胆数。

6.2肌蜻、Number 類(lèi)型

??Number 是與數(shù)字值對(duì)應(yīng)的引用類(lèi)型。要?jiǎng)?chuàng)建 Number 對(duì)象必尼,可以在調(diào)用 Number 構(gòu)造函數(shù)時(shí)向其中傳遞相應(yīng)的數(shù)值蒋搜。示例:

let numberObject = new Number(10); 

Number 類(lèi)型的實(shí)例:

  • 重寫(xiě)了 valueOf() 方法,返回對(duì)象表示的基本類(lèi)型的數(shù)值判莉;
  • 重寫(xiě)了 toString() 方法豆挽,返回字符串形式的數(shù)值;
  • 重寫(xiě)了 toLocaleString() 方法券盅,返回字符串形式的數(shù)值帮哈。
let num = new Number(10); 

console.log(num.valueOf()); // 10
console.log(typeof num.valueOf()); // number

console.log(num.toString()); // 10
console.log(typeof num.toString()); // string

console.log(num.toLocaleString()); // 10
console.log(typeof num.toLocaleString()); // string

??可以為 toString()方法傳遞一個(gè)表示基數(shù)的參數(shù),告訴它返回幾進(jìn)制
數(shù)值的字符串形式锰镀。示例:

let num = 10;
console.log(num.toString()); // "10"
console.log(num.toString(2)); // "1010"
console.log(num.toString(8)); // "12"
console.log(num.toString(10)); // "10"
console.log(num.toString(16)); // "a" 

??除了繼承的方法之外娘侍,Number 類(lèi)型還提供了一些用于將數(shù)值格式化為字符串的方法:

  • toFixed():會(huì)按照指定的小數(shù)位返回?cái)?shù)值的字符串表示。
  • toExponential():返回以指數(shù)表示法(也稱(chēng) e 表示法)表示的數(shù)值的字符串形式泳炉。
  • toPrecision():返回表示某個(gè)數(shù)值的最合適的格式憾筏。

toFixed()

let num = 10;
console.log(num.toFixed(2)); // "10.00" 

??這里給 toFixed() 方法傳入了數(shù)值 2,意思是顯示幾位小數(shù)花鹅。于是氧腰,這個(gè)方法返回了 "10.00",即以 0 填補(bǔ)了必要的小數(shù)位刨肃。如果數(shù)值本身包含的小數(shù)位比指定的還多古拴,那么接近指定的最大小數(shù)位的值就會(huì)舍入。示例:

let num = 10.005;
console.log(num.toFixed(2)); // "10.01" 

??能夠自動(dòng)舍入的特性之景,使得 toFixed()方法很適合處理貨幣值斤富。

toExponential()

??toExponential() 接收一個(gè)參數(shù),該參數(shù)指定輸出結(jié)果中的小數(shù)位數(shù)锻狗。示例:

let num = 10;
console.log(num.toExponential(1)); // "1.0e+1" 

toPrecision()

??對(duì)于一個(gè)數(shù)值來(lái)說(shuō)满力,toPrecision() 方法可能會(huì)返回固定大谢啦巍(fixed)格式,也可能返回指數(shù)(exponential)格式油额;具體規(guī)則是看哪種格式最合適叠纷。
??toPrecision() 方法接收一個(gè)參數(shù),即表示數(shù)值的所有數(shù)字的位數(shù)(不包括指數(shù)部分)潦嘶。示例:

let num = 99;
console.log(num.toPrecision(1)); // "1e+2"
console.log(num.toPrecision(2)); // "99"
console.log(num.toPrecision(3)); // "99.0" 

??toPrecision() 會(huì)根據(jù)要處理的數(shù)值決定到底是調(diào)用 toFixed() 還是調(diào)用toExponential()涩嚣。而這三個(gè)方法都可以通過(guò)向上或向下舍入,做到以最準(zhǔn)確的形式來(lái)表示帶有正確小數(shù)位的值掂僵。

??在使用 typeof 操作符測(cè)試基本類(lèi)型數(shù)值時(shí)航厚,始終會(huì)返回 "number",而在測(cè)試 Number 對(duì)象時(shí)锰蓬,則會(huì)返回 "object"幔睬。類(lèi)似地,Number 對(duì)象是 Number 類(lèi)型的實(shí)例芹扭,而基本類(lèi)型的數(shù)值則不是麻顶。

let numberObject = new Number(10);
let numberValue = 10;
console.log(typeof numberObject); // "object"
console.log(typeof numberValue); // "number"
console.log(numberObject instanceof Number); // true
console.log(numberValue instanceof Number); // false 

6.3、String 類(lèi)型

??**String 類(lèi)型是字符串對(duì)應(yīng)的引用類(lèi)型舱卡。示例:

let stringObject = new String("hello world"); 

String 類(lèi)型的實(shí)例:

  • 重寫(xiě)了 valueOf() 方法辅肾,返回對(duì)象所表示的基本字符串值;
  • 重寫(xiě)了 toString() 方法轮锥,返回對(duì)象所表示的基本字符串值矫钓;
  • 重寫(xiě)了 toLocaleString() 方法,返回對(duì)象所表示的基本字符串值舍杜。
let str = new String('hello world'); 

console.log(str.valueOf()); // "hello world"
console.log(typeof str.valueOf()); // string

console.log(str.toString()); // "hello world"
console.log(typeof str.toString()); // string

console.log(str.toLocaleString()); // "hello world"
console.log(typeof str.toLocaleString()); // string

??String 類(lèi)型的每個(gè)實(shí)例都有一個(gè) length 屬性份汗,表示字符串中包含多個(gè)字符。示例:

let stringValue = "hello world";
console.log(stringValue.length); // "11" 

注意:即使字符串中包含雙字節(jié)字符(不是占一個(gè)字節(jié)的 ASCII 字符)蝴簇,每個(gè)字符也仍然算一個(gè)字符杯活。

??String 類(lèi)型提供了很多方法,用于輔助完成對(duì) ECMAScript 中字符串的解析和操作熬词。

  1. 字符方法
    • charAt() :返回給定位置的字符旁钧。
    • charCodeAt():返回給定位置的字符的字符編碼。
    • stringValue():返回給定位置的字符互拾。
  2. 字符串操作方法
    • concat():將一或多個(gè)字符串拼接起來(lái)歪今,返回拼接得到的新字符串。
    • slice():返回被操作字符串的一個(gè)子字符串颜矿。
    • substr():返回被操作字符串的一個(gè)子字符串寄猩。
    • substring():返回被操作字符串的一個(gè)子字符串。
  3. 字符串位置方法
    • indexOf():從前向后搜索骑疆,返回字符串中指定字符串的位置田篇。
    • lastIndexOf():從后向前搜索替废,返回字符串中指定字符串的位置。
  4. trim() 方法
    • trim():會(huì)創(chuàng)建一個(gè)字符串的副本泊柬,刪除前置及后綴的所有空格椎镣,然后返回結(jié)果。
  5. 字符串大小寫(xiě)轉(zhuǎn)換方法
    • toLowerCase():將字符串全部轉(zhuǎn)換成小寫(xiě)兽赁。
    • toLocaleLowerCase():針對(duì)特定地區(qū)状答,將字符串全部轉(zhuǎn)換成小寫(xiě)。
    • toUpperCase():將字符串全部轉(zhuǎn)換成大寫(xiě)刀崖。
    • toLocaleUpperCase():針對(duì)特定地區(qū)惊科,將字符串全部轉(zhuǎn)換成大寫(xiě)。
  6. 字符串的模式匹配方法
    • match():返回匹配項(xiàng)信息的數(shù)組亮钦。
    • search():返回字符串中第一個(gè)匹配項(xiàng)的索引译断;如果沒(méi)有找到匹配項(xiàng),則返回 -1或悲。
    • replace():進(jìn)行子字符串的替換操作。
    • split():基于指定的分隔符將一個(gè)字符串分割成多個(gè)子字符串堪唐,并將結(jié)果放在一個(gè)數(shù)組中巡语。
  7. localeCompare() 方法
    • localeCompare():用于比較兩個(gè)字符串。
  8. fromCharCode() 方法
    • fromCharCode()
  9. HTML 方法
1. 字符方法

charAt() 方法接收一個(gè)參數(shù)淮菠,即基于 0 的字符位置男公,以單字符字符串的形式返回指定位置的字符。示例:

let stringValue = "hello world";
console.log(stringValue.charAt(1)); // "e" 

charCodeAt() 方法接收一個(gè)參數(shù)合陵,即基于 0 的字符位置枢赔,返回給定位置的字符的字符編碼。示例:

let stringValue = "hello world";
console.log(stringValue.charCodeAt(1)); // "101" 

stringValue() 方法使用方括號(hào)加數(shù)字索引來(lái)訪(fǎng)問(wèn)字符串中的特定字符拥知。示例:

let stringValue = "hello world";
console.log(stringValue[1]); // "e"
2. 字符串操作方法

concat() 方法用于將一或多個(gè)字符串拼接起來(lái)踏拜,返回拼接得到的新字符串。示例:

let stringValue = "hello "; 
let result = stringValue.concat("world", "!"); 

console.log(result); // "hello world!"
console.log(stringValue); // "hello" 

slice() 方法會(huì)返回被操作字符串的一個(gè)子字符串低剔。接收參數(shù):指定子字符串的開(kāi)始位置速梗,(可選)子字符串最后一個(gè)字符后面的位置(默認(rèn):到字符串末尾)。當(dāng)參數(shù)是負(fù)值時(shí)襟齿,slice() 方法會(huì)將傳入的負(fù)值與字符串的長(zhǎng)度相加姻锁。

substr() 方法會(huì)返回被操作字符串的一個(gè)子字符串。接收參數(shù):指定子字符串的開(kāi)始位置猜欺,(可選)返回的字符個(gè)數(shù)(默認(rèn):到字符串末尾)位隶。當(dāng)參數(shù)是負(fù)值時(shí),substr() 方法將負(fù)的第一個(gè)參數(shù)加上字符串的長(zhǎng)度开皿,而將負(fù)的第二個(gè)參數(shù)轉(zhuǎn)換為 0涧黄。

substring() 方法會(huì)返回被操作字符串的一個(gè)子字符串篮昧。接收參數(shù):指定子字
符串的開(kāi)始位置,(可選)子字符串最后一個(gè)字符后面的位置(默認(rèn):到字符串末尾)弓熏。當(dāng)參數(shù)是負(fù)值時(shí)恋谭,substring() 方法會(huì)把所有負(fù)值參數(shù)都轉(zhuǎn)換為 0。

let stringValue = "hello world"; // length === 11

console.log(slice(3));        // "lo world"
console.log(substr(3));       // "lo world"
console.log(substring(3));    // "lo world"

console.log(slice(3, 7));     // "lo w" 
console.log(substr(3, 7));    // "lo worl"
console.log(substring(3, 7)); // "lo w"

console.log(slice(-3));        // "rld"         (8)
console.log(substr(-3));       // "rld"         (8)
console.log(substring(-3));    // "hello world" (0)

console.log(slice(3, -4));     // "lo w"        (3, 7)
console.log(substr(3, -4));    // ""(空字符串) (0, 0)
console.log(substring(3, -4)); // "hel"         (3, 0)
3. 字符串位置方法

indexOf() 方法從字符串的開(kāi)頭向后搜索指定的子字符串挽鞠,然后返回子字符串的位置(如果沒(méi)有找到該子字符串疚颊,則返回-1)。接收參數(shù):指定字符串信认,(可選)開(kāi)始搜索的位置(indexOf() 會(huì)從該參數(shù)指定的位置向后搜索材义,忽略該位置之前的所有字符)。

lastIndexOf() 方法從字符串的末尾向前搜索指定的子字符串嫁赏,然后返回子字符串的位置(如果沒(méi)有找到該子字符串其掂,則返回-1)。接收參數(shù):指定字符串潦蝇,(可選)開(kāi)始搜索的位置(lastIndexOf() 會(huì)從指定的位置向前搜索款熬,忽略該位置之后的所有字符)。

let stringValue = "hello world"; 

console.log(stringValue.indexOf("o"));        // 4
console.log(stringValue.lastIndexOf("o"));    // 7

console.log(stringValue.indexOf("o", 6));     // 7
console.log(stringValue.lastIndexOf("o", 6)); // 4

??在使用第二個(gè)參數(shù)的情況下攘乒,可以通過(guò)循環(huán)調(diào)用 indexOf() 或 lastIndexOf() 來(lái)找到所有匹配的子字符串贤牛。示例:

let stringValue = "Lorem ipsum dolor sit amet, consectetur adipisicing elit";
let positions = new Array();
let pos = stringValue.indexOf("e");

while(pos > -1){
    positions.push(pos);
    pos = stringValue.indexOf("e", pos + 1);
}

console.log(positions); // [3, 24, 32, 35, 52] 

??這個(gè)例子通過(guò)不斷增加 indexOf() 方法開(kāi)始查找的位置,遍歷了一個(gè)長(zhǎng)字符串则酝。在循環(huán)之外殉簸,首先找到了 "e" 在字符串中的初始位置;而進(jìn)入循環(huán)后沽讹,則每次都給 indexOf() 傳遞上一次的位置加 1般卑。這樣,就確保了每次新搜索都從上一次找到的子字符串的后面開(kāi)始爽雄。每次搜索返回的位置依次被保存在數(shù)組 positions 中蝠检,以便將來(lái)使用。

4. trim() 方法

trim() 方法會(huì)創(chuàng)建一個(gè)字符串的副本挚瘟,刪除前置及后綴的所有空格蝇率,然后返回結(jié)果。由于 trim()返回的是字符串的副本刽沾,所以原始字符串中的前置及后綴空格會(huì)保持不變本慕。示例:

let stringValue = "    hello world     ";
let trimmedStringValue = stringValue.trim();

console.log(stringValue);       // "    hello world    "
console.log(trimmedStringValue); // "hello world" 
5. 字符串大小寫(xiě)轉(zhuǎn)換方法

??涉及字符串大小寫(xiě)轉(zhuǎn)換的方法有 4 個(gè):toLowerCase()toLocaleLowerCase()侧漓、toUpperCase()toLocaleUpperCase()锅尘。

??toLocaleLowerCase() 和 toLocaleUpperCase() 方法是針對(duì)特定地區(qū)的實(shí)現(xiàn)。一般來(lái)說(shuō),在不知道自己的代碼將在哪種語(yǔ)言環(huán)境中運(yùn)行的情況下藤违,還是使用針對(duì)地區(qū)的方法更穩(wěn)妥一些浪腐。

let stringValue = "hello world";

console.log(stringValue.toLocaleUpperCase()); // "HELLO WORLD"
console.log(stringValue.toUpperCase());       // "HELLO WORLD"

console.log(stringValue.toLocaleLowerCase()); // "hello world"
console.log(stringValue.toLowerCase());       // "hello world"
6. 字符串的模式匹配方法

??match() 只接受一個(gè)參數(shù),一個(gè)正則表達(dá)式 / 一個(gè) RegExp 對(duì)象顿乒。返回一個(gè)數(shù)組议街。在字符串上調(diào)用這個(gè)方法,本質(zhì)上與調(diào)用 RegExp 的 exec() 方法相同璧榄。示例:

let text = "cat, bat, sat, fat";
let pattern = /.at/;

//與 pattern.exec(text) 相同
let matches = text.match(pattern);
console.log(matches.index); // 0
console.log(matches[0]); // "cat"
console.log(pattern.lastIndex); // 0 

??上述示例中的 match() 方法返回一個(gè)數(shù)組特漩;如果調(diào)用 RegExp 對(duì)象的 exec() 方法并傳遞本例中的字符串作為參數(shù),那么也會(huì)得到與此相同的數(shù)組:數(shù)組的第一項(xiàng)是與整個(gè)模式匹配的字符串骨杂,之后的每一項(xiàng)(如果有)保存著與正則表達(dá)式中的捕獲組匹配的字符串涂身。

??search() 只接受一個(gè)參數(shù),由字符串或 RegExp 對(duì)象指定的一個(gè)正則表達(dá)式搓蚪。返回字符串中第一個(gè)匹配項(xiàng)的索引蛤售;如果沒(méi)有找到匹配項(xiàng),則返回 -1妒潭。search() 方法始終是從前向后查找悴能。示例:

let text = "cat, bat, sat, fat";
let pos = text.search(/at/);
console.log(pos); // 1 

??replace() 可以進(jìn)行子字符串的替換操作。接受 2 個(gè)參數(shù):一個(gè) RegExp 對(duì)象或者一個(gè)字符串(這個(gè)字符串不會(huì)被轉(zhuǎn)換成正則表達(dá)式)雳灾;一個(gè)字符串或者一個(gè)函數(shù)漠酿。

??如果第一個(gè)參數(shù)是字符串,那么只會(huì)替換第一個(gè)子字符串佑女。要想替換所有子字符串,唯一的辦法就是提供一個(gè)正則表達(dá)式谈竿,而且要指定全局(g)標(biāo)志团驱。示例:

let text = "cat, bat, sat, fat";

let result = text.replace("at", "ond");
console.log(result); // "cond, bat, sat, fat"

result = text.replace(/at/g, "ond");
console.log(result); // "cond, bond, sond, fond" 

??如果第二個(gè)參數(shù)是字符串,那么還可以使用一些特殊的字符序列空凸,將正則表達(dá)式操作得到的值插入到結(jié)果字符串中嚎花。

字符序列 替換文本
$$ $
$& 匹配整個(gè)模式的子字符串。與RegExp.lastMatch的值相同
$' 匹配的子字符串之前的子字符串呀洲。與RegExp.leftContext的值相同
$` 匹配的子字符串之后的子字符串紊选。與RegExp.rightContext的值相同
$n 匹配第n個(gè)捕獲組的子字符串,其中n等于0~9道逗。例如兵罢,$1是匹配第一個(gè)捕獲組的子字符串,$2是匹配第二個(gè)捕獲組的子字符串滓窍,以此類(lèi)推卖词。如果正則表達(dá)式中沒(méi)有定義捕獲組,則使用空字符串
$nn 匹配第nn個(gè)捕獲組的子字符串吏夯,其中nn等于01~99此蜈。例如即横,$01是匹配第一個(gè)捕獲組的子字符串,$02是匹配第二個(gè)捕獲組的子字符串裆赵,以此類(lèi)推东囚。如果正則表達(dá)式中沒(méi)有定義捕獲組,則使用空字符串

??通過(guò)這些特殊的字符序列战授,可以使用最近一次匹配結(jié)果中的內(nèi)容页藻,示例:

let text = "cat, bat, sat, fat";
let result = text.replace(/(.at)/g, "word ($1)");
console.log(result); // word (cat), word (bat), word (sat), word (fat) 

??上述例子中,每個(gè)以"at"結(jié)尾的單詞都被替換了陈醒,替換結(jié)果是"word"后跟一對(duì)圓括號(hào)惕橙,而圓括號(hào)中是被
字符序列$1 所替換的單詞。

??如果第二個(gè)參數(shù)是函數(shù)钉跷。
??在只有一個(gè)匹配項(xiàng)(即與模式匹配的字符串)的情況下弥鹦,會(huì)向這個(gè)函數(shù)傳遞 3 個(gè)參數(shù):模式的匹配項(xiàng)、模式匹配項(xiàng)在字符串中的位置爷辙、原始字符串彬坏。
??在正則表達(dá)式中定義了多個(gè)捕獲組的情況下,傳遞給函數(shù)的參數(shù)依次是模式的匹配項(xiàng)膝晾、第一個(gè)捕獲組的匹配項(xiàng)栓始、第二個(gè)捕獲組的匹配項(xiàng)……,但最后兩個(gè)參數(shù)仍然分別是模式的匹配項(xiàng)在字符串中的位置血当、原始字符串幻赚。

??這個(gè)函數(shù)應(yīng)該返回一個(gè)字符串,表示應(yīng)該被替換的匹配項(xiàng)使用函數(shù)作為 replace() 方法的第二個(gè)參數(shù)可以實(shí)現(xiàn)更加精細(xì)的替換操作臊旭,示例:

function htmlEscape(text) {
    return text.replace(/[<>"&]/g, function(match, pos, originalText){
        switch(match){
            case "<":
                return "&lt;";
            case ">":
                return "&gt;";
            case "&":
                return "&amp;";
            case "\"":
                return "&quot;";
         }
    });
}

console.log(htmlEscape("<p class=\"greeting\">Hello world!</p>"));
// &lt;p class=&quot;greeting&quot;&gt;Hello world!&lt;/p&gt; 

??上述例子中落恼,我們?yōu)椴迦?HTML 代碼定義了函數(shù) htmlEscape(),這個(gè)函數(shù)能夠轉(zhuǎn)義 4 個(gè)字符:小于號(hào)离熏、大于號(hào)佳谦、雙引號(hào)、和號(hào)滋戳。钻蔑。實(shí)現(xiàn)這種轉(zhuǎn)義的最簡(jiǎn)單方式,就是使用正則表達(dá)式查找這幾個(gè)字符奸鸯,然后定義一個(gè)能夠針對(duì)每個(gè)匹配的字符返回特定 HTML 實(shí)體的函數(shù)咪笑。

??split() 方法基于指定的分隔符將一個(gè)字符串分割成多個(gè)子字符串,并將結(jié)果放在一個(gè)數(shù)組中娄涩。
??分隔符可以是字符串蒲肋,也可以是一個(gè) RegExp 對(duì)象(這個(gè)方法不會(huì)將字符串看成正則表達(dá)式)。
??split()方法可以接受可選的第二個(gè)參數(shù),用于指定數(shù)組的大小兜粘,以便確保返回的數(shù)組不會(huì)超過(guò)既定大小申窘。
示例:

let colorText = "red, blue, green, yellow";
let colors1 = colorText.split(",");      // ["red", "blue", "green", "yellow"]
let colors2 = colorText.split(",", 2);   // ["red", "blue"]
let colors3 = colorText.split(/[^\,]+/); // [" ", ",", ",", ",", " "] 
/[^\,]+/:[^\,] 表示任何非,(逗號(hào))的字符,+ 表示一個(gè)或者多個(gè)孔轴。

??在最后一次調(diào)用 split() 返回的數(shù)組中剃法,第一項(xiàng)和最后一項(xiàng)是兩個(gè)空字符串。之所以會(huì)這樣路鹰,是因?yàn)橥ㄟ^(guò)正則表達(dá)式指定的分隔符出現(xiàn)在了字符串的開(kāi)頭(即子字符串 "red")和末尾(即子字符串 "yellow")贷洲。

7. localeCompare() 方法

localeCompare() 方法用于比較兩個(gè)字符串,并返回下列值中的一個(gè):

  • 如果字符串在字母表中應(yīng)該排在字符串參數(shù)之前晋柱,則返回一個(gè)負(fù)數(shù)(大多數(shù)情況下是 -1优构,具體的值要視實(shí)現(xiàn)而定);
  • 如果字符串等于字符串參數(shù)雁竞,則返回 0钦椭;
  • 如果字符串在字母表中應(yīng)該排在字符串參數(shù)之后,則返回一個(gè)正數(shù)(大多數(shù)情況下是 1碑诉,具體的值同樣要視實(shí)現(xiàn)而定)彪腔。

示例:

let stringValue = "yellow";
console.log(stringValue.localeCompare("brick")); // 1
console.log(stringValue.localeCompare("yellow")); // 0
console.log(stringValue.localeCompare("zoo")); // -1 

??強(qiáng)調(diào):因?yàn)?localeCompare() 返回的數(shù)值取決于實(shí)現(xiàn),所以最好是像下面例子所示的這樣使用這個(gè)方法进栽。

let stringValue = "yellow";
function determineOrder(value) {
    let result = stringValue.localeCompare(value);
    if (result < 0){
        console.log("The string 'yellow' comes before the string '" + value + "'.");
    } else if (result > 0) {
        console.log("The string 'yellow' comes after the string '" + value + "'.");
    } else { 
        console.log("The string 'yellow' is equal to the string '" + value + "'.");
    }
}
determineOrder("brick");
// The string 'yellow' comes after the string 'brick'.
determineOrder("yellow");
// The string 'yellow' is equal to the string 'yellow'.
determineOrder("zoo"); 
// The string 'yellow' comes before the string 'zoo'.
8. fromCharCode() 方法

??fromCharCode() 方法是String 構(gòu)造函數(shù)本身的一個(gè)一個(gè)靜態(tài)方法德挣。接收一或多個(gè)字符編碼,然后將它們轉(zhuǎn)換成一個(gè)字符串快毛。從本質(zhì)上來(lái)看格嗅,這個(gè)方法與實(shí)例方法 charCodeAt() 執(zhí)行的是相反的操作。示例:

console.log(String.fromCharCode(104, 101, 108, 108, 111)); 
// "hello" 
9. HTML 方法
方 法 輸出結(jié)果
anchor(name) <a name= "name">string</a>
big() <big>string</big>
bold() <b>string</b>
fixed() <tt>string</tt>
fontcolor(color) <font color="color">string</font>
fontsize(size) <font size="size">string</font>
italics() <i>string</i>
link(url) <a href="url">string</a>
small() <small>string</small>
strike() <strike>string</strike>
sub() <sub/>string</sub/>
sup() <sup/>string</sup/>

??注意:表格最后兩個(gè) sub() 唠帝、sup() 輸出結(jié)果中字母后斜杠(/)不是書(shū)寫(xiě)錯(cuò)誤屯掖,而是markdown 會(huì)自動(dòng)解析,不能正確展示没隘,故意為之懂扼。

使用方法:

let str="Hello world!"
console.log(str.big()); // <big>Hello world!</big>
console.log(str.anchor(name)); // <a name= "name">Hello world!</a>

7禁荸、單體內(nèi)置對(duì)象

??ECMA-262 對(duì)內(nèi)置對(duì)象的定義是:“由 ECMAScript 實(shí)現(xiàn)提供的右蒲、不依賴(lài)于宿主環(huán)境的對(duì)象,這些對(duì)象在 ECMAScript 程序執(zhí)行之前就已經(jīng)存在了赶熟。” 意思就是說(shuō),開(kāi)發(fā)人員不必顯式地實(shí)例化內(nèi)置對(duì)象尉剩,因?yàn)樗鼈円呀?jīng)實(shí)例化了面粮。
??前面我們已經(jīng)介紹了大多數(shù)內(nèi)置對(duì)象,例如Object、Array 和 String竹宋。
??ECMA-262 還定義了兩個(gè)單體內(nèi)置對(duì)象:Global 和 Math劳澄。

7.1、Global 對(duì)象

??Global(全局)對(duì)象可以說(shuō)是 ECMAScript 中最特別的一個(gè)對(duì)象了蜈七,因?yàn)椴还苣銖氖裁唇嵌壬峡疵氚危@個(gè)對(duì)象都是不存在的。
??ECMAScript 中的 Global 對(duì)象在某種意義上是作為一個(gè)終極的“兜底兒對(duì)象”來(lái)定義的飒硅。換句話(huà)說(shuō)砂缩,不屬于任何其他對(duì)象的屬性和方法,最終都是它的屬性和方法三娩。
??事實(shí)上庵芭,沒(méi)有全局變量或全局函數(shù);所有在全局作用域中定義的屬性和函數(shù)雀监,都是 Global 對(duì)象的屬性双吆。例如:isNaN()、isFinite()滔悉、parseInt() 伊诵、parseFloat(),實(shí)際上全都是 Global對(duì)象的方法回官。除此之外曹宴,Global 對(duì)象還包含其他一些方法。

1. URI 編碼方法

??Global 對(duì)象的 encodeURI() 和 encodeURIComponent() 方法可以對(duì) URI(Uniform Resource Identifiers歉提,通用資源標(biāo)識(shí)符)進(jìn)行編碼笛坦,以便發(fā)送給瀏覽器。
??有效的 URI 中不能包含某些字符苔巨,例如空格版扩。而這兩個(gè) URI 編碼方法就可以對(duì) URI 進(jìn)行編碼,它們用特殊的 UTF-8 編碼替換所有無(wú)效的字符侄泽,從而讓瀏覽器能夠接受和理解礁芦。

encodeURI() 主要用于整個(gè) URI
(例如,http://www.wrox.com/illegal value.html)悼尾。

encodeURIComponent() 主要用于對(duì) URI 中的某一段
(例如前面 URI 中的 illegal value.html)進(jìn)行編碼柿扣。

??區(qū)別:encodeURI() 不會(huì)對(duì)本身屬于 URI 的特殊字符進(jìn)行編碼,例如冒號(hào)闺魏、正斜杠未状、問(wèn)號(hào)和井字號(hào);encodeURIComponent( ) 則會(huì)對(duì)它發(fā)現(xiàn)的任何非標(biāo)準(zhǔn)字符進(jìn)行編碼析桥。示例:

let uri = "http://www.wrox.com/illegal value.html#start";

console.log(encodeURI(uri));
// "http://www.wrox.com/illegal%20value.html#start"

console.log(encodeURIComponent(uri)); 
// "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.html%23start"

??使用 encodeURI() 編碼后的結(jié)果是除了空格之外的其他字符都原封不動(dòng)司草,只有空格被替換成了%20艰垂。而 encodeURIComponent() 方法則會(huì)使用對(duì)應(yīng)的編碼替換所有非字母數(shù)字字符。這也正是可以對(duì)整個(gè) URI 使用 encodeURI()埋虹,而只能對(duì)附加在現(xiàn)有 URI 后面的字符串使用 encodeURIComponent() 的原因所在猜憎。

??一般來(lái)說(shuō),我們使用 encodeURIComponent() 方法的時(shí)候要比使用
encodeURI() 更多搔课,因?yàn)樵趯?shí)踐中更常見(jiàn)的是對(duì)查詢(xún)字符串參數(shù)而不是對(duì)基礎(chǔ) URI 進(jìn)行編碼拉宗。

?? 與 encodeURI() 和 encodeURIComponent() 方法對(duì)應(yīng)的兩個(gè)方法分別是 decodeURI() 和 decodeURIComponent()。

decodeURI() 只能對(duì)使用 encodeURI() 替換的字符進(jìn)行解碼辣辫。

decodeURIComponent() 能夠解碼使用 encodeURIComponent() 編碼的所有字符旦事,即它可以解碼任何特殊字符的編碼。

示例:

let uri = "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.html%23start";

console.log(decodeURI(uri));
// http%3A%2F%2Fwww.wrox.com%2Fillegal value.html%23start

console.log(decodeURIComponent(uri)); 
// http://www.wrox.com/illegal value.html#start
2. eval() 方法

?? eval() 方法就像是一個(gè)完整的 ECMAScript 解析器急灭,它只接受一個(gè)參數(shù)姐浮,即要執(zhí)行的 ECMAScript(或 JavaScript)字符串。示例:

eval("console.log('hi')"); 
// 等價(jià)于
console.log('hi');

??當(dāng)解析器發(fā)現(xiàn)代碼中調(diào)用 eval() 方法時(shí)葬馋,它會(huì)將傳入的參數(shù)當(dāng)作實(shí)際的 ECMAScript 語(yǔ)句來(lái)解析卖鲤,然后把執(zhí)行結(jié)果插入到原位置。

??通過(guò) eval() 執(zhí)行的代碼被認(rèn)為是包含該次調(diào)用的執(zhí)行環(huán)境的一部分畴嘶,因此被執(zhí)行的代碼具有與該執(zhí)行環(huán)境相同的作用域鏈蛋逾。這意味著通過(guò) eval() 執(zhí)行的代碼可以引用在包含環(huán)境中定義的變量,示例:

let msg = "hello world";
eval("console.log(msg)"); // "hello world" 

??變量 msg 是在 eval() 調(diào)用的環(huán)境之外定義的窗悯,但其中調(diào)用的 console.log() 仍然能夠顯示 "hello world"区匣。這是因?yàn)樯厦娴诙写a最終被替換成了一行真正的代碼。

??同樣地蒋院,我們也可以在 eval() 調(diào)用中定義一個(gè)函數(shù)亏钩,然后再在該調(diào)用的外部代碼中引用這個(gè)函數(shù):

eval("function sayHi() { console.log('hi'); }");
sayHi(); // "hi"

??顯然,函數(shù) sayHi() 是在 eval() 內(nèi)部定義的欺旧。但由于對(duì) eval() 的調(diào)用最終會(huì)被替換成定義函數(shù)的實(shí)際代碼姑丑,因此可以在下一行調(diào)用 sayHi()。

??對(duì)于變量也一樣:

eval("let msg = 'hello world'; ");
console.log(msg); // "hello world" 

??在 eval() 中創(chuàng)建的任何變量或函數(shù)都不會(huì)被提升辞友,因?yàn)樵诮馕龃a的時(shí)候栅哀,它們被包含在一個(gè)字符串中;它們只在 eval() 執(zhí)行的時(shí)候創(chuàng)建称龙。

??嚴(yán)格模式下留拾,在外部訪(fǎng)問(wèn)不到 eval() 中創(chuàng)建的任何變量或函數(shù),因此前面兩個(gè)例子都會(huì)導(dǎo)致錯(cuò)誤茵瀑。同樣间驮,在嚴(yán)格模式下躬厌,為 eval 賦值也會(huì)導(dǎo)致錯(cuò)誤:

"use strict";
eval = "hi"; // causes error 

??能夠解釋代碼字符串的能力非常強(qiáng)大马昨,但也非常危險(xiǎn)竞帽。因此在使用 eval() 時(shí)必須極為謹(jǐn)慎,特別是在用它執(zhí)行用戶(hù)輸入數(shù)據(jù)的情況下鸿捧。否則屹篓,可能會(huì)有惡意用戶(hù)輸入威脅你的站點(diǎn)或應(yīng)用程序安全的代碼(即所謂的代碼注入)。

3. Global 對(duì)象的屬性

??Global 對(duì)象還包含一些屬性匙奴,例如:特殊的值undefined堆巧、NaN、Infinity都是 Global 對(duì)象的屬性泼菌。此外谍肤,所有原生引用類(lèi)型的構(gòu)造函數(shù),像 Object 和Function哗伯,也都是 Global 對(duì)象的屬性荒揣。

屬 性 說(shuō) 明 屬 性 說(shuō) 明
undefined 特殊值undefined Date 構(gòu)造函數(shù)Date
NaN 特殊值NaN RegExp 構(gòu)造函數(shù)RegExp
Infinity 特殊值Infinity Error 構(gòu)造函數(shù)Error
Object 構(gòu)造函數(shù)Object EvalError 構(gòu)造函數(shù)EvalError
Array 構(gòu)造函數(shù)Array RangeError 構(gòu)造函數(shù)RangeError
Function 構(gòu)造函數(shù)Function ReferenceError 構(gòu)造函數(shù)ReferenceError
Boolean 構(gòu)造函數(shù)Boolean SyntaxError 構(gòu)造函數(shù)SyntaxError
String 構(gòu)造函數(shù)String TypeError 構(gòu)造函數(shù)TypeError
Number 構(gòu)造函數(shù)Number URIError 構(gòu)造函數(shù)URIError
4. window 對(duì)象

??ECMAScript 雖然沒(méi)有指出如何直接訪(fǎng)問(wèn) Global 對(duì)象,但 Web 瀏覽器都是將這個(gè)全局對(duì)象作為 window 對(duì)象的一部分加以實(shí)現(xiàn)的焊刹。因此系任,在全局作用域中聲明的所有變量和函數(shù),就都成為了 window 對(duì)象的屬性虐块。示例:

let color = "red";
function sayColor(){
    console.log(window.color);
}
window.sayColor(); // "red" 

??另一種取得 Global 對(duì)象的方法是使用以下代碼:

let global = function(){
    return this;
}(); 

??以上代碼創(chuàng)建了一個(gè)立即調(diào)用的函數(shù)表達(dá)式俩滥,返回 this 的值。如前所述贺奠,在沒(méi)有給函數(shù)明確指定 this 值的情況下(無(wú)論是通過(guò)將函數(shù)添加為對(duì)象的方法霜旧,還是通過(guò)調(diào)用 call() 或 apply()),this 值等于 Global 對(duì)象儡率。而像這樣通過(guò)簡(jiǎn)單地返回 this 來(lái)取得 Global 對(duì)象颁糟,在任何執(zhí)行環(huán)境下都是可行的。

7.2喉悴、Math 對(duì)象

??ECMAScript 還為保存數(shù)學(xué)公式和信息提供了一個(gè)公共位置棱貌,即 Math 對(duì)象。與我們?cè)?JavaScript 直接編寫(xiě)的計(jì)算功能相比箕肃,Math 對(duì)象提供的計(jì)算功能執(zhí)行起來(lái)要快得多婚脱。Math 對(duì)象中還提供了輔助完成這些計(jì)算的屬性和方法。

1. Math 對(duì)象的屬性

??Math 對(duì)象包含的屬性大都是數(shù)學(xué)計(jì)算中可能會(huì)用到的一些特殊值勺像。下表列出了這些屬性障贸。

屬 性 說(shuō) 明
Math.E 自然對(duì)數(shù)的底數(shù),即常量 e 的值
Math.LN10 10 的自然對(duì)數(shù)
Math.LN2 2 的自然對(duì)數(shù)
Math.LOG2E 以 2 為底e的對(duì)數(shù)
Math.LOG10E 以 10 為底e的對(duì)數(shù)
Math.PI π 的值
Math.SQRT1_2 1/2 的平方根(即 2 的平方根的倒數(shù))
Math.SQRT2 2 的平方根
2. min() 和 max() 方法

??min()max() 方法用于確定一組數(shù)值中的最小值和最大值吟宦。這兩個(gè)方法都可以接收任意多個(gè)數(shù)值參數(shù)篮洁,示例:

let max = Math.max(3, 54, 32, 16);
console.log(max); // 54

let min = Math.min(3, 54, 32, 16);
console.log(min); // 3 

??這兩個(gè)方法經(jīng)常用于避免多余的循環(huán)和在 if 語(yǔ)句中確定一組數(shù)的最大值。
??要找到數(shù)組中的最大或最小值殃姓,可以像下面這樣使用 apply() 方法袁波。示例:

let values = [1, 2, 3, 4, 5, 6, 7, 8];
let max = Math.max.apply(Math, values); 
console.log(max); // 8
3. 舍入方法

??將小數(shù)值舍入為整數(shù)的方法:

  • Math.ceil():執(zhí)行向上舍入瓦阐,即它總是將數(shù)值向上舍入為最接近的整數(shù);
  • Math.floor():執(zhí)行向下舍入篷牌,即它總是將數(shù)值向下舍入為最接近的整數(shù)睡蟋;
  • Math.round():執(zhí)行標(biāo)準(zhǔn)舍入,即它總是將數(shù)值四舍五入為最接近的整數(shù)(這也是我們?cè)跀?shù)學(xué)課上學(xué)到的舍入規(guī)則)枷颊。

示例:

console.log(Math.ceil(25.9)); // 26
console.log(Math.ceil(25.5)); // 26
console.log(Math.ceil(25.1)); // 26

console.log(Math.round(25.9)); // 26
console.log(Math.round(25.5)); // 26
console.log(Math.round(25.1)); // 25

console.log(Math.floor(25.9)); // 25
console.log(Math.floor(25.5)); // 25
console.log(Math.floor(25.1)); // 25 
4. random() 方法

Math.random() 方法返回大于等于 0 小于 1 的一個(gè)隨機(jī)數(shù)戳杀。

利用 Math.random() 從某個(gè)整數(shù)范圍內(nèi)隨機(jī)選擇一個(gè)值。

值 = Math.floor(Math.random() * 可能值的總數(shù) + 第一個(gè)可能的值) 

??公式中用到了 Math.floor() 方法夭苗,這是因?yàn)?Math.random() 總返回一個(gè)小數(shù)值信卡。而用這個(gè)小數(shù)值乘以一個(gè)整數(shù),然后再加上一個(gè)整數(shù)题造,最終結(jié)果仍然還是一個(gè)小數(shù)坐求。第一個(gè)可能的值規(guī)定隨機(jī)整數(shù)的最小值。示例:

// 1 ~ 10 之間的隨機(jī)整數(shù)
let num = Math.floor(Math.random() * 10 + 1); 

// 2 ~ 10 之間的隨機(jī)整數(shù)
let num = Math.floor(Math.random() *9 + 2); 

??多數(shù)情況下晌梨,都可以通過(guò)一個(gè)函數(shù)來(lái)計(jì)算可能值的總數(shù)和第一個(gè)可能的值桥嗤,例如:

function selectFrom(lowerValue, upperValue) {
    let choices = upperValue - lowerValue + 1;
    return Math.floor(Math.random() * choices + lowerValue);
} 
let num = selectFrom(2, 10);
console.log(num); // 介于 2 和 10 之間(包括 2 和 10)的一個(gè)數(shù)值

??利用這個(gè)函數(shù),可以方便地從數(shù)組中隨機(jī)取出一項(xiàng)仔蝌,例如:

let colors = ["red", "green", "blue", "yellow", "black", "purple", "brown"];
let color = colors[selectFrom(0, colors.length-1)];
console.log(color); // 可能是數(shù)組中包含的任何一個(gè)字符串
5. 其他方法
方 法 說(shuō) 明
Math.abs(num) 返回 num 的絕對(duì)值
Math.exp(num) 返回 Math.E 的 num 次冪
Math.log(num) 返回 num 的自然對(duì)數(shù)
Math.pow(num, power) 返回 num 的 power 次冪
Math.sqrt(num) 返回 num 的平方根
Math.acos(x) 返回 x 的反余弦值
Math.asin(x) 返回 x 的反正弦值
Math.atan(x) 返回 x 的反正切值
Math.atan2(y,x) 返回 y/x 的反正切值
Math.cos(x) 返回 x 的余弦值
Math.sin(x) 返回 x 的正弦值
Math.tan(x) 返回 x 的正切值

??雖然 ECMA-262 規(guī)定了這些方法泛领,但不同實(shí)現(xiàn)可能會(huì)對(duì)這些方法采用不同的算法。畢竟敛惊,計(jì)算某個(gè)值的正弦渊鞋、余弦和正切的方式多種多樣。也正因?yàn)槿绱饲萍罚@些方法在不同的實(shí)現(xiàn)中可能會(huì)有不同的精度锡宋。

小結(jié)

??對(duì)象在 JavaScript 中被稱(chēng)為引用類(lèi)型的值,而且有一些內(nèi)置的引用類(lèi)型可以用來(lái)創(chuàng)建特定的對(duì)象特恬,現(xiàn)簡(jiǎn)要總結(jié)如下:

  • 引用類(lèi)型與傳統(tǒng)面向?qū)ο蟪绦蛟O(shè)計(jì)中的類(lèi)相似执俩,但實(shí)現(xiàn)不同;
  • Object 是一個(gè)基礎(chǔ)類(lèi)型癌刽,其他所有類(lèi)型都從 Object 繼承了基本的行為役首;
  • Array 類(lèi)型是一組值的有序列表,同時(shí)還提供了操作和轉(zhuǎn)換這些值的功能显拜;
  • Date 類(lèi)型提供了有關(guān)日期和時(shí)間的信息衡奥,包括當(dāng)前日期和時(shí)間以及相關(guān)的計(jì)算功能;
  • RegExp 類(lèi)型是 ECMAScript 支持正則表達(dá)式的一個(gè)接口远荠,提供了最基本的和一些高級(jí)的正則表達(dá)式功能矮固。

??函數(shù)實(shí)際上是 Function 類(lèi)型的實(shí)例,因此函數(shù)也是對(duì)象譬淳;而這一點(diǎn)正是 JavaScript 最有特色的地方档址。由于函數(shù)是對(duì)象盹兢,所以函數(shù)也擁有方法,可以用來(lái)增強(qiáng)其行為辰晕。

??因?yàn)橛辛嘶景b類(lèi)型,所以 JavaScript 中的基本類(lèi)型值可以被當(dāng)作對(duì)象來(lái)訪(fǎng)問(wèn)确虱。三種基本包裝類(lèi)型分別是:Boolean含友、Number 和 String。以下是它們共同的特征:

  • 每個(gè)包裝類(lèi)型都映射到同名的基本類(lèi)型校辩;
  • 在讀取模式下訪(fǎng)問(wèn)基本類(lèi)型值時(shí)窘问,就會(huì)創(chuàng)建對(duì)應(yīng)的基本包裝類(lèi)型的一個(gè)對(duì)象,從而方便了數(shù)據(jù)操作宜咒;
  • 操作基本類(lèi)型值的語(yǔ)句一經(jīng)執(zhí)行完畢惠赫,就會(huì)立即銷(xiāo)毀新創(chuàng)建的包裝對(duì)象。

??在所有代碼執(zhí)行之前故黑,作用域中就已經(jīng)存在兩個(gè)內(nèi)置對(duì)象:Global 和 Math儿咱。在大多數(shù) ECMAScript 實(shí)現(xiàn)中都不能直接訪(fǎng)問(wèn) Global 對(duì)象;不過(guò)场晶,Web 瀏覽器實(shí)現(xiàn)了承擔(dān)該角色的 window 對(duì)象混埠。全局變量和函數(shù)都是 Global 對(duì)象的屬性。Math 對(duì)象提供了很多屬性和方法诗轻,用于輔助完成復(fù)雜的數(shù)學(xué)計(jì)算任務(wù)钳宪。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市扳炬,隨后出現(xiàn)的幾起案子吏颖,更是在濱河造成了極大的恐慌,老刑警劉巖恨樟,帶你破解...
    沈念sama閱讀 219,366評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件半醉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡劝术,警方通過(guò)查閱死者的電腦和手機(jī)奉呛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,521評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)夯尽,“玉大人瞧壮,你說(shuō)我怎么就攤上這事〕孜眨” “怎么了咆槽?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,689評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)圈纺。 經(jīng)常有香客問(wèn)我秦忿,道長(zhǎng)麦射,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,925評(píng)論 1 295
  • 正文 為了忘掉前任灯谣,我火速辦了婚禮潜秋,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘胎许。我一直安慰自己峻呛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,942評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布辜窑。 她就那樣靜靜地躺著钩述,像睡著了一般。 火紅的嫁衣襯著肌膚如雪穆碎。 梳的紋絲不亂的頭發(fā)上牙勘,一...
    開(kāi)封第一講書(shū)人閱讀 51,727評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音所禀,去河邊找鬼方面。 笑死,一個(gè)胖子當(dāng)著我的面吹牛色徘,可吹牛的內(nèi)容都是我干的葡幸。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼贺氓,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蔚叨!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起辙培,我...
    開(kāi)封第一講書(shū)人閱讀 39,349評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蔑水,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后扬蕊,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體搀别,經(jīng)...
    沈念sama閱讀 45,820評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,990評(píng)論 3 337
  • 正文 我和宋清朗相戀三年尾抑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了歇父。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,127評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡再愈,死狀恐怖榜苫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情翎冲,我是刑警寧澤垂睬,帶...
    沈念sama閱讀 35,812評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響驹饺,放射性物質(zhì)發(fā)生泄漏钳枕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,471評(píng)論 3 331
  • 文/蒙蒙 一赏壹、第九天 我趴在偏房一處隱蔽的房頂上張望鱼炒。 院中可真熱鬧,春花似錦蝌借、人聲如沸昔瞧。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,017評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)硬爆。三九已至欣舵,卻和暖如春擎鸠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背缘圈。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,142評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工劣光, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人糟把。 一個(gè)月前我還...
    沈念sama閱讀 48,388評(píng)論 3 373
  • 正文 我出身青樓绢涡,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親遣疯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子雄可,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,066評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 第2章 基本語(yǔ)法 2.1 概述 基本句法和變量 語(yǔ)句 JavaScript程序的執(zhí)行單位為行(line),也就是一...
    悟名先生閱讀 4,150評(píng)論 0 13
  • 第5章 引用類(lèi)型(返回首頁(yè)) 本章內(nèi)容 使用對(duì)象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類(lèi)型 使用基本類(lèi)型...
    大學(xué)一百閱讀 3,237評(píng)論 0 4
  • 六月缠犀,南方進(jìn)入梅雨季数苫,雨下了將近大半個(gè)月也絲毫沒(méi)有停下來(lái)的意思。窩在床上昏昏欲睡時(shí)一個(gè)許久不聯(lián)系的朋友發(fā)來(lái)一條微信...
    無(wú)志但有體重閱讀 509評(píng)論 4 3
  • 尊敬的: 我是總務(wù)部的梅蓓辨液,感謝我們**和**的信任虐急,讓我得以在2017年第二次站在這里和大家做分享,上次我說(shuō)過(guò)梅...
    梅子Mey閱讀 859評(píng)論 9 6
  • 一堂課: 復(fù)習(xí)四單元第一課《古詩(shī)二首》滔迈。 一個(gè)同學(xué): 岳薇小朋友是個(gè)表面看起來(lái)秀氣止吁,內(nèi)心火熱的女孩,交給她做事情總...
    酒窩窩_xlj閱讀 317評(píng)論 0 0