在网上许多文章都对 Javascript 中的 this 做了细致的引见,但大多是引见各个绑定体式格局或挪用体式格局下 this 的指向,因而我想有一个一致的思绪来更好明白 this 指向,使人人更好推断,以下有部份内容不是道理,而是一种解题思绪。
从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();
从上图中,我们能够看出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();
DOM事宜处置惩罚函数中的this
DOMElement.addEventListener('click', function(){
console.log(this);
});
把函数绑定到DOM事宜时,能够看成在DOM上增添一个函数要领,当触发这个事宜时挪用DOM上对应的事宜要领。
DOMElement.clickHandle = function(){
console.log(this);
}
DOMElement.clickHandle();
一般函数中的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();
闭包中的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();
这段代码的上下文以下图:
这里须要注重的是,我们再研讨函数中的 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);
庞杂状况下的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 。
图示以下:
迎接关注:Leechikit
原文链接:segmentfault.com到此本文完毕,迎接发问和斧正。
写原创文章不容易,若本文对你有协助,请点赞、引荐和关注作者支撑。