this 指向

101 阅读2分钟

this 的指向有哪些?

面试高频指数:★★★★★

函数的调用方式决定了 this 的值(运行时绑定)。this 不能在执行期间被赋值,并且在每次函数被调用时 this 的值也可能会不同。

this 的指向有以下七种:

全局上下文

this 指向全局对象

console.log(this === window); // true
a = 37;
console.log(window\.a); // 37

函数上下文

this 指向取决于函数被调用的方式:

  • 作为对象的方法调用,this 指向该对象
  • 作为普通函数调用
    • 严格模式下,指向全局对象,浏览器中就是 window
    • 非严格模式下,为 undefined
  • call、apply、bind 调用,this 指向绑定的对象
  • 作为构造函数调用,如使用 new,this 指向新的对象
function f1(){
return this;
}
//在浏览器中:this 指向全局对象 window
f1() === window;

//在 Node 中:this 指向 global
f1() === global;

// 严格模式下:this 指向 undefined
function f2(){
"use strict";
return this;
}

f2() === undefined; // true

// call 方法:this 指向传入的指定对象 o
function add(c, d) {
return this.a + this.b + c + d;
}
var o = {a: 1, b: 3};
add.call(o, 5, 7); // 16

类上下文

this 指向类。在类的构造函数中,this 是一个常规对象。类中所有非静态的方法都会被添加到 this 的原型中:

class Car {
    constructor() {
    // 使用 bind() 方法改变 this 指向
        this.sayBye = this.sayBye.bind(this);
    }
    sayHi() {
        console.log(`Hello from ${this.name}`);
    }
    sayBye() {
        console.log(`Bye from ${this.name}`);
    }
    get name() {
        return 'Ferrari';
    }
}

class Bird {
    get name() {
        return 'Tweety';
    }
}

const car = new Car();
const bird = new Bird();

// this 指向调用者
car.sayHi(); // Hello from Ferrari
bird.sayHi = car.sayHi;
bird.sayHi(); // Hello from Tweety

// bind() 方法改变了 this 指向,this 指向类 Car
bird.sayBye = car.sayBye;
bird.sayBye();  // Bye from Ferrari

箭头函数

this与封闭词法环境的 this 保持一致。在全局代码中,它将被设置为全局对象。

var window = this;
var foo = (() => this);
console.log(foo() === window); // true

原型链中的 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

作为一个 DOM 事件处理函数

当函数被用作事件处理函数时,它的 this 指向触发事件的元素。

function bluify(e) {
console.log(this === e.currentTarget); // true
this.style.backgroundColor = 'blue'
}

// 获取 id 为 test 的 button
let testBtn = document.getElementsById('test');

// 将 bluify 作为元素的点击监听函数,当元素被点击时,就会变成蓝色
testBtn.addEventListener('click', bluify, false);

getter 与 setter 中的 this
用作 getter 或 setter 的函数都会把 this 绑定到设置或获取属性的对象。

var o = {
    a: 1,
    b: 2,
    get sum() {
        return (this.a + this.b);
    }
};

console.log(o.sum); // 输出 3

小练习

给出下面代码的输出结果:

var length = 10;
function fn() {
    return this.length + 1;
}
var obj = {
    length: 5,
    test1: function() {
        return fn();
    }
};
obj.test2 = fn;

console.log(obj.test1.call()); // (1)
console.log(obj.test1()); // (2)
console.log(obj.test2.call()); // (3)
console.log(obj.test2()); // (4)

答案:输出如下:

1 处为:11, this 指向 window, 因为 call 方法没有执行具体要绑定的对象。 2 处为:11,this 指向 window,返回的 fn 函数的 this 指向 window 3 处为:11,原因同 1 处 4 处为: 6,this 指向 obj,此处函数作为对象 obj 的方法调用