因爲在循環中只有一個var,所以會導致閉包中的值是同一個,例如
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 6
對於let而言,for循環本身是一個父作用域,for內部是另一個作用域
for (let i = 0; i < 3; i++) {
let i = 'abc';
console.log(i);
}
// abc
// abc
// abc
const聲明不得改變值,也就是說const在定義時必須初始化
let [foo = true] = [];
foo // true
let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
===
),判斷一個位置是否有值。所以,如果一個數組成員不嚴格等於undefined
,默認值是不會生效的。如果默認值是一個表達式,那麼這個表達式是惰性求值的,即只有在用到的時候,纔會求值。
解構賦值的規則是,只要等號右邊的值不是對象或數組,就先將其轉爲對象。由於undefined
和null
無法轉爲對象,所以對它們進行解構賦值,都會報錯。
let { prop: x } = undefined; // TypeError
let { prop: y } = null; // TypeError
另外,一個容易忽略的地方是,如果參數默認值是變量,那麼參數就不是傳值的,而是每次都重新計算默認值表達式的值。也就是說,參數默認值是惰性求值的。
// 例一
function f(x = 1, y) {
return [x, y];
}
f() // [1, undefined]
f(2) // [2, undefined])
f(, 1) // 報錯
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) // 報錯
f(1, undefined, 2) // [1, 5, 2
注意,rest 參數之後不能再有其他參數(即只能是最後一個參數),否則會報錯。
function push(array, ...items) {
items.forEach(function(item) {
array.push(item);
console.log(item);
});
}
var a = [];
push(a, 1, 2, 3)
由於大括號被解釋爲代碼塊,所以如果箭頭函數直接返回一個對象,必須在對象外面加上括號。
var getTempItem = id => ({ id: id, name: "Temp" });
let propKey = 'foo';
let obj = {
[propKey]: true,
['a' + 'bc']: 123
};
Map 的鍵實際上是跟內存地址綁定的,只要內存地址不一樣,就視爲兩個鍵。這就解決了同名屬性碰撞(clash)的問題,我們擴展別人的庫的時候,如果使用對象作爲鍵名,就不用擔心自己的屬性與原作者的屬性同名。
const map = new Map();
const k1 = ['a'];
const k2 = ['a'];
map
.set(k1, 111)
.set(k2, 222);
map.get(k1) // 111
map.get(k2) // 222
上面代碼中,Promise 新建後立即執行,所以首先輸出的是Promise
。然後,then
方法指定的回調函數,將在當前腳本所有同步任務執行完纔會執行,所以Resolved
最後輸出。
一個使用break語句,跳出for...of
循環的例子。