笔试点滴类记录一些笔试遇到的题目,不一定有难度,但一定有所收获与启发。
一、关于闭包与this的理解
1、题目:
编写一个函数mul,使下面成立:
alert(mul(3)(4)(5));//提示60
alert(mul(2)(4)(5));//提示40
分析:
结果为3个数的累积,且是用三个函数分次输入这3个数。要使后面的函数能使用前面的函数的参数,可采用典型的闭包实现。
当时的具体实现:(测试正确)
function mul(numb1){
this.n1=numb1;
return function(numb2){
this.n1=n1;
this.n2=numb2;
return function(numb3){
return n1*n2*numb3;
}
}
}
反思:
this的理解:
最初理解:因为之前对闭包及this的含义理解不够透彻,所以每个函数中我都存储了该函数的返回函数将用到的值,如mul中以n1存储了numb1,第一个匿名函数中使用n1与n2存储了第一个mul函数的n1与新输入的numb2,第二个匿名函数中因为没有再返回引用参数的函数,所以直接通过闭包使用参数返回结果。
修正理解:最初理解存在错误,根本在于对this的误解,认为mul函数中的this指mul对象自身,而return语句中的this指返回的函数体构建的对象,如此看来mul函数体中this有三个身份(mul函数对象,第一个匿名函数对象,第二个匿名函数对象),而实际上mul中所有的this,都只指mul函数对象。验证如下:
function mul(numb1){
this.n1=numb1;//标记1
return funtion(numb2){
alert(this.n1);//调用mul函数后,此处将提示与numb1相同的值,说明此处this与标记1出this指同一个对象,mul函数对象。
}
}
闭包的理解:
当前某个函数正在使用的变量,都不会被释放,从而可实现保护变量的目标和使用先输入的参数(即此题中)。前提是正在使用该变量的函数,须属于该变量所属函数。实例讲解:
<script>
var n=10;//全局变量
function test(numb){
var n=numb;
this.method=function(){alert(n);}//此处实现了闭包,提示的是test函数中的n,因为method函数与numb变量同属于test函数。
}
function method(){alert(n);}//显然提示的是全局变量的n
<script>
当初设计的改进:(测试正确)
function mul(numb1){ //因为返回的函数中使用了numb1,所以形成了闭包,numb1不会被释放,即使作为形参
return function(numb2){ //同理
return function(numb3){
return numb1*numb2*numb3;
}
}
}
感悟:如果非要使用变量存储形参,最好使用私有变量,即通过var声明,而非使用this,这也是闭包达到保护变量的目的。
二、this与对象
此处所讨论对象只指函数对象与JSON 对象。
1、this与函数对象
this用在函数体中,声明或使用公有属性或方法。
function test(){
var privateV=10;
this.publicV=20;
var privateMethod=fucntion(){ //注解1
alert(privateV); //私有方法可使用私有属性变量
alert(typeof publicV+typeof publicV);//显示undefined,即私有方法不能引用公有属性(包括公有变量与公有方法)
};
this.publicMethod1=function(){
alert(privateV); //公有方法使用私有属性变量,不能通过this调用。提示10
alert(this.publicV); //公有方法使用公有属性变量,只能通过this调用。提示20
};
this.publicMethod2=function(){
this.publicMethod1(); //公有方法使用公有方法,只能通过this调用。
privateMethod(); //公有方法使用私有方法,不能通过shis调用。
}
}
小结:
将函数中this声明的变量与方法理解为属性变量与属性方法,引用它们只能通过this。私有方法不能引用属性变量与属性方法,属性方法能引用属性变量、私有变量、属性方法、私有方法。(但有一个例外,即直接return的方法,该方法体中访问上层函数通过this声明的属性或方法可不通过this,直接使用,这也正是题目1的最初设计结果正确的重要原因)
注解1:
以var 声明方式声明的私有函数,其内部使用的this并非指该私有函数所属的对象,而是指全局对象(window)。如:
var n=10;
function test(){
this.n=20;
var method1=function(){ alert(this.n);} //1处
this.method2=function(){ method1();}
}
var t=new test();
t.method2();//将提示10,而非20,var声明的函数的this并不指该函数所属的对象(此例中即t)。
另外,对于全局属性,var与this声明方式没有区别,都可直接使用(没有被局部变量覆盖时)或通过this调用。所以此例中this.n调用了全局变量n。
此外,还应注意,下面两种方法也都都形成了闭包:
var n=10;
//第一种
function test(){
var n=20;
return function(){alert(n);}
}
//第二种,与上一种本质一样
function test2(){
var n=30;
var method=function(){alert(n);}
return method;
}
var t1=test();
t1();//提示20
var t2=test2();
t2();//提示30
2、this与JSON 对象
比较:
var x=10;
var test={
x:20,
method:function(){alert(x)}
};
test.method();//提示10
var test2={
x:30,
method:function(){alert(this.x)}
}
test2.method();//提示30
小结:
JSON 对象的方法使用自身的属性变量必须通过this。
JSON 对象方法与函数对象方法的另一个区别:能否复制
var x=10;
var test2={
x:20,
method:fucntion(){alert(this.x)}
};
test2.method();//提示20
var t=test2.method;
t();//提示10
//所以JSON 对象调用自身属性变量并未形成闭包
//与之对比的函数对象的属性方法
function test3(){
var x=30;
this.method=function(){x++;alert(x);}
}
var t3=new test3();
t3.method(); //提示31
var t=t3.method;
t(); //提示32
t3.method(); //提示33。说明一个函数对象的某个方法至始至终只有自身一个,没有复制品。
小结:
JSON 对象的属性方法与属性变量未形成闭包,实际上也不需要,因为JSON 对象就是为了能直接使用属性方法与属性变量的。JSON 对象的方法可“复制”给其它变量而不影响该JSON 对象的属性变量,但形成闭包的函数对象的方法不能如此(即它是将自身给了某个变量,而非一个复制品)。