这篇文章写的是关于一个讨论的一些东西,算是整理和学习!。讨论来源一个强大的前端群,群主 司徒正美(博客:http://www.cnblogs.com/rubylouvre/ 微博:http://weibo.com/jslouvre?topnav=1&wvr=5&topsug=1)发了这样一个代码片段:
先说说我自己第一反应的答案吧:
1 function a(){} 2 undefined 3 [1,2,3] 4 ee 5 444 6 6
先说说我自己一开始最基本的理解吧:
在函数中变量的声明会被提前,但赋值会到代码所在行才会进行,另外函数名只是一个指针而不是绑定的,是可以修改的,因为函数本身就是一个对象(可以参考:http://www.cnblogs.com/zhouyongtao/archive/2012/11/19/2776776.html)。
a,aa变量的声明被提到代码的最前面此时值为undefined,但接着a指向了一个函数,故console.log(a)输出为function a(){},而console.log(aa)输出undefined,console.log(arguments)输出就为:[1,2,3]。
然后a,aa,arguments均被赋值,故console.log(a)输出为:ee,console.log(aa)输出为:444,console.log(arguments)输出为:6。
事情到这就真的完了吗?事实上远远没有完。
有人说:“这里面参数的优先级低于变量声明和函数声明,所以一直被派上用处”。还有人说:“知识点:函数,形参,变量同名的话,通俗理解,函数>形参>变量”。
那么函数声明,变量声明,赋值,如果有同名情况出现和这几者之间到底是谁优先呢?或者说谁覆盖谁?
后来大佬又发话了。
看完不能很好的理解,感觉抽象了。后来又有人贴出这样一篇正妹的文章:http://chauvetxiao.com/bo-blog/read.php?1
其中有几个demo很不错,引用过来理解和验证一下大佬所说的东西还是特别有帮助的。(下面的demo大多数出自于正妹的文章)
fu();//2 var fu=function(){ console.log(1); }; function fu(){ console.log(2); } fn();//1
这个demo和上面那个例子验证了大佬的第一句话“变量声明,当变量声明遇到VO中已经有同名的时候,不会影响已经存在的属性”。
第二句和第三句就不解释了。因为从上面第一例子已经看得出来了。
但第四句后半句觉得不是很对。疑问来源于这样的两个demo
1 function a(){ 2 console.log('2'); 3 } 4 var a; 5 console.log(a);//function a(){console.log('2);}
1 function a(){ 2 console.log(a); 3 var a=2; 4 } 5 a();//undefined
那么在函数内部和全局环境中,是谁覆盖谁?其实第一个例子中,声明与变量声明是先后进行,而第二例子中是函数声明先进行,调用函数函数时再有变量的声明。所以前者输出的正如大佬所说是function a(){consoleo.log('2')},后者是undefined。
另外也发现一点东西,js中全局变量的声明并不会提前。断点调试就能发现在window对象并没有这样一个属性。
1 console.log(num);//错误 2 num=2;
这样的话,这个例子也比较容易弄懂。
1 var num1 = 1; 2 3 function fn(num3){ 4 5 console.log(num1); //output undefined 6 7 console.log(num3); //output 4 8 9 console.log(num4); //throw error “num4 is not defined” 10 11 console.log(num2); //throw error “num2 is not defined” 12 13 var num1 = num4 = 2; 14 15 num2 = 3; 16 17 var num3= 5; 18 19 } 20 21 fn(4);
如果理解了上面的东西,这样的demo也很容易搞懂了。
1 function fn(t){ 2 3 t(); 4 5 function t(){ 6 7 console.log(2); 8 9 } 10 11 var t = function(){ 12 13 console.log(3); 14 15 } 16 17 } 18 19 fn(function(){console.log(1)}); //output 2
另外也学到一个东西,对于块级作用中的函数声明在chrome和ie下会提前,而在firefox中,招待时才会进行。
1 console.log(fn.toString()); 2 3 if (true) { 4 5 function fn(){ return 1; } 6 7 }else { 8 9 if(false){ 10 11 function fn(){ return 2; } 12 13 } 14 15 }
chrome和Ie下输出function fn(){return 2;}
而firefox中抛出异常。
如果不是很懂,再看这个例子。
1 if (true) { 2 3 function fn(){ return 1; } 4 5 }else { 6 7 if(false){ 8 9 function fn(){ return 2; } 10 11 } 12 13 } 14 15 console.log(fn.toString());
chrome和ie一均为function fn(){ return 2;},而firefox中依然报错。
可见三者处理并不相同。ff中会提前变量的声明,但不会提前块级作用域中的函数声明。而chrome和ie下就会提前块级作用域中的函数声明,而且后面的声明会覆盖前面的声明。