this是什么?

151 阅读3分钟

嗨,你真的懂this吗?

this是什么?

this是一个指针,指向调用函数的对象。

this的绑定规则:

  1. 默认绑定
  2. 隐式绑定
  3. 显式绑定
  4. new绑定

默认绑定 fun()

默认绑定,在不能应用其它绑定规则时使用的默认规则,通常是独立函数调用。

function sayHi(){
    console.log('Hello,', this.name);//hello,curry或者undefined
}
var name = 'curry';
sayHi();

在调用Hi()时,应用了默认绑定,this指向全局对象(非严格模式下),严格模式下,this指向undefined,undefined上没有this对象,会抛出错误。

隐式绑定 obj.fun()

函数的调用时在某个对象上触发的。

function sayHi(){
    console.log('Hello,', this.name);
}
var person = {
    name: 'YvetteLau',
    sayHi: sayHi
}
var name = 'Wiliam';
person.sayHi();//hello,YvetteLau

需要注意的是:对象属性链中只有最后一层会影响到调用位置。

function sayHi(){
    console.log('Hello,', this.name);
}
var person2 = {
    name: 'Christina',
    sayHi: sayHi
}
var person1 = {
    name: 'YvetteLau',
    friend: person2
}
person1.friend.sayHi();//hello,chirstina

隐式绑定有一个大陷阱,绑定很容易丢失

function sayHi(){
    console.log('Hello,', this.name);
}
var person = {
    name: 'YvetteLau',
    sayHi: sayHi
}
var name = 'William';
var Hi = person.sayHi;
Hi();//hello,william

Hi直接指向了sayHi的引用,在调用的时候,跟person没有半毛钱的关系.

fun()前面如果什么都没有,那肯定不是隐式绑定。

除了上面这种丢失之外,隐式绑定的丢失是发生在回调函数中(事件回调也是其中一种),eg:

function sayHi(){
    console.log('Hello,', this.name);
}
var person1 = {
    name: 'YvetteLau',
    sayHi: function(){
        setTimeout(function(){
            console.log('Hello,',this.name);
        })
    }
}
var person2 = {
    name: 'Christina',
    sayHi: sayHi
}
var name='Wiliam';
person1.sayHi();
setTimeout(person2.sayHi,100);
setTimeout(function(){
    person2.sayHi();
},200);

结果为:

Hello, Wiliam
Hello, Wiliam
Hello, Christina
  • 第一条,setTimeout的回调函数,this使用的是默认绑定,非严格模式下,指向全局对象。
  • 第二条,setTimeout(fn, delay){fun();}, 相当于将person2.sayHi赋值给了一个变量,最后执行了这个变量,此时sayHi中的this就和person2没有关系了
  • 第三条,执行的person2.sayHi()使用的是隐式绑定。

显式绑定

call,apply,bind。

call和apply作用一样,只是传参方式不同。call和apply都会执行对应的函数,二bind方法不会。

function sayHi(){
    console.log('Hello,', this.name);
}
var person = {
    name: 'YvetteLau',
    sayHi: sayHi
}
var name = 'Wiliam';
var Hi = person.sayHi;
Hi.call(person); //Hi.apply(person), hello,yvette

使用显式绑定将this绑定在了person上

但使用显式绑定还是会出现绑定丢失:

function sayHi(){
    console.log('Hello,', this.name);
}
var person = {
    name: 'YvetteLau',
    sayHi: sayHi
}
var name = 'Wiliam';
var Hi = function(fn) {
    fn();
}
Hi.call(person, person.sayHi); //Hello, Wiliam. 

Hi.call(person, person.sayHi)的确是将this绑定到Hi中的this了。但是在执行fn的时候,相当于直接调用sayHi方法(记住: person.sayHi已经被赋值给fn了,隐式绑定也丢了),没有指定this的值,对应的是默认绑定。

new绑定

new的过程:

  1. 创建一个空对象,构造函数中的this指向这个空对象
  2. 这个新对象被执行 [[原型]] 连接
  3. 执行构造函数方法,属性和方法被添加到this引用的对象中
  4. 如果构造函数中没有返回其它对象,那么返回this,即创建的这个的新对象,否则,返回构造函数中返回的对象。
function sayHi(name){
    this.name = name;
}
var Hi = new sayHi('Yevtte');
console.log('Hello,', Hi.name);

输出结果为 Hello, Yevtte, 原因是因为在var Hi = new sayHi('Yevtte');这一步,会将sayHi中的this绑定到Hi对象上。

绑定优先级

new > 显式绑定 > 隐式绑定 > 默认绑定