美文网首页
变量声明前置,立即执行函数,作用域链

变量声明前置,立即执行函数,作用域链

作者: candy252324 | 来源:发表于2016-11-09 18:12 被阅读0次

    1、函数声明和函数表达式有什么区别

    函数声明和函数表达式都有声明前置的效果,但是:

    • 函数表达式的声明前置效果更像变量的声明前置效果,相当于只是一个变量名被前置了,而这个变量的值并没有被前置,不能在前面调用,会报错。


    • 函数声明则相当于整个函数都被前置了,可以在声明之前调用。


    2、什么是变量的声明前置?什么是函数的声明前置

    • 什么是变量的声明前置?
      JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,然后给他初始值undefined,然后才逐句执行程序,这就叫做“变量提升”,也即“变量的声明前置”。


    • 什么是函数的声明前置?
      和变量的声明会前置一样,函数声明同样会前置,如果我们使用函数表达式那么规则和变量一样,如下图:



      如果我们使用函数声明的方式,那么即使函数写在最后也可以在前面语句调用,前提是函数声明部分已经被下载到本地。

    3、arguments 是什么

    是一个长的很像数组的对象,可以通过该对象获取到函数的所有传入参数。


    4、函数的重载怎样实现

    在JavaScript中没有函数重载的概念,函数通过名字确定唯一性,参数不同也被认为是相同的函数,后面的覆盖前面的。函数调用没必要把所有参数都传入,只要你函数体内做好处理就行,但前提是传的参数永远被当做前几个。


    5、立即执行函数表达式是什么?有什么作用

    立即执行函数表达式有多种写法:(function(){})();, 或(function(){}()); ,或!function(){}();,或void function(){}(); , 如下图所示:


    作用:创建一个独立的作用域。这个作用域里面的变量,外面访问不到(即避免变量污染)。
    比如下面这个例子:不管单击哪个li,alert出来的总是6,而不是0、1、2、3、4、5。因为我们一定是在for循环结束后才单击的,而i是贯穿整个作用域的,所以,i总是6.
    <ul>
        <li>li1</li>
        <li>li2</li>
        <li>li3</li>
        <li>li4</li>
        <li>li5</li>
        <li>li6</li>
    </ul>
    <script type="text/javascript">
         var liList=document.getElementsByTagName("li");
         for(var i=0; i<liList.length; i++){
             liList[i].onclick=function(){
                 alert(i);
             }
          }
    </script>
    

    这里我们就可以用立即执行函数给每个li创造一个独立的作用域来解决这个问题。



    当然也有其他解决方法


    6、什么是函数的作用域链

    JavaScript中所有的量都是存在于某一个作用域中的,在试图访问一个变量时JS引擎会从当前作用域开始向上查找直到Global全局作用域停止。
    如下图:当alert(A)时, JS引擎沿着D的作用域, B的作用域, 全局作用域的顺序进行查找,这三个作用域组成的有序集合就成为作用域链。


    7.以下代码输出什么?

     function getInfo(name, age, sex){ 
        console.log('name:',name);
        console.log('age:', age);
        console.log('sex:', sex); 
        console.log(arguments); 
        arguments[0] = 'valley'; 
        console.log('name', name); 
    }
    getInfo('hunger', 28, '男'); 
    getInfo('hunger', 28); 
    getInfo('男');
    

    输出:

    name:hunger;
    age:28;
    sex:男;
    ["hunger", 28, "男"]
    name:valley;
    
    name:hunger;
    age:28;
    sex:undefined;
    ["hunger", 28]
    name:valley;
    
    name:"男";
    age:undefined;
    sex:undefined;
    ["男"]
    name:valley;
    

    8.写一个函数,返回参数的平方和

     function sumOfSquares(){
         var sum=0;
         for(var i=0; i<arguments.length; i++){
            sum=sum+Math.pow(arguments[i],2);
         }
            console.log(sum);
     }
    sumOfSquares(3,5);   //34
    sumOfSquares(3,5,-2);  //38
    sumOfSquares(3,5,-2,"hello");   //NaN
    

    9.如下代码的输出?为什么

    console.log(a);  //underfined,因为变量提升的缘故,初始值undefined
    var a = 1;  
    console.log(b);  //报错,因为b没有声明
    

    10.如下代码的输出?为什么

    sayName('world');     //输出hello world,因为使用函数声明声明的函数,相当于整个函数都被前置了,可以在声明之前就被调用
    sayAge(10);  //会报错,因为使用表达式声明的函数,只是函数名被前置了,所以在声明之前调用会报错
    function sayName(name){ 
        console.log('hello ', name); 
    } 
    var sayAge = function(age){ 
        console.log(age); 
    };
    
    

    11.如下代码的输出?为什么

    function fn(){} 
    var fn = 3; 
    console.log(fn); //3,因为当在同一个作用域内定义了名字相同的变量和方法的话,无论其顺序如何,变量的赋值会覆盖方法的赋值
    

    12.如下代码的输出?为什么

    function fn(fn2){
        console.log(fn2); 
        var fn2 = 3; 
        console.log(fn2); 
        console.log(fn);
        function fn2(){
           console.log('fnnn2');
       } 
    } 
    fn(10); 
    
    

    输出

     function fn2(){
           console.log('fnnn2');
       } 
    
    3
    
    function fn(fn2){ 
        console.log(fn2); 
        var fn2 = 3; 
        console.log(fn2);
         console.log(fn); 
        function fn2(){ 
            console.log('fnnn2'); 
      } 
    }
    
    

    因为,**当函数执行有命名冲突的时候,函数执行时载入顺序是变量、函数、参数 **,所以原代码等同于如下代码:

    function fn(fn2){
        var fn2;  //变量声明前置
        function fn2(){   //函数声明前置
            console.log('fnnn2'); 
        }
         console.log(fn2);   //打印fn2()函数
         fn2 = 3;
         console.log(fn2);   //打印数字3
         console.log(fn);     //向上寻找,打印fn()函数
    }
    fn(10);
    

    13 .如下代码的输出?为什么

    var fn = 1; 
    function fn(fn){ 
        console.log(fn); 
    } 
    console.log(fn(fn)); 
    

    执行报错。代码等同于:

    var fn;   //变量声明前置
    function fn(fn){   //函数声明前置
        console.log(fn); 
    }
    fn=1;  //fn赋值为1
    console.log(fn(fn));   //报错,因为此时的fn是数字1
    

    14.如下代码的输出?为什么

     //作用域
    console.log(j);   //undefined,变量声明前置导致
    console.log(i);   //undefined,变量声明前置导致
    for(var i=0; i<10; i++){ 
        var j = 100; 
    } 
    console.log(i);  //10,因为i=9时,j=100,然后再执行i++,i=10,此时不满足条件i<10,跳出循环。
    console.log(j);  //100,j一直等于100.
    

    15.如下代码的输出?为什么

    fn();   
    var i = 10; 
    var fn = 20;
    console.log(i); 
    function fn(){ 
        console.log(i); 
        var i = 99; 
        fn2(); 
        console.log(i); 
        function fn2(){
             i = 100; 
        } 
    }
    

    会依次打印:undefined,100,10,分析如下;

    
    var i, fn;
    function fn(){ 
        var i;
        function fn2(){
             i = 100; 
        } 
        console.log(i);   //undefined,因为此时fn2()函数没有被调用,所以i没有被赋值,打印undefined
        i = 99; 
        fn2();    //此处调用了fn2()函数,但是由于fn2()函数没有返回值,所以此处没有打印,但是i已经被赋值为100,并且是全局变量
        console.log(i);   //打印出i的值100
       
    }
    fn();
    i=10;  //此处i被重新赋值为10
    fn=20;
    console.log(i); //打印重新赋值后的i值
    

    16.如下代码的输出?为什么

    var say = 0; 
    (function say(n){ 
        console.log(n); 
        if(n<3) return;
         say(n-1); 
    }( 10 )); 
    console.log(say);
    

    依次输出:10,9,8,7,6,5,4,3,2,0
    括号内是一个立即执行函数,创建了一个独立的作用域,这个作用域里的变量,外面访问不到。第一次传入参数10,打印10,由于n=10不满足条件(n<3),于是执行函数say(n-1),打印9,接着是8,7......3,2,当n=2时,满足条件(n<3),于是跳出函数,执行console.log(say);,打印0。


    © 本文归饥人谷和本人所有,如需转载请注明来源。

    相关文章

      网友评论

          本文标题:变量声明前置,立即执行函数,作用域链

          本文链接:https://www.haomeiwen.com/subject/kqmuuttx.html