一、字符串?dāng)U展
-
includes()、startsWith()、endsWith()。傳統(tǒng)JavaScript只有indexOf()方法用來確定一個(gè)字符串是否包含在另一個(gè)字符串中,ES6又提供了三個(gè)新方法。
-
includes():返回布爾值,表示是否找到了參數(shù)字符串。 -
startsWith():返回布爾值,表示參數(shù)字符串是否在原字符串的頭部。 -
endsWith():返回布爾值,表示參數(shù)字符串是否在原字符串的尾部。
let s = 'Hello world!';
s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true
這三個(gè)方法都支持第二個(gè)參數(shù),表示開始搜索的位置。但是使用第二個(gè)參數(shù)n時(shí),endsWith的行為與其他兩個(gè)方法有所不同。它針對(duì)前n個(gè)字符,而其他兩個(gè)方法針對(duì)從第n個(gè)位置直到字符串結(jié)束。
let s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
-
repeat。repeat方法返回一個(gè)新字符串,表示將原字符串重復(fù)n次。
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
- 參數(shù)如果是小數(shù),會(huì)被向下取整。
- 如果
repeat的參數(shù)是負(fù)數(shù)或者Infinity,會(huì)報(bào)錯(cuò)。 - 0 到-1 之間的小數(shù),則等同于 0,這是因?yàn)闀?huì)先進(jìn)行取整運(yùn)算。0 到-1 之間的小數(shù),取整以后等于
-0,repeat視同為 0。 - 參數(shù)
NaN等同于 0。 - 如果
repeat的參數(shù)是字符串,則會(huì)先轉(zhuǎn)換成數(shù)字。
-
padStart()、padEnd()。ES2017 引入了字符串補(bǔ)全長(zhǎng)度的功能。如果某個(gè)字符串不夠指定長(zhǎng)度,會(huì)在頭部或尾部補(bǔ)全。padStart()用于頭部補(bǔ)全,padEnd()用于尾部補(bǔ)全。
'x'.padStart(5, 'ab') // 'ababx'
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba'
- 如果原字符串的長(zhǎng)度,等于或大于指定的最小長(zhǎng)度,則返回原字符串。
- 如果用來補(bǔ)全的字符串與原字符串,兩者的長(zhǎng)度之和超過了指定的最小長(zhǎng)度,則會(huì)截去超出位數(shù)的補(bǔ)全字符串。
- 如果省略第二個(gè)參數(shù),默認(rèn)使用空格補(bǔ)全長(zhǎng)度。
- 模板字符串。
模板字符串是增強(qiáng)版的字符串,用反引號(hào)(`)標(biāo)識(shí)。它可以當(dāng)作普通字符串使用,也可以用來定義多行字符串,或者在字符串中嵌入變量。
- 如果在模板字符串中需要使用反引號(hào),則前面要用反斜杠轉(zhuǎn)義。
- 如果使用模板字符串表示多行字符串,所有的空格和縮進(jìn)都會(huì)被保留在輸出之中。
- 模板字符串中嵌入變量,需要將變量名寫在
${}之中。 - 大括號(hào)內(nèi)部可以放入任意的 JavaScript 表達(dá)式,可以進(jìn)行運(yùn)算,以及引用對(duì)象屬性。
- 模板字符串之中還能調(diào)用函數(shù)。
- 如果大括號(hào)中的值不是字符串,將按照一般的規(guī)則轉(zhuǎn)為字符串。比如,大括號(hào)中是一個(gè)對(duì)象,將默認(rèn)調(diào)用對(duì)象的
toString方法。 - 如果模板字符串中的變量沒有聲明,將報(bào)錯(cuò)。
var name = "追逐",trait = "帥氣";
//es
var str = "我叫"+name+",人非常"+trait+",說話又好聽";
//es6
var str2 = `我叫 ${name} ,人非常 ${trait} ,說話又好聽`;
- 標(biāo)簽?zāi)0濉D0遄址梢跃o跟在一個(gè)函數(shù)名后面,該函數(shù)將被調(diào)用來處理這個(gè)模板字符串。這被稱為“標(biāo)簽?zāi)0濉惫δ堋?/li>
alert`123`
// 等同于
alert(123)
標(biāo)簽?zāi)0迤鋵?shí)不是模板,而是函數(shù)調(diào)用的一種特殊形式?!皹?biāo)簽”指的就是函數(shù),緊跟在后面的模板字符串就是它的參數(shù)。如果模板字符里面有變量,就不是簡(jiǎn)單的調(diào)用了,而是會(huì)將模板字符串先處理成多個(gè)參數(shù),再調(diào)用函數(shù)。
let a = 5;
let b = 10;
tag`Hello ${ a + b } world ${ a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);
二、數(shù)值擴(kuò)展
-
Number.isFinite()、Number.isNaN()。ES6 在Number對(duì)象上,新提供了Number.isFinite()和Number.isNaN()兩個(gè)方法。
-
Number.isFinite()用來檢查一個(gè)數(shù)值是否為有限的(finite)。
Number.isFinite(15); // true
Number.isFinite(0.8); // true
Number.isFinite(NaN); // false
Number.isFinite(Infinity); // false
Number.isFinite(-Infinity); // false
Number.isFinite('foo'); // false
Number.isFinite('15'); // false
Number.isFinite(true); // false
-
Number.isNaN()用來檢查一個(gè)值是否為NaN。和全局函數(shù)isNaN()相比,該方法不會(huì)強(qiáng)制將參數(shù)轉(zhuǎn)換成數(shù)字,只有在參數(shù)是真正的數(shù)字類型,且值為NaN的時(shí)候才會(huì)返回true。
Number.isNaN(NaN); // true
Number.isNaN(Number.NaN); // true
Number.isNaN(0 / 0) // true
// 下面這幾個(gè)如果使用全局的 isNaN() 時(shí),會(huì)返回 true。
Number.isNaN("NaN"); // false,字符串 "NaN" 不會(huì)被隱式轉(zhuǎn)換成數(shù)字 NaN。
Number.isNaN(undefined); // false
Number.isNaN({}); // false
Number.isNaN("blabla"); // false
// 下面的都返回 false
Number.isNaN(true);
Number.isNaN(null);
Number.isNaN(37);
Number.isNaN("37");
Number.isNaN("37.37");
Number.isNaN("");
Number.isNaN(" ");
-
Number.parseInt()、Number.parseFloat()。ES6 將全局方法parseInt()和parseFloat(),移植到Number對(duì)象上面,行為完全保持不變。這樣做的目的,是逐步減少全局性方法,使得語(yǔ)言逐步模塊化。
// ES5的寫法
parseInt('12.34') // 12
parseFloat('123.45#') // 123.45
// ES6的寫法
Number.parseInt('12.34') // 12
Number.parseFloat('123.45#') // 123.45
Number.parseInt === parseInt // true
Number.parseFloat === parseFloat // true
-
Number.isInteger()。Number.isInteger()用來判斷一個(gè)值是否為整數(shù)。需要注意的是,在 JavaScript 內(nèi)部,整數(shù)和浮點(diǎn)數(shù)是同樣的儲(chǔ)存方法,所以 3 和 3.0 被視為同一個(gè)值。
Number.isInteger(25) // true
Number.isInteger(25.0) // true
Number.isInteger(25.1) // false
Number.isInteger("15") // false
Number.isInteger(true) // false
- Math對(duì)象的擴(kuò)展。
ES6 在 Math 對(duì)象上新增了 17 個(gè)與數(shù)學(xué)相關(guān)的方法。所有這些方法都是靜態(tài)方法,只能在 Math 對(duì)象上調(diào)用。
-
Math.trunc方法用于去除一個(gè)數(shù)的小數(shù)部分,返回整數(shù)部分。對(duì)于非數(shù)值,Math.trunc內(nèi)部使用Number方法將其先轉(zhuǎn)為數(shù)值。對(duì)于空值和無法截取整數(shù)的值,返回NaN。
Math.trunc(4.1) // 4
Math.trunc(4.9) // 4
Math.trunc(-4.1) // -4
Math.trunc(-4.9) // -4
Math.trunc(-0.1234) // -0
-
Math.sign方法用來判斷一個(gè)數(shù)到底是正數(shù)、負(fù)數(shù)、還是零。對(duì)于非數(shù)值,會(huì)先將其轉(zhuǎn)換為數(shù)值。它返回五種值,參數(shù)為正數(shù),返回+1;參數(shù)為負(fù)數(shù),返回-1;參數(shù)為 0,返回0;參數(shù)為-0,返回-0;其他值,返回NaN。
Math.sign(-5) // -1
Math.sign(5) // +1
Math.sign(0) // +0
Math.sign(-0) // -0
Math.sign(NaN) // NaN
Math.sign('') // 0
Math.sign(true) // +1
Math.sign(false) // 0
Math.sign(null) // 0
Math.sign('9') // +1
Math.sign('foo') // NaN
Math.sign() // NaN
Math.sign(undefined) // NaN
-
Math.cbrt方法用于計(jì)算一個(gè)數(shù)的立方根。對(duì)于非數(shù)值,Math.cbrt方法內(nèi)部也是先使用Number方法將其轉(zhuǎn)為數(shù)值。
Math.cbrt(-1) // -1
Math.cbrt(0) // 0
Math.cbrt(1) // 1
Math.cbrt(2) // 1.2599210498948734
-
Math.hypot方法返回所有參數(shù)的平方和的平方根。
Math.hypot(3, 4); // 5
Math.hypot(3, 4, 5); // 7.0710678118654755
Math.hypot(); // 0
Math.hypot(NaN); // NaN
Math.hypot(3, 4, 'foo'); // NaN
Math.hypot(3, 4, '5'); // 7.0710678118654755
Math.hypot(-3); // 3
- 指數(shù)運(yùn)算符。ES2016 新增了一個(gè)指數(shù)運(yùn)算符(
**)。指數(shù)運(yùn)算符可以與等號(hào)結(jié)合,形成一個(gè)新的賦值運(yùn)算符(**=)。
2 ** 2 // 4
2 ** 3 // 8
let a = 1.5;
a **= 2;
// 等同于 a = a * a;
let b = 4;
b **= 3;
// 等同于 b = b * b * b;
三、函數(shù)擴(kuò)展
- 函數(shù)參數(shù)的默認(rèn)值。
- 基本用法。
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello
- 與解構(gòu)賦值默認(rèn)值結(jié)合使用。
function foo({x, y = 5}) {
console.log(x, y);
}
foo({}) // undefined 5
foo({x: 1}) // 1 5
foo({x: 1, y: 2}) // 1 2
foo() // TypeError: Cannot read property 'x' of undefined
- 參數(shù)默認(rèn)值的位置。通常情況下,定義了默認(rèn)值的參數(shù),應(yīng)該是函數(shù)的尾參數(shù)。因?yàn)檫@樣比較容易看出來,到底省略了哪些參數(shù)。如果非尾部的參數(shù)設(shè)置默認(rèn)值,實(shí)際上這個(gè)參數(shù)是沒法省略的。
// 例一
function f(x = 1, y) {
return [x, y];
}
f() // [1, undefined]
f(2) // [2, undefined])
f(, 1) // 報(bào)錯(cuò)
f(undefined, 1) // [1, 1]
// 例二
function f(x, y = 5, z) {
return [x, y, z];
}
f() // [undefined, 5, undefined]
f(1) // [1, 5, undefined]
f(1, ,2) // 報(bào)錯(cuò)
f(1, undefined, 2) // [1, 5, 2]
- 函數(shù)的
length屬性。指定了默認(rèn)值以后,函數(shù)的length屬性,將返回沒有指定默認(rèn)值的參數(shù)個(gè)數(shù)。也就是說,指定了默認(rèn)值后,length屬性將失真。fn.length 返回形參個(gè)數(shù),arguments.length 返回實(shí)參個(gè)數(shù)。
(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
- 作用域。一旦設(shè)置了參數(shù)的默認(rèn)值,函數(shù)進(jìn)行聲明初始化時(shí),參數(shù)會(huì)形成一個(gè)單獨(dú)的作用域。等到初始化結(jié)束,這個(gè)作用域就會(huì)消失。這種語(yǔ)法行為,在不設(shè)置參數(shù)默認(rèn)值時(shí),是不會(huì)出現(xiàn)的。
var x = 1;
function f(x, y = x) {
console.log(y);
}
f(2) // 2
上面代碼中,參數(shù)y的默認(rèn)值等于變量x。調(diào)用函數(shù)f時(shí),參數(shù)形成一個(gè)單獨(dú)的作用域。在這個(gè)作用域里面,默認(rèn)值變量x指向第一個(gè)參數(shù)x,而不是全局變量x,所以輸出是2。
let x = 1;
function f(y = x) {
let x = 2;
console.log(y);
}
f() // 1
上面代碼中,函數(shù)f調(diào)用時(shí),參數(shù)y = x形成一個(gè)單獨(dú)的作用域。這個(gè)作用域里面,變量x本身沒有定義,所以指向外層的全局變量x。函數(shù)調(diào)用時(shí),函數(shù)體內(nèi)部的局部變量x影響不到默認(rèn)值變量x。
var x = 1;
function foo(x = x) {
// ...
}
foo() // ReferenceError: x is not defined
上面代碼中,參數(shù)x = x形成一個(gè)單獨(dú)作用域。實(shí)際執(zhí)行的是let x = x,由于暫時(shí)性死區(qū)的原因,這行代碼會(huì)報(bào)錯(cuò)”x 未定義“。
var x = 1;
function foo(x, y = function() { x = 2; }) {
var x = 3;
y();
console.log(x);
}
foo()//3
console.log(x); //1
如果將var x = 3的var去除,函數(shù)foo的內(nèi)部變量x就指向第一個(gè)參數(shù)x,與匿名函數(shù)內(nèi)部的x是一致的,所以最后輸出的就是2,而外層的全局變量x依然不受影響。
var x = 1;
function foo(x, y = function() { x = 2; }) {
x = 3;
y();
console.log(x);
}
foo() // 2
x // 1
- rest參數(shù)。
ES6 引入 rest 參數(shù)(形式為...變量名),用于獲取函數(shù)的多余參數(shù),這樣就不需要使用arguments對(duì)象了。rest 參數(shù)搭配的變量是一個(gè)數(shù)組,該變量將多余的參數(shù)放入數(shù)組中。
function add(...values) {
let sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
add(2, 5, 3) // 10
arguments對(duì)象不是數(shù)組,而是一個(gè)類似數(shù)組的對(duì)象。所以為了使用數(shù)組的方法,必須使用Array.prototype.slice.call先將其轉(zhuǎn)為數(shù)組。rest 參數(shù)就不存在這個(gè)問題,它就是一個(gè)真正的數(shù)組,數(shù)組特有的方法都可以使用。下面是一個(gè)利用 rest 參數(shù)改寫數(shù)組push方法的例子。
function push(array, ...items) {
items.forEach(function(item) {
array.push(item);
console.log(item);
});
}
var a = [];
push(a, 1, 2, 3)
注意,rest 參數(shù)之后不能再有其他參數(shù)(即只能是最后一個(gè)參數(shù)),否則會(huì)報(bào)錯(cuò)。
// 報(bào)錯(cuò)
function f(a, ...b, c) {
// ...
}
函數(shù)的length屬性,不包括 rest 參數(shù)。
(function(a) {}).length // 1
(function(...a) {}).length // 0
(function(a, ...b) {}).length // 1
- 嚴(yán)格模式。
ES2016規(guī)定只要函數(shù)參數(shù)使用了默認(rèn)值、解構(gòu)賦值、或者擴(kuò)展運(yùn)算符,那么函數(shù)內(nèi)部就不能顯式設(shè)定為嚴(yán)格模式,否則會(huì)報(bào)錯(cuò)。 - name屬性,返回函數(shù)名。
function foo() {}
foo.name // "foo"
var f = function () {};
f.name // "f"
var fn1 = function fn2(){};
fn1.name // "fn2"
- 箭頭函數(shù)
- 基本用法,ES6 允許使用“箭頭”(
=>)定義函數(shù)。
var f = v => v;
//上面的箭頭函數(shù)等同于
var f = function(v) {
return v;
};
如果箭頭函數(shù)不需要參數(shù)或需要多個(gè)參數(shù),就使用一個(gè)圓括號(hào)代表參數(shù)部分。
var f = () => 5;
// 等同于
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
如果箭頭函數(shù)的代碼塊部分多于一條語(yǔ)句,就要使用大括號(hào)將它們括起來,并且使用return語(yǔ)句返回。
var sum = (num1, num2) => { return num1 + num2; }
由于大括號(hào)被解釋為代碼塊,所以如果箭頭函數(shù)直接返回一個(gè)對(duì)象,必須在對(duì)象外面加上括號(hào),否則會(huì)報(bào)錯(cuò)。
// 報(bào)錯(cuò)
let getTempItem = id => { id: id, name: "Temp" };
// 不報(bào)錯(cuò)
let getTempItem = id => ({ id: id, name: "Temp" });
- 函數(shù)體內(nèi)的
this對(duì)象,就是定義時(shí)所在的對(duì)象,而不是使用時(shí)所在的對(duì)象。 - 不可以當(dāng)作構(gòu)造函數(shù),也就是說,不可以使用
new命令,否則會(huì)拋出一個(gè)錯(cuò)誤。 - 不可以使用
arguments對(duì)象,該對(duì)象在函數(shù)體內(nèi)不存在。如果要用,可以用 rest 參數(shù)代替。 - 不可以使用
yield命令,因此箭頭函數(shù)不能用作 Generator 函數(shù)。 -
this指向的固定化,并不是因?yàn)榧^函數(shù)內(nèi)部有綁定this的機(jī)制,實(shí)際原因是箭頭函數(shù)根本沒有自己的this,導(dǎo)致內(nèi)部的this就是外層代碼塊的this。正是因?yàn)樗鼪]有this,所以也就不能用作構(gòu)造函數(shù)。 - 由于箭頭函數(shù)沒有自己的
this,所以當(dāng)然也就不能用call()、apply()、bind()這些方法去改變this的指向。
// ES6
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
// ES5
function foo() {
var _this = this;
setTimeout(function () {
console.log('id:', _this.id);
}, 100);
}
//轉(zhuǎn)換后的 ES5 版本清楚地說明了,箭頭函數(shù)里面根本沒有自己的this,而是引用外層的this。
- 函數(shù)參數(shù)的尾逗號(hào)。ES2017允許函數(shù)的最后一個(gè)參數(shù)有尾逗號(hào)。這樣的規(guī)定也使得,函數(shù)參數(shù)與數(shù)組和對(duì)象的尾逗號(hào)規(guī)則,保持一致了。
function clownsEverywhere(
param1,
param2,
) { /* ... */ }
clownsEverywhere(
'foo',
'bar',
);
四、數(shù)組的擴(kuò)展
- 擴(kuò)展運(yùn)算符是三個(gè)點(diǎn)(...)。它好比rest參數(shù)的逆運(yùn)算,將一個(gè)數(shù)組轉(zhuǎn)為用逗號(hào)分隔的參數(shù)序列。該運(yùn)算符將一個(gè)數(shù)組變?yōu)閰?shù)序列。
console.log(...[1, 2, 3])
// 1 2 3
console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5
[...document.querySelectorAll('div')]
// [<div>, <div>, <div>]
擴(kuò)展運(yùn)算符后面還可以放置表達(dá)式。
const arr = [
...(x > 0 ? ['a'] : []),
'b',
];
如果擴(kuò)展運(yùn)算符后面是一個(gè)空數(shù)組,則不產(chǎn)生任何效果。
[...[], 1]
// [1]
由于擴(kuò)展運(yùn)算符可以展開數(shù)組,所以不再需要apply方法,將數(shù)組轉(zhuǎn)為函數(shù)的參數(shù)了。
// ES5 的寫法
function f(x, y, z) {
// ...
}
var args = [0, 1, 2];
f.apply(null, args);
// ES6的寫法
function f(x, y, z) {
// ...
}
let args = [0, 1, 2];
f(...args);
取一個(gè)數(shù)組中的最大值。
//es5
Math.max.apply(null,[1,5,2,8]) // 8
//es6
Math.max(...[1,5,2,8])//8
//上面兩種方法等同于
Math.max(1,5,2,8)
擴(kuò)展運(yùn)算符可以用于復(fù)制數(shù)組。
//es5
const a1 = [1, 2];
const a2 = a1.concat();
a2[0] = 2;
a1 // [1, 2]
a2 // [2, 2]
//es6
const a1 = [1, 2];
// 寫法一
const a2 = [...a1];
// 寫法二
const [...a2] = a1;
擴(kuò)展運(yùn)算符用于合并數(shù)組。
// ES5
[1, 2].concat(more)
// ES6
[1, 2, ...more]
var arr1 = ['a', 'b'];
var arr2 = ['c'];
var arr3 = ['d', 'e'];
// ES5的合并數(shù)組
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]
// ES6的合并數(shù)組
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]
擴(kuò)展運(yùn)算符可以與解構(gòu)賦值結(jié)合起來,用于生成數(shù)組。
// ES5
a = list[0], rest = list.slice(1)
// ES6
[a, ...rest] = list
const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest // [2, 3, 4, 5]
const [first, ...rest] = [];
first // undefined
rest // []
const [first, ...rest] = ["foo"];
first // "foo"
rest // []
const [...butLast, last] = [1, 2, 3, 4, 5];
// 報(bào)錯(cuò)
const [first, ...middle, last] = [1, 2, 3, 4, 5];
// 報(bào)錯(cuò)
擴(kuò)展運(yùn)算符還可以將字符串轉(zhuǎn)為真正的數(shù)組。
[...'hello']
// [ "h", "e", "l", "l", "o" ]
擴(kuò)展運(yùn)算符實(shí)現(xiàn)了 Iterator 接口的對(duì)象
let nodeList = document.querySelectorAll('div');
let array = [...nodeList];
-
Array.from()方法用于將兩類對(duì)象轉(zhuǎn)為真正的數(shù)組。
- 第一個(gè)參數(shù):一個(gè)類數(shù)組對(duì)象,用于轉(zhuǎn)為真正的數(shù)組
- 第二個(gè)參數(shù):類似于數(shù)組的
map方法,用來對(duì)每個(gè)元素進(jìn)行處理,將處理后的值放入返回的數(shù)組。 - 第三個(gè)參數(shù):如果
map函數(shù)里面用到了this關(guān)鍵字,還可以傳入Array.from的第三個(gè)參數(shù),用來綁定this。
// NodeList對(duì)象
let ps = document.querySelectorAll('p');
Array.from(ps).forEach(function (p) {
console.log(p);
});
// arguments對(duì)象
function foo() {
var args = Array.from(arguments);
// ...
}
-
Array.of()方法用于將一組值,轉(zhuǎn)換為數(shù)組。這個(gè)方法的主要目的,是彌補(bǔ)數(shù)組構(gòu)造函數(shù)Array()的不足。因?yàn)閰?shù)個(gè)數(shù)的不同,會(huì)導(dǎo)致Array()的行為有差異。
//Array
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]
Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1
- 數(shù)組實(shí)例的
copyWithin方法,在當(dāng)前數(shù)組內(nèi)部,將指定位置的成員復(fù)制到其他位置(會(huì)覆蓋原有成員),然后返回當(dāng)前數(shù)組。也就是說,使用這個(gè)方法,會(huì)修改當(dāng)前數(shù)組。
它接受三個(gè)參數(shù)。
- target(必需):從該位置開始替換數(shù)據(jù)。
- start(可選):從該位置開始讀取數(shù)據(jù),默認(rèn)為 0。如果為負(fù)值,表示倒數(shù)。
- end(可選):到該位置前停止讀取數(shù)據(jù),默認(rèn)等于數(shù)組長(zhǎng)度。如果為負(fù)值,表示倒數(shù)。
這三個(gè)參數(shù)都應(yīng)該是數(shù)值,如果不是,會(huì)自動(dòng)轉(zhuǎn)為數(shù)值。
[1, 2, 3, 4, 5].copyWithin(0, 3)
// [4, 5, 3, 4, 5]
- 數(shù)組實(shí)例的
find()和findIndex()。這兩個(gè)方法都可以接受第二個(gè)參數(shù),用來綁定回調(diào)函數(shù)的this對(duì)象。
- 數(shù)組實(shí)例的
find方法,用于找出第一個(gè)符合條件的數(shù)組成員。它的參數(shù)是一個(gè)回調(diào)函數(shù),所有數(shù)組成員依次執(zhí)行該回調(diào)函數(shù),直到找出第一個(gè)返回值為true的成員,然后返回該成員。如果沒有符合條件的成員,則返回undefined。
[1, 4, -5, 10].find((n) => n < 0)
// -5
[1, 5, 10, 15].find(function(value, index, arr) {
return value > 9;
}) // 10
//find方法的回調(diào)函數(shù)可以接受三個(gè)參數(shù),依次為當(dāng)前的值、當(dāng)前的位置和原數(shù)組。
-
findIndex方法的用法與find方法非常類似,返回第一個(gè)符合條件的數(shù)組成員的位置,如果所有成員都不符合條件,則返回-1。
[1, 5, 10, 15].findIndex(function(value, index, arr) {
return value > 9;
}) // 2
- 數(shù)組實(shí)例的
fill(),fill方法使用給定值,填充一個(gè)數(shù)組。fill方法用于空數(shù)組的初始化非常方便。數(shù)組中已有的元素,會(huì)被全部抹去。fill方法還可以接受第二個(gè)和第三個(gè)參數(shù),用于指定填充的起始位置和結(jié)束位置。
['a', 'b', 'c'].fill(7)
// [7, 7, 7]
new Array(3).fill(7)
// [7, 7, 7]
-
for...of是es6引入的作為遍歷所有數(shù)據(jù)結(jié)構(gòu)的統(tǒng)一的方法。一個(gè)數(shù)據(jù)結(jié)構(gòu)只要部署了Symbol.iterator屬性,就被視為具有 iterator 接口,就可以用for...of循環(huán)遍歷它的成員。也就是說,for...of循環(huán)內(nèi)部調(diào)用的是數(shù)據(jù)結(jié)構(gòu)的Symbol.iterator方法。 - 數(shù)組實(shí)例的
entries(),keys()和values()用于遍歷數(shù)組,它們都返回一個(gè)遍歷器對(duì)象,可以用for...of循環(huán)進(jìn)行遍歷,唯一的區(qū)別是keys()是對(duì)鍵名的遍歷、values()是對(duì)鍵值的遍歷,entries()是對(duì)鍵值對(duì)的遍歷。
for (let index of ['a', 'b'].keys()) {
console.log(index);
}
// 0
// 1
for (let elem of ['a', 'b'].values()) {
console.log(elem);
}
// 'a'
// 'b'
for (let [index, elem] of ['a', 'b'].entries()) {
console.log(index, elem);
}
// 0 "a"
// 1 "b"
- 數(shù)組實(shí)例的
includes()方法返回一個(gè)布爾值,表示某個(gè)數(shù)組是否包含給定的值,與字符串的includes方法類似。
[1, 2, 3].includes(2) // true
[1, 2, 3].includes(4) // false
[1, 2, NaN].includes(NaN) // true
該方法的第二個(gè)參數(shù)表示搜索的起始位置,默認(rèn)為0。如果第二個(gè)參數(shù)為負(fù)數(shù),則表示倒數(shù)的位置,如果這時(shí)它大于數(shù)組長(zhǎng)度(比如第二個(gè)參數(shù)為-4,但數(shù)組長(zhǎng)度為3),則會(huì)重置為從0開始。
沒有該方法之前,我們通常使用數(shù)組的indexOf方法,檢查是否包含某個(gè)值。indexOf方法有兩個(gè)缺點(diǎn),一是不夠語(yǔ)義化,它的含義是找到參數(shù)值的第一個(gè)出現(xiàn)位置,所以要去比較是否不等于-1,表達(dá)起來不夠直觀。二是,它內(nèi)部使用嚴(yán)格相等運(yùn)算符(===)進(jìn)行判斷,這會(huì)導(dǎo)致對(duì)NaN的誤判。
- 數(shù)組的空位指,數(shù)組的某一個(gè)位置沒有任何值。
空位不是undefined,一個(gè)位置的值等于undefined,依然是有值的??瘴皇菦]有任何值,in運(yùn)算符可以說明這一點(diǎn)。
0 in [undefined, undefined, undefined] // true
0 in [, , ,] // false
es5對(duì)空位的處理很不一致,大多數(shù)情況下會(huì)忽略空位。
-
forEach(),filter(),reduce(),every()和some()都會(huì)跳過空位。 -
map()會(huì)跳過空位,但會(huì)保留這個(gè)值 -
join()和toString()會(huì)將空位視為undefined,而undefined和null會(huì)被處理成空字符串。
es6明確將空位轉(zhuǎn)為undefined。 -
Array.from方法會(huì)將數(shù)組的空位,轉(zhuǎn)為undefined,也就是說,這個(gè)方法不會(huì)忽略空位。
Array.from(['a',,'b'])
// [ "a", undefined, "b" ]
- 擴(kuò)展運(yùn)算符(
...)也會(huì)將空位轉(zhuǎn)為undefined。
[...['a',,'b']]
// [ "a", undefined, "b" ]
-
copyWithin()會(huì)連空位一起拷貝。
[,'a','b',,].copyWithin(2,0) // [,"a",,"a"]
-
fill()會(huì)將空位視為正常的數(shù)組位置。
new Array(3).fill('a') // ["a","a","a"]
-
for...of循環(huán)也會(huì)遍歷空位。
let arr = [, ,];
for (let i of arr) {
console.log(1);
}
// 1
// 1
上面代碼中,數(shù)組arr有兩個(gè)空位,for...of并沒有忽略它們。如果改成map方法遍歷,空位是會(huì)跳過的。
entries()、keys()、values()、find()和findIndex()會(huì)將空位處理成undefined。
// entries()
[...[,'a'].entries()] // [[0,undefined], [1,"a"]]
// keys()
[...[,'a'].keys()] // [0,1]
// values()
[...[,'a'].values()] // [undefined,"a"]
// find()
[,'a'].find(x => true) // undefined
// findIndex()
[,'a'].findIndex(x => true) // 0
由于空位的處理規(guī)則非常不統(tǒng)一,所以建議避免出現(xiàn)空位。
五、對(duì)象的擴(kuò)展
- 屬性的簡(jiǎn)潔表示法,ES6 允許直接寫入變量和函數(shù),作為對(duì)象的屬性和方法。這樣的書寫更加簡(jiǎn)潔。
//es6寫法
const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}
// 等同于es5寫法
const baz = {foo: foo};
//es6寫法
const o = {
method() {
return "Hello!";
}
};
// 等同于es5寫法
const o = {
method: function() {
return "Hello!";
}
};
- 屬性名表達(dá)式
JavaScript 定義對(duì)象的屬性,有兩種方法。
// 方法一
obj.foo = true;
// 方法二
obj['a' + 'bc'] = 123;
但是,如果使用字面量方式定義對(duì)象(使用大括號(hào)),在 ES5 中只能使用方法一(標(biāo)識(shí)符)定義屬性。
var obj = {
foo: true,
abc: 123
};
ES6 允許字面量定義對(duì)象時(shí),用方法二(表達(dá)式)作為對(duì)象的屬性名,即把表達(dá)式放在方括號(hào)內(nèi)。
let propKey = 'foo';
let obj = {
[propKey]: true,
['a' + 'bc']: 123
};
表達(dá)式還可以用于定義方法名。
let obj = {
['h' + 'ello']() {
return 'hi';
}
};
obj.hello() // hi
注意,屬性名表達(dá)式與簡(jiǎn)潔表示法,不能同時(shí)使用,會(huì)報(bào)錯(cuò)。
// 報(bào)錯(cuò)
const foo = 'bar';
const bar = 'abc';
const baz = { [foo] };
// 正確
const foo = 'bar';
const baz = { [foo]: 'abc'};
-
Object.is()。ES5 比較兩個(gè)值是否相等,只有兩個(gè)運(yùn)算符:相等運(yùn)算符(==)和嚴(yán)格相等運(yùn)算符(===)。它們都有缺點(diǎn),前者會(huì)自動(dòng)轉(zhuǎn)換數(shù)據(jù)類型,后者的NaN不等于自身,以及+0等于-0。JavaScript 缺乏一種運(yùn)算,在所有環(huán)境中,只要兩個(gè)值是一樣的,它們就應(yīng)該相等。
ES6 提出同值相等算法,用來解決這個(gè)問題。Object.is就是部署這個(gè)算法的新方法。它用來比較兩個(gè)值是否嚴(yán)格相等,與嚴(yán)格比較運(yùn)算符(===)的行為基本一致。
Object.is('foo', 'foo')
// true
Object.is({}, {})
// false
不同之處只有兩個(gè):一是+0不等于-0,二是NaN等于自身。
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
-
Object.assign()。Object.assign方法用于對(duì)象的合并,將源對(duì)象(source)的所有可枚舉屬性,復(fù)制到目標(biāo)對(duì)象(target)。
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
console.log(target); // {a:1, b:2, c:3}
如果只有一個(gè)參數(shù),Object.assign會(huì)直接返回該參數(shù)。
const obj = {a: 1};
Object.assign(obj) === obj // true
由于undefined和null無法轉(zhuǎn)成對(duì)象,所以如果它們作為參數(shù),就會(huì)報(bào)錯(cuò)。
Object.assign(undefined) // 報(bào)錯(cuò)
Object.assign(null) // 報(bào)錯(cuò)
注意:Object.assign可以用來處理數(shù)組,但是會(huì)把數(shù)組視為對(duì)象。
Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]
//把數(shù)組視為屬性名為 0、1、2 的對(duì)象,因此源數(shù)組的 0 號(hào)屬性4覆蓋了目標(biāo)數(shù)組的 0 號(hào)屬性1。
-
Object.keys()。ES5 引入了Object.keys方法,返回一個(gè)數(shù)組,成員是參數(shù)對(duì)象自身的(不含繼承的)所有可遍歷(enumerable)屬性的鍵名。
var obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]
ES2017 引入了跟Object.keys配套的Object.values和Object.entries,作為遍歷一個(gè)對(duì)象的補(bǔ)充手段,供for...of循環(huán)使用。
let {keys, values, entries} = Object;
let obj = { a: 1, b: 2, c: 3 };
for (let key of keys(obj)) {
console.log(key); // 'a', 'b', 'c'
}
for (let value of values(obj)) {
console.log(value); // 1, 2, 3
}
for (let [key, value] of entries(obj)) {
console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}
-
Object.values()。Object.values方法返回一個(gè)數(shù)組,成員是參數(shù)對(duì)象自身的(不含繼承的)所有可遍歷(enumerable)屬性的鍵值。
const obj = { foo: 'bar', baz: 42 };
Object.values(obj)
// ["bar", 42]
返回?cái)?shù)組的成員順序,下面的代碼中,屬性名為數(shù)值的屬性,是按照數(shù)值大小,從小到大遍歷的,因此返回的順序是b、c、a。
const obj = { 100: 'a', 2: 'b', 7: 'c' };
Object.values(obj)
// ["b", "c", "a"]
-
Object.entries()。Object.entries方法返回一個(gè)數(shù)組,成員是參數(shù)對(duì)象自身的(不含繼承的)所有可遍歷(enumerable)屬性的鍵值對(duì)數(shù)組。
const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]
- 對(duì)象的擴(kuò)展運(yùn)算符。
- 解構(gòu)賦值。
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }
由于解構(gòu)賦值要求等號(hào)右邊是一個(gè)對(duì)象,所以如果等號(hào)右邊是undefined或null,就會(huì)報(bào)錯(cuò),因?yàn)樗鼈儫o法轉(zhuǎn)為對(duì)象。
let { x, y, ...z } = null; // 運(yùn)行時(shí)錯(cuò)誤
let { x, y, ...z } = undefined; // 運(yùn)行時(shí)錯(cuò)誤
解構(gòu)賦值必須是最后一個(gè)參數(shù),否則會(huì)報(bào)錯(cuò)。
let { ...x, y, z } = obj; // 句法錯(cuò)誤
let { x, ...y, ...z } = obj; // 句法錯(cuò)誤
注意,解構(gòu)賦值的拷貝是淺拷貝,即如果一個(gè)鍵的值是復(fù)合類型的值(數(shù)組、對(duì)象、函數(shù))、那么解構(gòu)賦值拷貝的是這個(gè)值的引用,而不是這個(gè)值的副本。
let obj = { a: { b: 1 } };
let { ...x } = obj;
obj.a.b = 2;
console.log(x.a.b); // 2
- 擴(kuò)展運(yùn)算符
擴(kuò)展運(yùn)算符(...)用于取出參數(shù)對(duì)象的所有可遍歷屬性,拷貝到當(dāng)前對(duì)象之中。
let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
這等同于使用Object.assign方法。
let aClone = { ...a };
// 等同于
let aClone = Object.assign({}, a);