换个思路理解Javascript中的this

在网上不少文章都对 Javascript 中的 this 作了详细的介绍,但大可能是介绍各个绑定方式或调用方式下 this 的指向,因而我想有一个统一的思路来更好理解 this 指向,使你们更好判断,如下有部份内容不是原理,而是一种解题思路。segmentfault

从call方法开始

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

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

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 方法切换函数执行上下文环境的功能。dom

对象方法中的this

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

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

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

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

object-method

从上图中,咱们能够看出getX方法的调用者的上下文是foo,所以getX方法中的 this 指向调用者上下文foo,转换成 call 方法为foo.getX.call(foo)spa

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

构造函数中的this

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

执行 new 若是不考虑原型链,只考虑上下文的切换,就至关于先建立一个空的对象,而后把这个空的对象做为构造函数的上下文,再去执行构造函数,最后返回这个对象。code

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();

creater-method

DOM事件处理函数中的this

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

把函数绑定到DOM事件时,能够看成在DOM上增长一个函数方法,当触发这个事件时调用DOM上对应的事件方法。

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

domelement-method

普通函数中的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();

normal-function

闭包中的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();

这段代码的上下文以下图:
closure-function1

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

所以这段代码咱们关注的部分只有:

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

与普通函数调用同样,建立一个虚拟上下文对象,而后普通函数做为这个虚拟上下文对象的方法当即调用,匿名函数中的 this 也就指向了这个虚拟上下文。
closure-function2

参数中的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);

global-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

图示以下:
judge-this

欢迎关注:Leechikit
原文连接:segmentfault.com

到此本文结束,欢迎提问和指正。写原创文章不易,若本文对你有帮助,请点赞、推荐和关注做者支持。

相关文章
相关标签/搜索