this指向

209 阅读3分钟

在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绑定在新创建的实例对象上。

通过构造函数创建对象的步骤:

  1. 创建一个空对象
  2. 为这个新对象准备原型链
  3. 把构造函数的this指向这个对象
  4. 给对象赋值(属性,方法)
  5. 返回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

  1. 当代码被内联处理函数调用时,它的this指向监听器所在的DOM元素
  2. 当代码被包括在函数内部执行时,其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 {...}