JavaScript中this用法总结

基础知识时间长了也会忘, 虽然可能用对了, 但是又不知道为什么会对? 最后陷入了自我怀疑, this 可以说是js里面的灵魂关键字, 如果不能完全掌握它的原理, 你就不能随心所欲的使用.

DOM中使用this

来, 让我们以一个例子开始:

function doSomething() {
    this.style.color = '#cc0000';
}

这里的this 指向谁? 在Javascript中 this总是指向这个函数执行时的所以者. 如果用一句话来总结this的用法, 应该就是这一句. 如果 doSomething()直接在页面中调用 ,那它的所有者就是这个页面本身, 或者window对象(或者global对象).

如果是在html元素的onclick属性中调用, 那this就指向这个HTML元素

element.onclick = doSomething;

有一个情况要特别注意:

<element onclick="doSomething()">

内联事件中的函数, 不是作为html元素的属性调用的! 它只是对函数的引用! 所以这里调用doSomethind()函数里面的this指向window, 因为它仅仅是找到doSomething然后执行它:

doSomething();

以下几种this指向html元素:

element.onclick = doSomething
element.addEventListener('click',doSomething,false)
element.onclick = function () {this.style.color = '#cc0000';}
<element onclick="this.style.color = '#cc0000';">

以下几种this指向window

element.onclick = function () {doSomething()}
<element onclick="doSomething()">

内联事件中正确用法:

<element onclick="doSomething(this)">

function doSomething(obj) {
    // this is present in the event handler and is sent to the function
    // obj now refers to the HTML element, so we can do
    obj.style.color = '#cc0000';
}

全局环境

全局环境中(任何函数外) this 指向全局对象.
在浏览器中指向 window

函数内部环境

this 取决于函数调用的方式 (先不讨论严格模式))

看下面的例子

function f1(){
    return this;
}

调用f1(), 将返回window对象, 因为直接调用f1()相当于调用window.f1() ,所以这里的 this 指向window对象

如果想要改变this的执行环境,就要用到call or apply方法.

看下面的例子

var obj = { a: 'chestnut'}
var a = 'pinapple'

function hold_what(arg){
    return this.a;
}

hold_what(); // return 'pinapple'
hold_what.call(obj);  // return 'chestnut'
hold_what.apply(obj); // return 'chestnut'

注意的是call或者apply的第一个参数,如果不是一个对象,js会尝试将其转换成对象.

bind方法调用this

调用f.bind(obj)会创建一个新的函数, 但是函数体内的this将永久的被绑定到obj. 无论这个函数在哪里被调用

function f(){
    return this.a;
}

var g = f.bind({a:"azerty"});
console.log(g()); // azerty

var h = g.bind({a:'yoo'}); // bind只生效一次!
console.log(h()); // azerty

var o = {a:37, f:f, g:g, h:h};
console.log(o.f(), o.g(), o.h()); // 37, azerty, azerty

箭头函数内调用this

// 创建一个含有bar方法的obj对象,
// bar返回一个函数,
// 这个函数返回this,
// 这个返回的函数是以箭头函数创建的,
// 所以它的this被永久绑定到了它外层函数的this。
// bar的值可以在调用中设置,这反过来又设置了返回函数的值。
var obj = {
    bar: function() {
        var x = (() => this);
        return x;
    }
};



//作为对比,创建一个obj2
var obj2 = {
    bar: function() {
        var x = function(){ return this };
        return x;
    }
}

var fn = obj.bar();
var fn2 = obj2.bar();

console.log(fn()===obj);     //结果1:  返回true
console.log(fn2()===obj2);   //结果2:  返回false
console.log(fn2()===window); //结果3:  返回true

// 但是注意,如果你只是引用obj的方法,
// 而没有调用它
var fn3 = obj.bar;
// 那么调用箭头函数后,this指向window,因为它从 bar 继承了this。
console.log(fn3()() == window); // true

看结果,体会箭头函数和普通函数的区别. 特别注意这行注释 所以它的this被永久绑定到了它外层函数的this。

作为对象的方法调用this

函数作为对象里的方法调用时, this指向调用该函数的对象.

var o = {
    prop: 37,
    f: function() {
        return this.prop;
    }
};

console.log(o.f()); // logs 37

看下面的例子

var o = {prop: 37};

function independent() {
    return this.prop;
}

o.f = independent;

console.log(o.f()); // logs 37

o.b = {g: independent};
console.log(o.b.g()); // undefined

这里注意 o.b的例子中,this指向o.b.与她的对象o没什么关系.

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

如果该方法存在于一个对象的原型链上,那么this指向的是调用这个方法的对象,就像该方法在对象上一样。原型链这里很有意思. 虽然p没有f方法, 但是在它的原型链中找到了, 但是f是作为p的方法调用的, 所以它的this指向p. 多读两遍这句话, 真的很有意思.

构造函数中的this

当一个函数用作构造函数时(使用new关键字),它的this被绑定到正在构造的新对象。

如果构造函数中手动返回了对象, 那this绑定的默认对象就会被丢弃.

function C2(){
    this.a = 37;
    return {a:38};
}

o = new C2();
console.log(o.a); // logs 38

总结一下

JavaScript是面向对象的/

参考 ppk the this keyword MDN this