美文网首页
函数与作用域 知识点总结

函数与作用域 知识点总结

作者: osborne | 来源:发表于2017-02-10 23:37 被阅读8次

    一:函数声明和函数表达式的区别

    • 函数声明必须带有标示符(Identifier)(即函数名称),而函数表达式则可以省略这个标示符。
      • 函数声明:function functionName(){}
        function 函数名称 (参数:可选){ 函数体 }
      • 函数表达式:var fn = function(){}
        function 函数名称(可选)(参数:可选){ 函数体 }
    • 函数声明语句中的函数名是一个变量名,变量指向函数对象。
      函数定义表达式和通过var声明变量一样,其函数被提前到了脚本或函数的顶部,因此它在整个脚本和或函数内都是可见的。这样的话,只有函数变量声明提前了,函数的初始化代码仍然在原来的位置。但是使用函数声明的话,函数名称和函数体均提前了,即脚本中的函数和函数中嵌套的函数都会在当前上下文中其它代码之前声明,也即可以在声明一个函数之前调用它。

    注:区别是函数声明会提前,即可以在函数声明之前调用函数。而函数表达式只会将变量先提升,此时的变量是undefined,所以不能在函数表达式前调用函数。

    二:什么是变量的声明前置?什么是函数的声明前置

    • 变量声明前置:JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部。
    console.log(a) //undefined
    var a = 1;
    console.log(a); //1
    //相当于
    var a;
    console.log(a);
    a = 1;
    console.log(a);
    
    • 函数声明前置:JavaScript引擎将函数名视同变量名,所以采用function命令声明函数时,整个函数会像变量声明一样,被提升到代码头部。所以,下面的代码不会报错。
    fn(); //3 因为函数声明提前,所以不会报错
    function fn() {
        console.log(3);
    }
    

    三:arguments 是什么

    • arguments对象包含了函数运行时的所有参数,arguments[0]就是第一个参数,arguments[1]就是第二个参数,以此类推。这个对象只有在函数体内部,才可以使用。
    var f = function(one) {
      console.log(arguments[0]);
      console.log(arguments[1]);
      console.log(arguments[2]);
    }
    f(1, 2, 3)
    // 1
    // 2
    // 3
    

    四:函数的"重载"怎样实现

    • 重载是很多面向对象语言实现多态的手段之一,在静态语言中确定一个函数的手段是靠方法签名——函数名+参数列表,也就是说相同名字的函数参数个数不同或者顺序不同都被认为是不同的函数,称为函数重载。
    • 在JavaScript中没有函数重载的概念,函数通过名字确定唯一性,参数不同也被认为是相同的函数,后面的覆盖前面的,但可以在函数体针对不同的参数调用执行相应的逻辑。
      function printPeopleInfo (name, age, sex){
        if(name){
          console.log(name);
        }
        if(age){
          console.log(age);
        }
        if(sex){
          console.log(sex);
        }
      }
      printPeopleInfo('Byron', 26);
      printPeopleInfo('Byron', 26, 'male');
    

    五:立即执行函数表达式是什么,作用呢

    • 立即执行函数表达式(Immediately-Invoked Function Expression),简称IIFE。表示定义函数之后,立即调用该函数。
    (function(){
      var a  = 1;
    })()
    

    其他写法:

    (function fn1() {});
    [function fn2() {}];
    1, function fn3() {};
    
    • 作用:隔离作用域。

    六:求n!,用递归来实现

    function factor(n){
      if(n === 1) {
        return 1
      }
      return n * factor(n-1)
    }
    

    七:以下代码输出什么

        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, '男');
    /* 输出:name:饥人谷 age:2 sex:男 ["饥人谷",2,"男"] name valley */
    getInfo('小谷', 3);
    /* 输出:name:小谷 age:3 sex:undefined ["小谷",3] name valley */
    getInfo('男');
    /* 输出:name:男 age:undefiend sex:undefined ["男"] name valley */
    

    八:写一个函数,返回参数的平方和

       function sumOfSquares(){
            var result=0;
            for(var i=0;i<arguments.length;i++){
                result=result+arguments[i]*arguments[i];
            }
            console.log(result);
       }
       var result = sumOfSquares(2,3,4)
       var result2 = sumOfSquares(1,3)
       console.log(result)  //29
       console.log(result)  //10
    

    九:如下代码的输出?为什么

        console.log(a);
        var a = 1;
        console.log(b);
        /* 输出:undefined 报错:b is not defined 原因:变量提升,没有b变量的声明*/
    

    十:如下代码的输出?为什么

        sayName('world');//输出:hello world 函数声明前置
        sayAge(10);//报错:sayAge is not a function 函数表达式不前置
        function sayName(name){
            console.log('hello ', name);
        }
        var sayAge = function(age){
            console.log(age);
        };
    

    十一:如下代码输出什么? 写出作用域链查找过程伪代码

    var x = 10
    bar() 
    function foo() {
      console.log(x)
    }
    function bar(){
      var x = 30
      foo()
    }
    /* 输出:10
    1.
    globalContext = {
      AO: {
        x: 10
        foo: function
        bar: function
      }
      Scope: null
    }
    foo.[[scope]] = globalContext.AO
    bar.[[scope]] = globalContext.AO
    2.调用bar()
    barContext = {
      AO: {
        x: 30
      }
      Scope: bar.[[scope]] = globalContext.AO
    }
    3.调用foo()
    fooContext = {
      AO: {}
      Scope: foo.[[scope]] = globalContext.AO
    } */
    

    十二:如下代码输出什么? 写出作用域链查找过程伪代码

    var x = 10;
    bar() 
    function bar(){
      var x = 30;
      function foo(){
        console.log(x) 
      }
      foo();
    }
    /* 输出:30
    1.
    globalContext = {
      AO: {
        x: 10
        bar: function
      }
      Scope: null
    }
    bar.[[scope]] = globalContext.AO
    2.调用bar()
    barContext = {
      AO: {
        x: 30
        foo: function
      }
      Scope: bar.[[scope]] = globalContext.AO
    }
    foo.[[scope]] = barContext.AO
    3.调用foo()
    fooContext = {
      AO: {}
      Scope: foo.[[scope]] = barContext.AO
    } */
    

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

    var x = 10;
    bar() 
    function bar(){
      var x = 30;
      (function (){
        console.log(x)
      })()
    }
    /* 输出:30
    1.
    globalContext = {
      AO: {
        x: 10
        bar: function
      }
      Scope: null
    }
    bar.[[scope]] = globalContext.AO
    2.调用bar()
    barContext = {
      AO: {
        x: 30
        function(){}
      }
      Scope: bar.[[scope]] = globalContext.AO
    }
    function.[[scope]] = barContext.AO
    3.调用function()
    functionContext = {
      AO: {}
      Scope: function.[[scope]] = barContext.AO
    } */
    

    十四:以下代码输出什么? 写出作用域链查找过程伪代码

    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)
    /* 输出: undefined 5 1 6 20 200
    1.首先将声明都提前,然后1赋值给a,调用函数fn(),第一个console.log(a)由于a还没有赋值5,但已经声明(var a)所以输出undefined;第二个console.log(a)则已经赋值5,所以输出5;
    2.接着调用函数fn3(),因为函数fn3()并不在函数fn()的作用域,所以输出全局变量a=1,并且把全局变量a“污染“为200;
    3.紧接着调用函数fn2(),在函数fn()的作用域里,之前由于a++,所以输出6,且对函数fn()的作用域的a进行赋值20;
    4.然后又是一个console.log(a),在函数fn()的作用域里,上一步已经调用为20了,所以输出20;
    5.最后又是一个在函数fn()的作用域里,这次在全局作用域里,函数体外,之前第二步解释了全局变量a为200,所以输出200;
    综上输出结果就是:undefined 5 1 6 20 200
    
    
    - 参考 作用域链视频讲解(2017.08.21更新)

    相关文章

      网友评论

          本文标题:函数与作用域 知识点总结

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