- 函數體內的
this
對象,就是定義時所在的對象,而不是使用時所在的對象。
請看下面這個例子:
var a = {
x: 'haha',
f: () => {
console.log(this.x);
}
};
var b = {
x: 'heiehi'
};
a.f(); // undefined
a.f.call(b); // undefined
輸出undefined
是因為箭頭函數定義時所在對象為global
對象,沒有x屬性(是在global
對象的環境下定義的,即定義時this
指向global
,而不是a對象,這里容易混淆)。該函數在定義時,this
就被綁定了定義時的所在對象。
再看一個例子:
function get() {
return {
f: () => {
console.log(this.x);
}
}
};
var b = {
x: 'heiehi'
};
get.call(b).f(); // heihei
// 或
var b = {
x: 'heiehi',
get: function () {
return {
f: () => {
console.log(this.x);
}
}
}
};
b.get().f(); // heihei
這里get函數運行時的this
指向b,f定義時this
綁定了b。
PS: 在node中,運行一個js程序:
//test.js
function a() {
console.log(this === global ? 'global' : this);
}
console.log(this); // {}
console.log(this === global); // false
a(); // global
a.call({x:1}); // {x:1}
可見與瀏覽器環境不同,全局環境下代碼執行時的this
指向一個空對象,全局環境下調用函數,會將global
對象傳給this
。而在瀏覽器環境中(global
為window
對象),全局環境下的this
即指向window
。
- 不可以使用
arguments
對象,該對象在函數體內不存在。如果要用,可以用Rest參數代替。
請看下面例子:
function a() {
return () => {
console.log(arguments);
}
}
a(1,2,3)(5,6); // {'0':1,'1':2,'2':3}
箭頭函數內訪問arguments
時,訪問的是外層代碼塊的arguments
。
再看一個例子:
//test.js
var a = 0;
// arguments = {};
setTimeout(() => {
console.log(a);
if (++a<10) {
setTimeout(arguments.callee, 500);
}
}, 500); // 1,1,1,1,1.................無限
在node環境中,上述代碼里的arguments.callee
指向node運行test.js文件時,用來包裹代碼的函數。因此以上所有代碼就會不斷重復執行
在瀏覽器環境中,會報出arguments undefined
的錯誤。因為瀏覽器運行js代碼不像node會包個函數在外面,所以箭頭函數中的代碼運行時,直接找外層代碼塊中的arguments,不在函數中所以就找不到了。
這時如果把arguments = {}
這句去注釋,則不會報錯。看來箭頭函數運行時查找arguments
也和查找普通變量一樣。
總結:
this
、arguments
在箭頭函數內的調用過程:箭頭函數運行時,引擎不定義這倆變量,這樣就會沿著作用域鏈向上查找,找到了箭頭函數定義時的this
與arguments
變量(這句話可能不嚴謹,還不了解js引擎,大概意思就是箭頭函數根本沒有自己的this
,導致內部的this
就是外層代碼塊的this
)。
這也是為什么箭頭函數不能作為構造函數的原因。