背景
在js或者ts使用過程中,在方法中使用了this的時候,一個不小心就可能因其引起莫名其妙的錯誤。這通常是this所指向的上下文不是我們所期望的上下文引起的。
規則
在一個方法中(如果是ts,這裏僅限於非lambda表達式定義的方法)有使用this關鍵字,那麼可以按照下面的優先級順序來推斷this指向的是什麼:
如果這個函數是function#bind調用的結果,那麼this指向的是傳入bind的參數
如果函數是以foo.func()形式調用的,那麼this值爲foo
如果是在嚴格模式下,this將爲undefined
否則,this將是全局對象(瀏覽器環境裏爲window)
驗證
var x = {
name: "x",
sayHello: function () {
console.log("_" + this.name);
}
};
x.sayHello();//_x;
var say = x.sayHello;
say();//非嚴格模式_,嚴格模式拋出異常Cannot read property 'name' of undefined
var name = "y";
say();//非嚴格模式_y
var z={
name:"z",
say:x.sayHello
}
z.say();//_z
say.bind(z)();//_z
TS中lambda表達式中的this
看下面的代碼
class Foo {
name = "z";
x = {
name: "x",
sayHello: () => {
let y = {
name: "y",
sayHello: () => {
console.log("hello,I'm " + this.name);
}
}
y.sayHello();
}
};
sayHello(){
this.x.sayHello();
}
}
let foo=new Foo();
foo.sayHello();//z
var t={
name:"t",
x:foo.x
}
foo.sayHello.bind(t)();//z
Foo.prototype.sayHello.bind(t)();//z
全部都輸出z,說明了再TS中,如果方法是lambda表達式定義的,那麼其中的this關鍵字總是指向類實例,而不在乎其引用鏈是怎樣的,這實際上。實際上,如果方法是靜態的,this會指向類本身。
foo.sayHello.bind(t)()和Foo.prototype.sayHello.bind(t)()的方式也沒能改變this的指向,其實這是因爲t.x指向了foo.x,而foo.x.sayHello()中的this指向foo的。
如果我們做下面的修改,就會發現了不一樣了。
let foo2=new Foo();
foo2.name="t";
foo.sayHello.bind(foo2)();//t
Foo.prototype.sayHello.bind(foo2)();//t