在JavaScript中,this的指向是调用时决定的 ,而不是创建时决定的。
对于函数的this,谁调用这个函数,这个函数的this就指向谁。
全局上下文
在全局上下文中,this始终指向全局对象(window)
console.log(window === this) // true
函数上下文
函数直接调用
非严格模式下,this默认指向全局对象window
function f1() { return this; }
f1() === window // true
严格模式下,this为undefined
function f2() {
"use strict";
return this;
}
f2() === undefined //true
call & apply
call 和 apply 都是 Function.prototype 中的方法。
通过call 或 apply 方法调用函数时,其函数内部的this可绑定到 call / apply 方法指定的第一个对象上。后面的参数是函数实参。
function add(c,d){
return this.a + this.b + c + d;
}
let o = {a:1, b:3};
add.call(o,5,7); // 1 + 3 + 5 + 7 = 16
add.apply(o,[10, 20]); // 1 + 3 + 10 + 20 = 34
bind
bind 也在 Function.prototype 上。
通过bind方法绑定后,将返回一个新函数, 这个新函数将永远绑定在其第一个参数对象上,无论其在什么情况下被调用。原函数的this依旧指向调用它的对象。
function f() { return this.a; }
let g = f.bind({a: "wy"}); //g被绑定到了{a: "wy"}上,而f没有
let o = {a:37, f:f, g:g};
console.log(o.f(), o.g()) // 37, wy
对象中的this
对象内部方法的this
对象内部方法的this指向调用这些方法的对象。多层嵌套的对象,内部方法的this指向离被调用函数最近的对象。
原型链中this
原型链中的方法的this仍然指向调用它的对象。
构造函数中this
构造函数的this绑定在新创建的实例对象上。
通过构造函数创建对象的步骤:
- 创建一个空对象
- 为这个新对象准备原型链
- 把构造函数的this指向这个对象
- 给对象赋值(属性,方法)
- 返回this
DOM事件处理函数中的this
对于一个事件监听事件的处理函数 (回调函数),其this指向触发该事件的元素,也就是事件处理程序绑定到的DOM节点。
// 获取文档中的所有元素的列表
var elements = document.getElementsByTagName('*');
// 将bluify作为元素的点击监听函数,当元素被点击时,就会变成蓝色
for (var i = 0; i < elements.length; i++) {
elements[i].addEventListener('click', bluify, false); //bluify的this指向elements[i]
}
内联事件中的this
- 当代码被内联处理函数调用时,它的this指向监听器所在的DOM元素
- 当代码被包括在函数内部执行时,其this指向等同于函数直接调用的情况,即非严格模式指向全局对象window,严格模式下指向undefined
代码
<button onclick = "console.log(this);"></button>
<button onclick = " (function() {console.log(this)})();"></button>
setTimeout & setInterval
延时函数内部的回调函数的this,指向全局对象window。也可以通过bind方法改变这个函数的this指向。
箭头函数中的this
由于箭头函数不绑定this,它会捕获其所在上下文(即定义的位置)的this值,作为自己的this值。
call() / apply() / bind() 方法对于箭头函数来说只是传入参数,对它的 this 毫无影响。
let adder = {
base: 1,
add: function (a) {
let f = (v) => v + this.base; //this指向了adder
return f(a);
},
};
console.log(adder.add(1)); // 1 + 1 = 2
以上的箭头函数都是在方法内部,以非方法的方式使用。
如果将箭头函数当作一个方法使用,作为方法的箭头函数this指向全局window对象,而普通函数则指向调用它的对象。
var obj = {
i: 10,
b: () => console.log(this.i, this),
c: function() {
console.log( this.i, this)
}
}
obj.b(); // undefined window{...}
obj.c(); // 10 Object {...}