美文网首页
函数与作用域

函数与作用域

作者: 饥人谷_啦啦啦 | 来源:发表于2017-06-15 23:15 被阅读0次

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

    • 函数声明:
      形式上 function fuctionName(){//statement};声明了一个名字为functionName的函数,浏览器解析的时候,先要做函数声明前置,在globlecontext的AO中,声明此函数,此时,你在全球作用域下(包括函数声明之前的位置)调用,都可以找到这个函数。

    • 函数表达式:
      形式上 var someThing=fuction (){//statement};虽然这也是声明了一个函数(匿名的),但实际上浏览器解析的时候,先做的是变量提升,在globlecontext的AO中,声明的是一个变量,假如,在函数声明之前调用该函数,是不能够找到这个函数的,因为调用的时候必然要调用的someThing这个变量,但是变量值在提升变量的时候未给出。

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

    • 变量的声明前置:
      变量的声明前置就是在函数内部,首先要做的事也是类似于浏览器做变量提升,先在当前上下文的AO中声明这个变量。

    • 函数的声明前置:
      函数的声明前置是,当我们用函数声明来声明一个函数时,函数就会在至当前上下文的AO中声明这个这个函数,同时,在函数内部的上下文的scope中,给声明的函数开辟一个空间,并指向父元素的AO.

    3.arguments是什么?

    • arguments是一个伪类数组,目前仅仅知道,他是一个函数内部自带的一个类似于数组的参数,我们可以调用arguments[],来获取传入函数内部的参数,并且支持索引,支持length属性。

    4.函数的"重载"怎样实现?

    • 首先,JS中不同于其他语言,没有重载,例如其他语言中,我们可以设定。但是我们可以控制函数体内部的逻辑语句来实现重载。

    例如:

    <script language="JavaScript"> 
    function f(length) 
    { 
        alert("高为:"+length); 
    } 
    
    function f(length,width) 
    { 
        alert("高为:"+length+",宽为:"+width); 
    } 
    </srcipt>
    /* 上面这个段代码行不通,第一个函数会被第二个覆盖,不能实现 f(10)想要的效果。*/
    

    但是我们可以这么做

    <script language="JavaScript"> 
    function f(length) 
    { 
        var len= arguments.length; 
        if(1 == len) 
        { 
            var width = arguments[1]; 
            alert("高为:"+length+",宽为:"+width); 
        } 
        else 
        { 
            alert("高为:"+length); 
        } 
    } 
    </srcipt>
    

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

    • 立即执行表达式是什么?
      (function (){})();
      (function(){}());
      上面就是两个常见的立即执行表达式,当我们建立一个匿名函数时,并希望他执行时,我们想到可以这样 function (){}(); 但是实际上,语法上不对,因为浏览器读到这里时,会认为这是一个函数声明,但是没有给出函数名字,所以会报错。但是我们在 function (){}加上括号,意义就不一样了,因为JS中小括号内部是一个表达式,表达式后面加括号,函数可以立即执行的, 和函数表达式声明一样
    var something= functiong (){
      console.log ( "hello")
    }();
    

    所以,我们只需要让浏览器明白,我们前面function (){} 是一个函数表达式就可以了,类似的方法有许多,而已加上各种运算符,让浏览器知道,我们这是一个函数表达式,这就可以了。类似的有很多。

    • 为什么要用立即执行函数表达式?

      因为JS并没有块级作用域的概念,你在全局或者局部声明的变量 极有可能会被自己或者他人覆盖掉,为了保护这些的变量,我们可以给他加上一层外壳,封装起来,这样,外部变量就不会对内部的变量造成影响了。

    求n!,用递归来实现

    function doRecursion(n){
        if(n<0){
          console.log('You input a wrong number');
        }
        else if(n===0||n===1){
            return 1;
        }
        else if(n>0){
          return n*multiply(n-1);
        }
    }
    

    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('饥人谷', 2, '男'); 
    getInfo('小谷', 3);
    getInfo('男');
    

    // 倒数第三行调用函数 ,输出 name: 饥人谷,age:2,sex:男;['饥人谷',2,'男‘],name:valley
    // 倒数第二行调用函数,输出 name:小谷,age:3;sex:undefined;['小谷',3,];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+arguments[i]*arguments[i];
          }
          return sum;
       }
       var result = sumOfSquares(2,3,4);
       var result2 = sumOfSquares(1,3);
       console.log(result) ;
       console.log(result2) ;
    

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

        console.log(a); //undefined,变量提升,有变量a,但是没有值。
        var a = 1;
        console.log(b);//error ,没有定义这个变量。
    

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

        sayName('world'); //hello,world.
        sayAge(10);//报错 。
        function sayName(name){
            console.log('hello ', name);
        }
        var sayAge = function(age){
            console.log(age);
        };
    

    第一个函数能输出是因为,函数声明前置,可以找到globleContext的OA中有这个函数,然后就可以去执行这个函数的上下文。
    第二个变量提升,浏览器不知道sayAge(10)是什么意思,如果放在函数表达式后面,浏览器就知道原来这个sayAge()是一个函数表达式,就会执行了。

    11.如下代码输出什么? 写出作用域链查找过程伪代码

    var x = 10
    bar() 
    function foo() {
      console.log(x)
    }
    function bar(){
      var x = 30
      foo()
    }
    

    第一步:

    globleContext{
      A0:{
      x:10,
      function foo(),
      bar(),
      }
      scope:null;
    }
    foo().[[scope]]=globleContext.AO
    bar().[[scope]]=globleContext.AO
    

    第二步:

    执行bar();
    在globloContext.AO中找到了 bar();
    调用bar();进入bar()函数的barContext
    barContext:{
      AO:{
        x:30,
      }
      scope:globleContext.AO
    }
    barContext.AO中没有找到 foo();然后去scope中找,scope指向globleContext.AO, 找到右foo();调用foo();
    fooContext:{
      AO:{
        x:undefined,
      }
      scope:globleContext.AO
    }
    执行console.log(x);
    但是在AO中没有找到,去scope中找到指向globleContext.AO,找到x的值为10,所以,最终结果就是10。
    

    12.如下代码输出什么? 写出作用域链查找过程伪代码

    var x = 10;
    bar() 
    function bar(){
      var x = 30;
      function foo(){
        console.log(x) 
      }
      foo();
    }   
    
    globleContext: {
      AO:{
        x:10,
        function bar(),
      }
      scope:null
    }
    
    bar.[[scope]]=globleContext.AO;
    
    //第二部;
    执行bar(); 在globleContext中找到。
    进入bar();
    
    barContext:{
      AO:{
        x=30;
        function foo();
      }
      scope:globleContext.AO
    }
    
    foo.[[scope]]=barContext.AO;
    
    执行 foo(); 
    foo()中没有找到x.去barContext.AO找到了。所以console.log(x);
    结果是10。
    

    13. 以下代码输出什么? 写出作用域链的查找过程伪代码

    var x = 10;
    bar() 
    function bar(){
      var x = 30;
      (function (){
        console.log(x)
      })()
    }
    
    1、执行bar(),globleContext中有bar()
    2 、进入bar()的上下文;
    3、执行立即执行函数表达式,但是函数表达式AO中没有找到X,
    4、去scope中找,找到的是barContext.AO中,有x的值,得到30.
    

    14. 以下代码输出什么? 写出作用域链查找过程伪代码

    var a = 1;
    
    function fn(){
      console.log(a)
      var a = 5
      console.log(a)
      a++
      var a
      fn3()
      fn2()
      console.log(a)
    
      function fn2(){
        console.log(a)
        a = 20
      }
    }
    
    function fn3(){
      console.log(a)
      a = 200
    }
    
    fn()
    console.log(a)
    
    1、执行fn() 在globleContext中找到了,所以,进入fn()的上下文。
    2、console.log(a),当前函数的作用域中有a变量,此时没有赋值//输出 **undefined**
    3、再次执行console.log(a),上一行,a已经赋值,所以//输出 **5**
    4、a++ ; a=6,不用输出。
    5、var a, a仍然等于6.
    6、执行fn3() ,当前函数的AO中没有,找到globleContext.AO,有fn3(),进入fn3()的上下文中。
    7、console.log(a),当前的AO还没有a,所以,去找到上一级的AO,找到globleContext.AO,然后,得到结果// **1**,顺便,修改了globleContext.AO中的a=200;
    8、回到fn(),运行fn2(),找到了fn2(),进入fn2(), console.log(a), 当前AO中没有a,找到上一级也就是fn的AO中,a=6 ,所以输出 ** 6 ** ,顺便修改了fnContext中的AO,是20 。
    9、执行fn()中的console.log(a),此时受到第8步骤的影响,所以,输出是**20.**
    10 、fn()运行结束,此时,再次运行console.log,受到第7 的影响,a变为了200.所以输出**200**
    

    相关文章

      网友评论

          本文标题:函数与作用域

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