Javascript 是一种后期绑定语言。事实上,它是很晚的绑定。 this 不仅在编译期间没有绑定,甚至在运行时也没有绑定(就像大多数其他后期绑定语言一样)。在 javascript 中,this 在调用期间被绑定。
绑定规则与大多数其他 OO 语言完全不同,这就是为什么它似乎让很多不熟悉 javascript 的人感到困惑。
基本上,您在代码中使用this 的方式和位置不会影响this 的行为方式(不管它是独立函数、对象文字等),决定this 值的因素是如何调用函数。
规则是:
1 - 当函数作为构造函数调用时,会创建一个新对象并将this 绑定到该对象。例如:
function Foo () {
this.bar = 1; // when called with the new keyword
// this refers to the object just created
}
new Foo().bar;
2 - 当作为对象方法调用时,this 指的是该方法所属的对象。基本上是最后一个点之前的名称。例如:
foo.bar = 1;
foo.baz = function () {
alert(this.bar); // this refers to foo when called as foo.baz()
}
foo.baz();
3 - 如果在任何函数之外使用,或者如果函数没有作为方法调用,this 指的是全局对象。 javascript 规范没有给全局对象命名,只是说存在一个,但对于浏览器,它传统上称为window。例如:
bar = 1;
alert(this.bar); // this refers to the global object
foo = {
bar: this.bar // also global object
}
function foofoo () {
alert(this.bar); // also refers to the global object
}
foofoo();
4 - 在事件处理程序中(例如 onclick 等)this 指的是触发事件的 DOM 元素。或者对于与 DOM 无关的事件,例如 setTimeout 或 XMLHTTPRequest,this 指的是全局对象。例如:
foo.bar = 1;
foo.baz = function () {
alert(this.bar); // this would normally be foo but if this
// function is assigned to an event it would
// point to the element that triggered the event
}
somediv.bar = 2;
somediv.onclick = foo.baz; // clicking on somedive alerts 2 instead of 1
5 - 最后,当使用call() 或apply() 方法调用函数时,this 可以重新分配给任何东西(谷歌“mdn function.prototype.call”) .这样,javascript中的任何对象都可以借用/窃取另一个对象的方法。例如:
cat = {
type: "cat",
explain: function () {
return "I am a " + this.type;
}
}
dog = {
type: "dog"
}
cat.explain.call(dog); // returns "I am a dog"
在现代 javascript 实现中使用Function.bind(),我们现在有了另一条规则:
6 - 函数还可以使用bind() 方法将this 显式绑定到对象。 bind 方法返回函数的一个新实例,其中this 绑定到传递给bind 的参数。例如:
function explain () {
return "I am a " + this.type;
}
dog = {
type: "dog"
}
var dog_explain = explain.bind(dog);
dog_explain(); // returns "I am a dog"
ECMAscript 5 引入了严格模式,它改变了函数中 this 的含义,这些函数不是作为方法调用或通过 call 或 apply 调用的,因此我们必须添加一个新规则:
7 - 在严格模式下,this 不允许引用全局对象(浏览器中的窗口)。因此,当一个函数未被作为方法调用或this 未通过call 或apply 或bind 手动绑定到任何东西时,this 将变为undefined:
"use strict";
function foo () {
return this;
}
foo(); // returns undefined instead of the global object
ECMAscript 6 引入了箭头函数。箭头函数通过提前绑定来改变 this 的行为方式。
8 - 在箭头函数中,this 在函数声明时被绑定。所以this在下面的代码中:
var x = () => {return this};
就好像函数声明如下代码:
var x = function () {return this}.bind(this);
请注意,由于箭头函数中的this 在声明函数时已绑定如果要使用继承,则不能使用箭头函数。这是因为函数中的this 将始终 指向父对象,而永远不会指向子对象。这意味着使用箭头函数进行继承的唯一方法是覆盖父对象中的所有箭头函数。