上题目
function getLength(){
return this.length;
}
function foo() {
this.length = 1;
return (function(){
var length = 2;
return {
length : function(a,b,c){
return this.arr.length;
},
arr : [1,2,3,4],
info : function(){
return getLength.call(this.length);
}
}
})();
}
var result = foo().info();
alert(result);
复制代码
初看题目,由于嵌套了很深,出现了很多个this,不免有些发慌。 但从头到尾看下来,按照函数执行的过程,一点一点在头脑中画出一张脉络图,问题也能迎刃而解。
小伙伴们可以自己先做一下,如果和我一样有些懵,不妨先拿起笔画张图自己梳理下流程。
其实,遇到this的问题不要慌,先记住一条"总则":
this永远指向函数执行时的上下文对象。
也就是说,看到上面代码中那么多this,先别急着看this到底是谁,跟着代码的执行,一步一步往下走,你自然就能知道this是谁了。
第一步:foo():
function foo() {
// 函数foo直接圆括号执行,上下文是window对象,即this指向window。
this.length = 1; // window.length = 1; 给window添加了属性length
return (function(){
// .....
})();
}
复制代码
函数foo执行返回一个自执行函数,看看这个自执行函数的结果是什么:
(function(){
var length = 2;
// 只需要看到这里,自执行函数中没有this, 只有一个私有变量length。
// 自执行函数返回一个对象,也就是foo()的结果就是这个对象
return {
length : function(a,b,c){
return this.arr.length;
},
arr : [1,2,3,4],
info : function(){
return getLength.call(this.length);
}
}
})()
复制代码
第二步: foo().info():
已知foo()的结果是一个对象, 假设叫AA:
{
length : function(a,b,c){
return this.arr.length;
},
arr : [1,2,3,4],
info : function(){
return getLength.call(this.length);
}
}
复制代码
那么foo().info(), 函数info中的this指向上面这个对象AA:
function info(){
// this.length即对象AA的属性length, 是一个函数
return getLength.call(this.length);
}
复制代码
第三步:getLength.call(this.length):
这一步相当于让函数getLength执行,并将函数内部的this指向了call的参数,即this.length:
function getLength(){
// this指向被call修改了,指向 "this.length" 即对象AA的length属性(length是个函数)
// 所以这里的this其实是个函数,函数的length就是形参的个数,length函数有三个形参,所以这里返回3
return this.length;
}
复制代码
所以,
var result = foo().info();
alert(result); // 弹出3
复制代码
小结
这道题目用到this的规律其实不算多,但强调了一个点:this永远指向函数执行时的上下文对象。 所以,看题目时遇见那么多this不要慌,这时候你根本不知它是谁,只要跟着代码一步一步执行下去,终会拨云见日。