上题目
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不要慌,这时候你根本不知它是谁,只要跟着代码一步一步执行下去,终会拨云见日。