原题如下:
function func(n,o) {
console.log(o)
return {
func:function(m){
return func(m,n);
}
};
}
var a = func(0);a.func(1);a.func(2);
var b = func(0).func(1).func(2).func(3);
var c = func(0).func(1);c.func(2);
这段代码中出现了三个func函数,所以第一步先搞清楚,这三个fun函数的关系,哪个函数与哪个函数是相同的。
function func(n,o) {
console.log(o)
return {
func:function(m){
//...
}
};
}
先看第一个func函数,属于标准具名函数声明,是新创建的函数,他的返回值是一个对象字面量表达式,属于一个新的object。
这个新的对象内部包含一个也叫func的属性,通过上述介绍可得知,属于匿名函数表达式,即func这个属性中存放的是一个新创
建匿名函数表达式。
注意:所有声明的匿名函数都是一个新函数。
所以第一个func函数与第二个func函数不相同,均为新创建的函数。
函数表达式内部能不能访问存放当前函数的变量。
- 对象内部的函数表达式:
var o={
fn:function (){
console.log(fn);
}
};
o.fn();//ERROR报错
2. 非对象内部的函数表达式:
var fn=function (){
console.log(fn);
};
fn();//function (){console.log(fn);};正确
结论是:使用var或是非对象内部的函数表达式内,可以访问到存放当前函数的变量;在对象内部的不能访问到。
原因也非常简单,因为函数作用域链的问题,采用var的是在外部创建了一个fn变量,函数内部当然可以在内部寻找不到fn后向
上册作用域查找fn,而在创建对象内部时,因为没有在函数作用域内创建fn,所以无法访问。
所以综上所述,可以得知,最内层的return出去的func函数不是第二层func函数,是最外层的func函数。
所以,三个fun函数的关系也理清楚了,第一个等于第三个,他们都不等于第二个。
到底在调用哪个函数?
再看下原题,现在知道了程序中有两个func函数(第一个和第三个相同),遂接下来的问题是搞清楚,运行时他执行的是哪个func
函数?
1. 第一行a
var a = func(0);
a.func(1);
a.func(2);
a.func(3);
/* a.func(1) //一开始func(n=0,o=undefined)!!!!!!理解初始化状态这点非常重要
a.func(m=1)→执行后→func(n=1,o=0)→n赋值为1,o赋值为0.
var a={
func:执行console.log(0),返回:{
func:function(1){
return func(m,1) //由于没有执行所以n不会赋值为undefined,o也不会赋值为1
}
}
} */
/* a.func(2) //一开始func(n=0,o=undefined)!!!!!!理解初始化状态这点非常重要
a.func(m=2)→执行后→func(n=2,o=0)→n赋值为2,o赋值为0.
var a={
func:执行console.log(0),返回:{
func:function(2){
return func(m,2)由于没有执行所以n不会赋值为undefined,o也不会赋值为2
}
}
} */
同理 a.func(3)
可以得知,第一个func(0)是在调用第一层fun函数。第二个func(1)是在调用前一个fun的返回值的func函数,所以:
第后面几个func(1),func(2),func(3),函数都是在调用第二层fun函数。
即:
在第一次调用func(0)时,o为undefined;
第二次调用func(1)时m为1,此时func闭包了外层函数的n,也就是第一次调用的n=0,即m=1,n=0,并在内部调用第一层func
函数func(1,0);所以o为0;
第三次调用func(2)时m为2,但依然是调用a.func,所以还是闭包了第一次调用时的n,所以内部调用第一层的func(2,0);即o为0
第四次同理;
即:最终答案为undefined,0,0,0
2. 第二行b
var b = func(0).func(1).func(2).func(3);//undefined,0,1,2
/*一开始func(n=undefined,o=undefined)*/
/*
var b = func(n=0,o=undefined); 执行后,相对应改变局部变量n和o.
执行console.log(undefined),返回:
var b={
func:执行func(n=1,o=0);console.log(0),返回:{
func:执行func(n=2,o=1);console.log(1),返回:{
func:执行func(n=3,o=2);console.log(2),返回:{
func:function(3){
return func(m,3)由于没有执行所以n不会赋值为undefined,o也不会赋值为3
}
}
}
}
}
*/
先从func(0)开始看,肯定是调用的第一层func函数;而他的返回值是一个对象,所以第二个fun(1)调用的是第二层func函数,后
面几个也是调用的第二层func函数。
即:
在第一次调用第一层func(0)时,o为undefined;
第二次调用 .func(1)时m为1,此时func闭包了外层函数的n,也就是第一次调用的n=0,即m=1,n=0,并在内部调用第一层func
函数func(1,0);所以o为0;
第三次调用 .func(2)时m为2,此时当前的func函数不是第一次执行的返回对象,而是第二次执行的返回对象。而在第二次执行
第一层func函数时时(1,0)所以n=1,o=0,返回时闭包了第二次的n,遂在第三次调用第三层fun函数时m=2,n=1,即调用第一层func
函数func(2,1),所以o为1;
第四次调用 .func(3)时m为3,闭包了第三次调用的n,同理,最终调用第一层func函数为func(3,2);所以o为2;
即最终答案:undefined,0,1,2
3. 第三行c
var c = func(0).func(1); c.func(2); c.func(3);
根据前面两个例子,可以得知:
func(0)为执行第一层func函数,.func(1)执行的是func(0)返回的第二层fun函数,这里语句结束,遂c存放的是func(1)的返回值,
而不是func(0)的返回值,所以c中闭包的也是func(1)第二次执行的n的值。c.func(2)执行的是func(1)返回的第二层func函数,
c.func(3)执行的也是func(1)返回的第二层func函数。
即:
在第一次调用第一层func(0)时,o为undefined;
第二次调用 .func(1)时m为1,此时func闭包了外层函数的n,也就是第一次调用的n=0,即m=1,n=0,并在内部调用第一层func
函数func(1,0);所以o为0;
第三次调用 .func(2)时m为2,此时func闭包的是第二次调用的n=1,即m=2,n=1,并在内部调用第一层func函数func(2,1);
所以o为1;
第四次.func(3)时同理,但依然是调用的第二次的返回值,遂最终调用第一层func函数func(3,1),所以o还为1
即最终答案:undefined,0,1,1