javascript this的理解

150 阅读3分钟

关于this

this是javascript中的一个关键字,就是一个指针,指向我们调用函数的对象。

this是基于函数运行时的执行环境绑定的,也就是说this是动态绑定的。

执行环境可以看做是执行上下文,它包含了:

变量作用域(和作用域链条,闭包里面来自外部作用域的变量),函数参数,以及 this 对象的值。

this的指向

this总是指向它的直接调用者

function foo() {
    console.log(this.a);
}
var a = 'apple';
foo();  //  'apple' => window
var a = '123';
var b = {
    a: '456',
    doo:function() {
        console.log(this.a);
    }
};
b.doo(); // '456'  => b
var a = '123';
var b = {
    a: '456',
    c:{
        a: '789',
        doo:function() {
            console.log(this.a);  
        }
    }
};
b.c.doo(); // '789' => c (this指向上一级的对象)
var a = '123';
var b = {
    a: '456',
    doo: function () {
        console.log(this.a);
    }
};
var c = {
    a: '789'
};
var t = b.doo;
c.doo = b.doo;
t();        // '123'  => window (被赋值后,b不是直接调用者)
c.doo();    // '789'  => c
var a = '123';
var b = {
    a: '456',
    doo: function () {
        function woo() {
            console.log(this.a);
        }
        woo();
    }
};
b.doo(); // '123' => window (函数内定义函数,相当于函数调用,指向window)

apply、call和bind改变函数的 this 指向到指定的对象

bind可以覆盖apply和call

function foo() {
  console.log(this.a);
}
var a = 1;
foo.apply({ a: 2 }); // 2
foo.call({ a: 2 }); // 2
foo.bind({ a: 2 })(); // 2

new 绑定

new一个函数时,会自动把this绑定在新对象上,并且会覆盖bind的绑定。以下是创建new的会执行的操作:

  • 创建一个全新的对象。

    var person = {};

  • 这个新对象会被执行[[Prototype]]连接。新对象的_proto_属性指向构造函数的原型对象。

    obj.__ proto __ = Person.prototype;

  • 这个新对象会绑定到函数调用的 this。

    var result = Person.call(obj);

  • 判断返回值类型,如果是引用类型,就返回这个引用类型的对象。如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。

    return typeof result === 'object' ? result : obj;

function foo1() {
    this.a = 1;
}
function foo2() {
    this.a = 2;
    return {
        a: 3
    };
}
var a = new foo1();
var b = new foo2();
console.log(a); // {a: 1}
console.log(b); // {a: 3}
function showThis () {
  console.log(this)
}

showThis() // window
new showThis() // showThis

var boss1 = { name: 'boss1' }

var boss1showThis = showThis.bind(boss1)
boss1showThis() // boss1
new boss1showThis() // showThis

优先级

new > call、apply、bind > 对象调用

箭头函数中的this

箭头函数没有this,通过查找作用域链来决定其值。this绑定的是最近一层非箭头函数的this,否则this的值则被设置为全局对象。

var a = '123';
var b = {
    a: '456',
    doo: () => {
        console.log(this.a);
    }
};
b.doo(); // '123'  => b

setTimeout和setInterval中的this

这两个方法是挂在window对象下的。《JavaScript高级程序设计》第二版中,写到:“超时调用的代码都是在全局作用域中执行的,因此函数中this的值在非严格模式下指向window对象,在严格模式下是undefined”,所以第一个参数的this指向window。可以使用箭头函数自动绑定this。

var a = '123';
var b = {
    a: '456',
    foo: function() {
        setTimeout(function(){
            console.log(this.a)
        }, 1)
    },
    hoo: function(){
        setTimeout(() => {
            console.log(this.a)
        }, 1)
    }
};
b.foo();    //  '123'
b.hoo();    //  '456'

闭包中的this

var a = '123';
var b = {
    a: '456',
    c: function() {
        return function() {
            return this.a
        }
    }
};
b.c()();  //  '123'

闭包返回的函数不属于对象的一个方法,执行这个闭包相当于全局调用这个函数,所以this指向window。