# 简介
在绝大数情况下,函数的调用方式决定了this值。this不能在执行期间被复制,并且在每次函数被调用时this的值也可能会不同。
- this的值表示当前执行环境对象,而与声明环境无关,所以this代表的对象要等函数运行。类似定义函数时的参数列表,只有在函数调用时才传入真正的对象。
- this 关键字虽然会根据环境变化,但它始终代表的是调用当前函数的对象
# 全局环境
无论是否在严格模式下,在全局执行环境中(在任何函数体外部),this都指向全局对象
console.log(this === window); // true
# 函数环境中的this
在函数内部, this的值取决于函数被调用的方式
# 函数环境中的this
在非严格模式下, this 的值不是由该调用设置的, 所以this 的值默认指向全局对象
function fn() {
return this;
}
fun() === window;
在严格模式下,this将保持他进入执行环境时的值,所以this将会默认为undefined
function f2() {
'use strict'
return this;
}
fn2() === undefined
在严格模式下,如果 this 没有执行环境定义,那它将保持为undefined。
如果想把 this 的值从一个环境传到另一个,就要用 call 或者 apply 方法
// 将一个对象作为call和apply的第一个参数,thsi将会被绑定到这个对象
var obj = {a: 'Custom'};
var a = 'Global';
function whatsThis(arg) {
return this.a;
}
whatsThis(); // Global
whatsThis.call(obj); // Custom
whatsThis.apply(obj); // Custom
当一个函数在其主体中使用this关键字时,可以使用函数继承自 Function.prototype 的call或apply方法将 this 值绑定到调用中的特定对象。
使用call 和apply 函数的时候,如果传递给 this 的值不是一个对象,JavaScript会尝试使用内部 toObject 操作 将其转换为对象。
function bar() {
console.log(Object.prototype.toString.call(this));
}
bar.call(7); // [object Number]
# bind方法
ES5引入了 Function.prototype.bind。调用f.bind(someObject)会创建一个与f 具有相同函数体和作用域的函数,但是在这个新函数中,this将永久的被绑定到了bind的第一个参数,无论这个函数是如何被调用的
function f() {
return this.a;
}
var g = f.bind({ a: 'azerty' });
console.log(g()); // azerty;
var h = g.bind({ a: 'yoo' }); // bind只生效一次,所以此处bind无效
console.log(h()); // azerty
var o = { a: 37, f: f, g: g, h: h }
console.log(o.f(), o.g(), o.h()); // 37, azerty, azerty
# 剪头函数
在剪头函数中,this与普通函数的指向不同,它与封闭词法环境的this保持一致。在剪头函数中,this指向创建时所在的环境,这同样适用于在其他函数内所创建的剪头函数;在普通函数中,this指向执行时的环境
剪头函数被调用的时候,不会自动绑定一个this对象。剪头函数没有自己的this,它的this都是捕获其所在上下文的this值
举例子
var foo = () => this;
console.log(foo() === window); // true
// 作为对象的一个方法调用
var obj = { foo: foo }
console.log(obj.foo() === window); // true;
// 使用call来设定this
console.log(foo.call(obj) === window); // true;
// 使用bind 设定this
foo = foo.bind(obj);
console.log(foo() === window); // true;
第二个🌰
// bar返回一个函数,这个函数返回this
// 这个返回的函数是以剪头函数创建的
// 所以它的this被绑定到了外层函数的this
var obj = {
bar: function() {
var x = () => this;
return x;
}
}
//作为obj对象的一个方法来调用bar,把它的this绑定到obj。将返回的函数的引用复制给fn
var fn = obj.bar();
//直接调用fn而不设置this
//通常不适用箭头函数的情况,默认为全局对象
//若在严格模式则为undefined
console.log(fn() === obj); //true
//如果只是引用obj的方法,而没有调用它
var fn2 = obj.bar; //fn2 = function() {var x = (() => this); return x;}
//调用箭头函数后,this指向window,因为它从bar继承了this
console.log(fn2() === window); /true
# 作为对象的方法
当函数作为对象里的方法被调用时,他们的this是调用该函数的对象
var o = {
prop: 37,
f: function() {
return this.prop;
}
}
console.log(o.f()); // 37;
函数时从o的f成员调用才是重点。
同样,this的绑定只受最靠近的成员应用的影响
o.b = { g: o.f, prop: 42};
console.log(o.b.g()); // 42
这个栗子说明,这与它是对象o的成员没有什么关系,最靠近的引用才是最重要的。
# 原型链中的this
对于在对象原型链上某处定义的方法,同样的概念也使用。如果该方法存在于一个对象的原型链上,那么this指向的是调用这个方法的对象,就像是该方法在对象上一样
var o = {
f: function() {
return this.a + this.b;
}
}
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5
在这个栗子中,对象p没有属于自己的属性,它的f属性继承自它的原型。虽然在对于f的查找过程中,最终是在o中找到的f属性,但是查找股从横首先从p.f的引用开始,所以函数中的this指向p。也就是说f是作为p的方法调用的,所以它的this指向了p。这是JavaScript的原型继承中的一个有趣的特征。
# getter与setter中的this
同样的概念适用于,当函数在一个getter或者setter中被调用。用作getter或setter的函数都会把this绑定到设置或获取属性的对象。
function sum() {
return this.a + this.b + this.c;
}
var o = {
a: 1,
b: 2,
c: 3,
get average() {
return (this.a + this.b + this.c) / 3;
}
};
Object.defineProperty(o, 'sum', {
get: sum, enumerable: true, configurable: true
})
console.log(o.average, o.sum); //logs 2, 6
# 作为构造函数
当一个函数用作构造函数时(使用new关键字),它的this被绑定到正在构造的新对象。
虽然构造器返回的默认值是this所指的对象,但是也可以手动地返回其他的对象(如果返回值不是一个对象,则返回this对象)。
function C() {
this.a = 37;
}
var o = new C();
console.log(o.a); //logs 37
function C2() {
this.a = 37;
return {a:38};
}
o = new C2();
console.log(o.a); //logs 38
在这个栗子中,在调用构造函数的过程中,手动的设置了返回对象,所以默认对象就被丢弃了。this.a = 37;这条语句虽然执行了,但是对于外部没有任何影响。
# 作为一个DOM事件处理函数
当函数被用作事件处理函数时,它的this指向触发事件的元素。
# 作为一个内联事件处理函数
当代码被内联on-event处理函数调用时,它的this指向监听器所在的DOM元素:
<button onclick="alert(this.tagName.toLowerCase());">
Show this
</button>
这个栗子的alert会显示button。只有外层代码中的this是这样设置的:
<button onclick="alert((function() {return this})());">
Show inner this
</button>
在这种情况下,没有设置内部函数的this,所以它指向window/global对象,非严格模式下,调用的函数未设置this时指向的默认对象。