15分钟理解JavaScript中的this
沉沙 2018-06-19 来源 : 阅读 1520 评论 0

摘要:在网上很多文章都对 Javascript 中的 this 做了详细的介绍,但大多是介绍各个绑定方式或调用方式下 this 的指向,希望阅读本篇文章以后大家有所收获,帮助大家对JavaScript的理解更加深入。

从call方法开始

call 方法允许切换函数执行的上下文环境(context),即 this 绑定的对象。

大多数介绍 this 的文章中都会把 call 方法放到最后介绍,但此文我们要把 call 方法放在第一位介绍,并从 call 方法切入来研究 this ,因为 call 函数是显式绑定 this 的指向,我们来看看它如何模拟实现(不考虑传入 null 、 undefined 和原始值):


Function.prototype.call = function(thisArg) {
    var context = thisArg;
    var arr = [];
    var result;
 
    context.fn = this;
 
    for (let i = 1, len = arguments.length; i < len; i++) {
        arr.push('arguments[' + i + ']');
    }
 
    result = eval("context.fn(" + arr + ")");
 
    delete context.fn;
 
    return result;
}

   

从以上代码我们可以看到,把调用 call 方法的函数作为第一个参数对象的方法,此时相当于把第一个参数对象作为函数执行的上下文环境,而 this 是指向函数执行的上下文环境的,因此 this 就指向了第一个参数对象,实现了 call 方法切换函数执行上下文环境的功能。


对象方法中的this

在模拟 call 方法的时候,我们使用了对象方法来改变 this 的指向。调用对象中的方法时,会把对象作为方法的上下文环境来调用。

既然 this 是指向执行函数的上下文环境的,那我们先来研究一下调用函数时的执行上下文情况。

下面我门来看看调用对象方法时执行上下文是如何的:


var foo = {
    x : 1,
    getX: function(){
        console.log(this.x);
    }
}
foo.getX();

15分钟理解JavaScript中的this

从上图中,我们可以看出getX方法的调用者的上下文是foo,因此getX方法中的 this 指向调用者上下文foo,转换成 call 方法为foo.getX.call(foo)。

下面我们把其他函数的调用方式都按调用对象方法的思路来转换。


构造函数中的this


function Foo(){
    this.x = 1;
    this.getX = function(){
        console.log(this.x);
    }
}
var foo = new Foo();
foo.getX();

   

执行 new 如果不考虑原型链,只考虑上下文的切换,就相当于先创建一个空的对象,然后把这个空的对象作为构造函数的上下文,再去执行构造函数,最后返回这个对象。

var newMethod = function(func){
    var context = {};
    func.call(context);
    return context;
}
function Foo(){
    this.x = 1;
    this.getX = function(){
        console.log(this.x);
    }
}
var foo = newMethod(Foo);
foo.getX();

   15分钟理解JavaScript中的this

 

DOM事件处理函数中的this

  
DOMElement.addEventListener('click', function(){
    console.log(this);
});

   

把函数绑定到DOM事件时,可以当作在DOM上增加一个函数方法,当触发这个事件时调用DOM上对应的事件方法。


DOMElement.clickHandle = function(){
    console.log(this);
}
DOMElement.clickHandle();

    15分钟理解JavaScript中的this

普通函数中的this


var x = 1;
function getX(){
    console.log(this.x);
}
getX();

   

这种情况下,我们创建一个虚拟上下文对象,然后普通函数作为这个虚拟上下文对象的方法调用,此时普通函数中的this就指向了这个虚拟上下文。

那这个虚拟上下文是什么呢?在非严格模式下是全局上下文,浏览器里是 window ,NodeJs里是 Global ;在严格模式下是 undefined 。


var x = 1;
function getX(){
    console.log(this.x);
}
 
[viturl context].getX = getX;
[viturl context].getX();

   15分钟理解JavaScript中的this

 

闭包中的this


var x = 1;
var foo = {
    x: 2,
    y: 3,
    getXY: function(){
        (function(){
            console.log("x:" + this.x);
            console.log("y:" + this.y); 
        })();
    }
}
foo.getXY();

   

这段代码的上下文如下图:

15分钟理解JavaScript中的this

这里需要注意的是,我们再研究函数中的 this 指向时,只需要关注 this 所在的函数是如何调用的, this 所在函数外的函数调用都是浮云,是不需要关注的。因此在所有的图示中,我们只需要关注红色框中的内容。

因此这段代码我们关注的部分只有:


(function(){
    console.log(this.x);
})();

   

与普通函数调用一样,创建一个虚拟上下文对象,然后普通函数作为这个虚拟上下文对象的方法立即调用,匿名函数中的 this 也就指向了这个虚拟上下文。

参数中的this


var x = 1;
var foo = {
    x: 2,
    getX: function(){
        console.log(this.x);
    }
}
setTimeout(foo.getX, 1000);

   

函数参数是值传递的,因此上面代码等同于以下代码:


var getX = function(){
    console.log(this.x);
};
setTimeout(getX, 1000);

   

然后我们又回到了普通函数调用的问题。


全局中的this

全局中的 this 指向全局的上下文


var x = 1;
console.log(this.x);

    15分钟理解JavaScript中的this

复杂情况下的this


var x = 1;
var a = {
    x: 2,
    b: function(){
        return function(){
            return function foo(){
                console.log(this.x);
            }        
        }
    }
};
 
(function(){
    var x = 3;
    a.b()()();
})();

   

看到上面的情况是有很多个函数,但我们只需要关注 this 所在函数的调用方式,首先我们来简化一下如下:


var x = 1;
(function(){
    var x = 3;
    var foo = function(){
        console.log(this.x);
    }
    foo();
});

   

this 所在的函数 foo 是个普通函数,我们创建一个虚拟上下文对象,然后普通函数作为这个虚拟上下文对象的方法立即调用。因此这个 this指向了这个虚拟上下文。在非严格模式下是全局上下文,浏览器里是 window ,NodeJs里是 Global ;在严格模式下是 undefined 。


总结

在需要判断 this 的指向时,我们可以安装这种思路来理解:

· 判断 this 在全局中OR函数中,若在全局中则 this 指向全局,若在函数中则只关注这个函数并继续判断。

· 判断 this 所在函数是否作为对象方法调用,若是则 this 指向这个对象,否则继续操作。

· 创建一个虚拟上下文,并把this所在函数作为这个虚拟上下文的方法,此时 this 指向这个虚拟上下文。

· 在非严格模式下虚拟上下文是全局上下文,浏览器里是 window ,Node.js里是 Global ;在严格模式下是 undefined 。

图示如下:

 15分钟理解JavaScript中的this

 

 

本文由职坐标整理发布,学习更多的JavaScript相关知识,请关注职坐标WEB前端JavaScript频道!

本文由 @沉沙 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved