美文网首页
进阶3 函数与作用域

进阶3 函数与作用域

作者: 512a36a11b8c | 来源:发表于2017-11-10 15:21 被阅读9次

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

    函数声明:function fnname (){函数体}
    函数表达式:var fnname=function(){函数体}
    使用function关键字可以声明一个函数,它的特征是函数声明提升,执行代码前会先读取函数声明,即函数声明不必放在调用的前面,它可以放在当前作用域任何位置;函数表达式在使用前必须先赋值,所以声明必须放在调用前面,不然浏览器解析代码时会认为函数还不存在而抛出错误,理解函数提升的关键就是理解函数声明与函数表达式之间的区别。

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

    变量的声明前置:在程序运行前,先获取变量的名字,并将其提升到当前作用域的头部,到该变量的赋值语句,为该变量赋值,在此前都是undefined。
    变量的声明前置位置:变量提升到其所处作用域的顶部;函数内的变量,则提升到函数内的顶部。
    函数的声明前置:function 函数名(){}声明了一个函数,在程序运行前,提取所有函数声明的函数名,提升到作用域的头部,之后才正式开始运行函数,所以,无论函数声明的函数执行语句放在程序的最前面,或者程序的最后面,都能够正常执行
    函数声明前置:提升到其所处作用域的顶部,函数内的函数,提升到函数内的顶部。

    3. arguments 是什么

    类数组对象,在函数内部,你可以使用arguments对象获取到该函数的所有传入参数,通过访问arguments对象的length属性可以获知有多少个参数传递给了函数。而且arguments的值会与对应命名的参数值保持同步,没有传递值的命名参数会自动赋值为undefined。


    arguments.png

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

    概念:函数重载指同一函数名对应着多个函数的实现。即每种实现对应一个函数体,这些函数名字相同,但参数类型或个数或顺序不同。
    基本设计原则:当两个函数除了参数类型和参数个数不同以外其他功能完全相同时,利用函数重载;两个函数功能不同时不应使用重载,而应使用一个名字不同的函数。

    //其他语言重载范例
    int sum(int num1, int num2){
      return num1 + num2;
    }
    
    float sum(float num1, float num2){
      return num1 + num2;
    }
    
    sum(1, 2);
    sum(1.5, 2.4);
    
    

    js是弱类型语言,参数不是固定的某个类型,所以在js中没有重载,同名函数后面的会覆盖前面的。但我们也可以实现重载所需要的功能。

    function printPeopleInfo(name,age,sex){
        if(name){
            console.log(name);
        }
        if(age){
            console.log(age);
        }
        if(sex){
            console.log(sex);
        }
    }
    printPeopleInfo("dot",23);  //dot 23
    printPeopleInfo("dot","female",23);  //dot female 23
    
    
    

    注意:始终记住函数名只是一个指向函数对象的指针,并不会与某个函数绑定。

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

    立即执行函数表达式:缩写IIFE,是一种利用javascript函数生成新作用域的编程方法,也叫自执行函数。
    作用:

    • 令函数中声明的变量绕过js的变量置顶声明规则
    • 避免新的变量被解释成全局变量或函数名占用全局变量名的情况
    • 在禁止访问函数內变量声明的情况下允许外部对函数的调用

    实现:因js里的()里不能包含语句,所以解析器会将()里的代码解析成function表达式并立即执行。

    // 以下都能实现立即执行
    (function(){ /* code */ }());
    (function(){ /* code */ })();
    
    // function前加一元运算符也可实现,advance-task2我有提到过
    !function () { /* code */ } ();
    ~function () { /* code */ } ();
    -function () { /* code */ } ();
    +function () { /* code */ } ();
    

    6. 求n!,用递归来实现

    function fun(num) {
    
        if (num == 1 || num == 0) {
            return 1
        } else if (num < 1) { return false }
        return num*fun(num-1)
    }
    //n! (n的阶乘)这道题,由于 0! = 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 res = 0;
        for (var i in arguments){
            if (typeof arguments[i] !== 'number') {
                return 'you entered a wrong number';
            }
        }
        for (var j in arguments){
            res += arguments[j]*arguments[j];
        }
        return res;
    }
    var result = sumOfSquares(2,3,4);
    var result2 = sumOfSquares(1,3);
    console.log(result);  //29
    console.log(result2); //10
    

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

        console.log(a);   //undefined,因为变量a声明提升并赋值为undefined,先读取变量声明
        var a = 1;
        console.log(b);   //ReferenceError:b is not defined,因为b没有声明
    

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

            sayName('world');      //hello world    函数声明前置,
        sayAge(10);    //报错:say age is not a function,因为sayAge是函数表达式,使用前必须赋值,而声明放在了调用的后面,此时函数还不存在,所以会报错
        function sayName(name){
            console.log('hello ', name);
        }
        var sayAge = function(age){  
            console.log(age);
        };
    

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

    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)
    //为了更好的理解上面的函数 下面我来改写一下
    var a = 1;
    
    function fn(){
      console.log(_a)
      var _a = 5 //var a变量提升
      console.log(_a)
      _a++
      var _a
      fn3() // 执行fn3 函数
      fn2() // 执行fn2 函数
      console.log(_a)
    
      function fn2(){
        console.log(_a)
        _a = 20
      }
    }
    
    function fn3(){
      console.log(a)
      a = 200
    }
    
    fn()
    console.log(a)
    

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

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

    输出30

    gobalContext = {
                AO: {
                    x:10,
                    foo: function(){}
                },
              Scope: null
            }
            bar.[[scope]] = gobalContext.AO
    
            barContext = {
                AO:{
                    x:30,
                    foo: function(){}
                },
                Scope: gobalContext.AO
            }
    

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

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

    30

    gobalContext = {
                AO: {
                    x: 10,
                    bar: function(){}
                },
                Scope: null
            }
            bar.[[scope]] = gobalContext.AO;
    
            barContext = {
                AO: {
                    x: 30,
                    IIFE: function(){}
                },
                Scope: gobalContext.AO;
            };
    
            IIFEContext = {
                AO: {
    
                },
                Scope: barContext.AO
            }
    
    

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

    var a = 1;
    
    function fn(){
      console.log(a)         //undefined
      var a = 5
      console.log(a)         //5
      a++
      var a                        
      fn3()                        
      fn2()                         
      console.log(a)           //20
    
      function fn2(){
        console.log(a)          //6
        a = 20
      }
    }
    
    function fn3(){
      console.log(a)               //1
      a = 200
    }
    
    fn()
    console.log(a)                   //200
    
            gobalContext = {
                AO: {
                    a:1,
                    fn: function(){},
                    fn3: function(){}
                },
                Scope: null
            };
    
            fn[Scope] = gobalContext.AO;
            fn3[Scope] = gobalContext.AO;
    
            fnContext = {
                AO: {
                    a: 20,
                    fn2: function(){}
                }
                Scope: gobalContext.AO;
            };
    
            fn3Context = {
                AO: {
    
                },
                Scope: gobalContext.AO;
            };
    
            fn2Context = {
                AO: {
    
                },
                Scope: fnContext.AO
            }
    
    

    相关文章

      网友评论

          本文标题:进阶3 函数与作用域

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