JS面试题

http://blog.csdn.net/lbxx1984/article/details/48133255

1.难度 ★★★
[javascript] view plain copy
  1. function func1() {  
  2.     var n = 0;  
  3.     add = function () {  
  4.         n++;  
  5.     }  
  6.     function func2() {  
  7.         console.log(n);  
  8.     }  
  9.     return func2;  
  10. }  
  11. var result1 = func1();  
  12. var result2 = func1();  
  13. result1(); // 0  
  14. result2(); // 0  
  15. add();  
  16. result1(); // 0  
  17. result2(); // 1  

解:
    这段程序的考点有三个:一是变量作用域;二是函数作用域链的创建;三是闭包。
    (1)首先func1中的add没有var,相当于在全局声明了一个add变量,指向一个动态创建的匿名函数
    (2)result1初始化的时候引擎做了什么?首先在全局添加变量add,然后制作一个匿名函数挂到add上,这个匿名函数在创建时,产生了一个作用域链,其中包含n的值0;
    (3)result2初始化的时候引擎做了什么?此时全局已经有了add变量,func1再次创建一个匿名函数,并将函数挂在add上,这样add就被覆盖了一次,(2)中产生的匿名函数将不能被调用,因为指向它的add已经指向了新创建的匿名函数。新的匿名函数有自己独立的作用域链,开始时作用域中的n也是0,但这个n跟(2)中的n已经不是同一个了,因为两个匿名函数的作用域链是不同的,因为n前面有个var
   (4)result1和result2都是闭包,他们第一次执行的时候,输出各自的n的初始值0。
   (5)add运行的时候,实际是执行了与result2有关的另一个闭包,而与result1有关的闭包中的n并没有被修改。
   (6)result1和result2再次执行的时候,上述分析得到验证。
   (7)引申以下,如果去掉n前面的var呢?答,输出则是0,0,1,1。因为这时n也被提升了,result1和result2的作用域联中对n的引用是同一个,所以执行add后都输出1。
   (8)如果重写以上代码,让它已大家熟悉的形式展现,则相当于:
[javascript] view plain copy
  1. var add;  
  2. function func1(n) {  
  3.     add = function () {  
  4.         n++;  
  5.     }  
  6.     return function () {  
  7.         console.log(n);  
  8.     };  
  9. }  
  10. var result1 = func1(0);  
  11. var result2 = func1(0);  
  12. result1(); // 0  
  13. result2(); // 0  
  14. add();  
  15. result1(); // 0  
  16. result2(); // 1  


2.难度 ★★
[javascript] view plain copy
  1. function main() {  
  2.     var n = 0;  
  3.     var func = function () {  
  4.         n = 1;  
  5.     }  
  6.     func();  
  7.     console.log(n); // 1  
  8.     function func() {  
  9.         n = 2;  
  10.     }  
  11.     func();  
  12.     console.log(n); // 1  
  13. }  
  14. main();  

解:
    这段程序考点比较少,只有函数提升和表达式函数。
    (1)在一个作用域块中,任何地方定义的函数(非表达式方式定义),都相当于在该作用域块头部定义,在作用域任何位置都能调用,这就是”函数提升“。也就是说解释器在创建main是,就将func创建好了,但此时n还没有创建,因为main还没有执行。
    (2)在等号后面创建的函数是表达式函数,表达式函数与声明函数的不同在于只有代码执行到这一样时,这个函数才被创建,在创建之前是不能调用的。在一个作用域块中,表达式函数可以覆盖声明函数,但声明函数不能覆盖表达式函数。
    (3)接下来看main执行的时候发生了什么。
        首先创建一个变量n。
        然后创建一个匿名函数,并将匿名函数挂到func上。注意,func前面的var其实是没有意义的,因为func已经存在了,是包含“n = 2;”的那个函数。如果在main的第一行添加“console.log(func)”,控制台会输出函数体,而不是undefined。但执行到这里的时候,原来的函数被匿名函数覆盖掉了。
        执行func时,执行的是新创建的匿名函数,输出1。
        第一个控制台输出后面的代码是没有意义的,因为这部分代码已经被提升了,完全当它不存在就可以。
        接下来的执行和输出道理就一样了。
    (4)总之记住一点:作用域中的函数在作用域任何地方都可以用;但var出来的东西只有在var后面才能用;作用域中的变量,在var之前用永远是undefined。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值