在JavaScript中的函数理解中预解释是一个比较难懂的话题。原理虽然简单,寥寥数言,但其内涵却有深意,精髓难懂。如何在轻松活跃的头脑中将它学会,现在针对我在学习中的一点小窍门给大家分享一下,希望能给大家一些帮助:
万事需遵循“原理”——“预解释”无节操和“this”指向:(可先看例题解析然后结合原理进行学习)
(感谢蕾蕾老师给归纳的预解释无节操原理:)
如果函数传参数则先于以下执行,就相当于在函数私有作用域下var了一个变量;根据作用域原理,私有作用域的权重永远大于父级作用域,当我私有作用域中有某个变量时,而我正好需要他时,私有作用域变量的值就是我所需要的;当私有作用域中没有时,而我有恰好需要它时,我就会沿着作用域链一级级的往上找。此时可得出子级可以用父级的变量,但父级不能访问子级的作用域,打个简单的比喻可能不太贴切,子孙能继承祖宗的财产,但祖宗不能继承子孙的财产,因为祖宗都没了,还怎么继承。
1. 只对等号左边带var的,声明但不定义
2. 自执行函数不会进行预解释,只有,执行到他的时候,声明+定义+调用同步完成
3. 已经声明过的不会进行重复声明,但会重新赋值;
4. return下面的语句虽然不会执行,但会进行预解释;
5. 函数的声明早于变量的声明
6. 在条件判断语句中,无论条件是否成立,都会进行预解释;
不要在条件判断语句中写函数的定义阶段;否则,各大浏览器对其的兼容性不同
this指向:
1. 当一个元素身上的事件被触发的时候,会执行一个函数,函数中的this指向当前这个元素;
2. 自执行函数中的this,永远都是window;
3. 回调函数中的this,一般都是window; setInterval(函数名,1000) ary.sort(function(){})
4. 当函数被调用的时候,看前面是否有".","."前面是谁,this就是谁;
原理阐述篇————实例小窍门篇:
例1:
(function f(){
function f(){ return 1; }
alert (f());
function f(){ return 2; }
})();
解析:此函数为自执行函数,观察函数,注意类似于function fn(){}这样的才是声明函数,像var f=function(){},b=function(){}这样的都不属于声明函数,前者属于变量的声明,
只有像声明函数那样的在函数才会进行预解释,此题中两个为需要声明的函数为同名函数,所以根据‘已经声明过的不会进行重复声明,但会重新赋值’原理得到函数预解释为 function f(){ return 2; }
此时,当函数执行时
alert (f())的结果为2;
例2:
var a=12;
function show(){
alert(a);
a=15;
}
show();
alert(a);
解析:此题为对作用域链的考察,先进行预解释,特别提示变量只有声明,函数既有声明还有定义,预解释了之后代码执行时就会自动跳过不执行,但var a=12,这相当于给变量重新赋值,因为任何变量进行预解释的初始值为
undefined;本题先对变量和函数进行预解释:var a=undefined;
function show(){
alert(a);
a=15;
}
预解释完毕后,代码从上往下的执行,1. a=12; 2. function show(){alert(a);a=15}已经经过预解释不会执行; 3. show()进行函数的调用,alert(a).当前作用域下没
有a,就去父级作用域,a=12; 4.接着执行a=15,任何在函数私有作用域下‘变量‘前面不带var的本身不属于当前作用域域,而是对全局作用域中全局变量的重新赋值,所
以此时相当于把全局变量中的a直接赋值为15; 5.最后在全局作用域下alert(a),只能访问自己的变量。所以a=15;
此题答案为 12,15;
此题引申:
var a=12;
function show(){
alert(a);
var a=15;
}
show();
alert(a);
此时输出的结果为undefined,12,你猜对了吗?切记私有作用域中的变量是以var为基准的,当然如果传参数例外,因为传参就相当于最先var,此题在show函数执行时,因为
里面有var,所以肯定有私有变量所以var a,接着alert(a),大家应该没有忘记任何变量的预解释初始值为undefined,接着执行var a=15,此时相当于重新赋值,这里不用有疑问,因为代码
是从上往下执行,接着继续执行外面全局变量中的alert(a)此时值为12,因为函数私有作用域中并没有改变全局变量的值。
再引申:
var a=12;
function show(a){
alert(a);
var a=15;
}
show(a);
alert(a);
此题结果应为12,12,此题相对于上一题做的改善是对函数进行了传参数处理,上面提过传参相当于最先进行var变量处理,所以在show函数执行时,私有变量a的最开始赋值就为12,在执行就相当于重新赋值
事已至此,咱们再引申一下:
var a=12;
function show(a){
alert(a);
a=15;
}
show(a);
alert(a);
此题结果应该为:12,15,此题主要关键点为全局变量的从新赋值:
那么大家肯定就更能做出这道题了:
alert(a);
var a = 12;
function show(a) {
alert(a);
var a = 15;
alert(a);
}
show(a);
alert(a);
此题结果为undefined,12,15,12
例2:接下来我们来讨论一下变量和函数的一些关系:
function a() {
var b=10;
alert(b);
};
var a;
a();
解析:此题中变量和函数为同名,根据原理知识我们可以知道,函数的声明要优先于变量的声明,所以当同名时以函数优先,所以不难的出此题的答案为10;别急,你以为这么简单就完了,来开始做个小修改
引申一下:
function a() {
var b=10;
alert(b);
};
var a=6;
a();
解析:大家猜猜这道题的结果,如果你对上面的原理理解的不错的话,那么你应该很容易得出此题会报错,a is not defined; 确实函数占用了名称,当接下来执行var a=6,时,大家要注意了,只要变量
有等号就相当于重新赋值,但大家疑问来了,为啥会报错呢,请注意a的名字已经被函数占用,当你进行var a=6,时此时你又把a赋值给6,此时函数本身就犹如孤魂野鬼,没有名字,当最后调用啊a()我去哪找函数a,所以必须的必肯定会报错!!!
例3:
if("a" in window){
var a=15;
}
function fn() {
alert(a)
}
fn()
解析:此题考查的知识点为在条件判断语句中,无论条件是否成立,都会进行预解释,在此题中,大家也应该记住类似于“a” in window 都是正确的,所以起先会进行预解释 var a, 因为条件成立,进入
条件语句中会进行重新赋值,此时a=15;在函数中alert(a),向上级作用域寻找a,结果为15;
引申:
if(!"a" in window){
var a=15;
}
function fn() {
alert(a)
}
fn()
解析:加个“!”,条件肯定为false,不进入条件,但会进行预解释var a,此时a 的值为undefined,
接下来将他们综合起来先来个简单的
var name=‘haha‘;
var age=500;
name=(function(name,age){
arguments[0]=‘xixi‘;
age=age||this.age;
console.log(name,age);
})(name);
console.log(name,age)
解析:看到此题,来吧先进行预解释,1.var name;var age;此时有个注意点,name=...;等号后面的函数不会进行预解释。2.代码从上到下执行,name=‘haha‘;age=500;3.接下来是个关键点,name等于一个自执行函数,先看看它有没有返回值,一个函数执行后若没有返回值则结果都等于undefined,所以此时全局name=undefined,此时自执行函数执行时,函数经过传参,就相当于提前var,所以有私有变量,arguments[0]=‘xixi‘;此时就相当于将函数私有作用域中name=xixi;age=age||this.age,自执行函数的this指向为window,"||"为或的意思,有一项成立就行,那么age=500.第一次console结果应该为xixi,500 4.全局的console我们刚才分析了name富裕没有返回值的自执行函数时为undefined,所以结果为undefined,500;
今天先更新点简单的,明天加上内存释放等问题,通过特殊的小技巧让你事半功倍,做爽预解释,不用画图也能看出答案。。。
未完,待续....