快速理解JavaScript中this的用法与陷阱

this是 JS 这门语言的魅力之一——灵活方便又难以捉摸,即便是有经验的程序员,若是不仔细也有可能搞错,关于this的用法也成为许多公司的经典面试题。程序员

若是你写过 Java ,你可能接触过this——通常指向当前对象,实际上,这时候this的含义已经肯定了,由于Java属于编译期绑定,而JS属于运行期绑定,因此致使this的含义在运行过程当中可能有多种变化。面试

进一步说,this和它声明环境无关,而彻底取决于他的执行环境。务必牢记这句话。app

//读如下代码以前,必须先阅读《哈利·波特》原著。(笑)

var name = '罗恩';
var aaa = {
    name: '哈利',
    say: function () {
        console.log(this.name);
    }
}

var bbb = {
    name: '赫敏',
    say: aaa.say
}

var ccc = aaa.say;

aaa.say();    //哈利
bbb.say();    //赫敏
ccc();        //罗恩

咱们看第一行,aaa.say()调用的是aaa对象自己的say()方法,此时this指代的是aaa对象自己,因此此时输出固然就是aaa对象的name属性值。异步

第二行,bbb.say();输出赫敏必定和JS新手们的常识不相符,其实只要牢记“this取决于执行环境”就能想明白。bbb对象是怎么声明自身的say方法的呢?它只是把aaa对象的say方法引用过来,注意,引用的是一个方法而非一个对象,而aaa.say存储的是一个匿名函数,因此这种写法和如下代码并无什么区别。函数

var bbb = {
    name: '赫敏',
    say: function () {
        console.log(this.name);
    }
}

第三行的ccc()是在最外层执行,也就是在全局对象window下。因此ccc()执行的时候this指代的就是window对象。而在window对象下声明了name属性,就至关于window.name = '罗恩',输出的固然就是罗恩this

固然,也有特殊状况,那就是 setTimeout 和 setInterval 。
我把开头的aaa对象的声明改为:code

var aaa = {
    name: '哈利',
    getName: function () {
        setTimeout(function(){
            console.log(this.name);
        },100)
    }
}

仅仅是在console.log(this.name)外面套了一个setTimeout,猜猜原来三行的输出会是什么?对象

答案:3个罗恩
也就是说,三次this,指代的都是window对象。ip

关于为何会这样,我这里暂时不详细展开,由于涉及到JS异步回调的知识,若是你仅仅想快速熟悉this的用法,那么只要记住这个特殊状况便可。这个知识点曾经是阿里仍是小米的面试题。get

显然,三个罗恩不是我想要的,毕竟韦斯莱夫人的孩子已经够多了。那么咱们只需稍微改写一下这个方法:

getName: function () {
        //在setTimeout外存储this指代的对象
        var that = this;
        setTimeout(function(){
            //this.name变成了that.name
            console.log(that.name);
        },100)
    }

输出就又正常了。

显然,that并非一个关键字,只是一个你们解决这种状况时约定俗成的名字。若是你愿意,也能够叫thatGuy。固然,考虑到可能会有其余人维护你的代码,仍是用that比较好。

之因此写这篇文章,是为了我下一篇文章作铺垫:
《快速理解JavaScript中apply()和call()的用法》敬请期待~~

相关文章
相关标签/搜索