JS面试题(持续更新)

1.难度 ★★★
    function func1() {
        var n = 0;
        add = function () {
            n++;
        }
        function func2() {
            console.log(n);
        }
        return func2;
    }
    var result1 = func1();
    var result2 = func1();
    result1(); // 0
    result2(); // 0
    add();
    result1(); // 0
    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)如果重写以上代码,让它已大家熟悉的形式展现,则相当于:
    var add;
    function func1(n) {
        add = function () {
            n++;
        }
        return function () {
            console.log(n);
        };
    }
    var result1 = func1(0);
    var result2 = func1(0);
    result1(); // 0
    result2(); // 0
    add();
    result1(); // 0
    result2(); // 1


2.难度 ★★
    function main() {
        var n = 0;
        var func = function () {
            n = 1;
        }
        func();
        console.log(n); // 1
        function func() {
            n = 2;
        }
        func();
        console.log(n); // 1
    }
    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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值