美文网首页
函数与作用域

函数与作用域

作者: cctosuper | 来源:发表于2017-11-03 11:03 被阅读0次

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

    • 函数声明: 函数声明通过关键字function来声明, 关键词后面是函数名, 名称后面有个小括号, 括号里面放的是函数的参数, 最后是一对花括号,包括函数的代码块
    • 函数表达式
      • 省略标识符(函数名)
        var printName = function(){}
        
        这种写法是将一个匿名函数赋值给变量; 这时这个匿名函数又称函数表达式(Function Expression), 因为赋值语句等号后面只能放表达式
      • 带有标识符; 采用函数表达式声明函数时, function后一般不带函数名, 如果带上函数名, 该函数名只在函数体内部有效, 在函数体外部无效
    • 区别:
      • 函数声明是以function关键词开始, 如果不是,那么就是函数表达式
      • 函数声明最后一般不写分号, 而函数表达式有分号
      • 函数声明和变量声明都有声明提前的特点, 函数声明是函数名称和函数体均提前声明了, 可以在声明之前调用它;
      • 函数表达式的规则与变量声明提前一样,只是函数声明变量提前了, 但是它的赋值仍在原来的位置, 不能在函数表达式之前调用

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

    • 变量声明前置是指把变量的声明提前到当前作用域的最前面, 但变量的赋值仍然按照原来的顺序执行, 如果变量声明但未被赋值, 变量自动赋值为undefined
    • 函数的声明前置有两种情况, 一个是使用函数声明, 则整个声明都前置, 而且会被前置到变量声明的后面; 另一个是使用函数表达式, 那么规则和变量的声明前置一样
    var a = 1;
    function main() {
        console.log(a);
        var a = 2;
    }
    main()//输出undefined
    解析如下:
    
    var a = 1;
    function main() {
        var a;        //这时的a是undefined
        console.log(a);
        a = 2;
    }
    

    arguments 是什么

    • arguments是一个类数组对象, 代表传给一个function的参数列表, 只在函数内部起作用; arguments的值与函数传入参数有关, 与定义参数无关
    • 在函数内部可以使用arguments对象获取到该函数的所有传入参数, 这个对象为传递给函数的每个参数建立一个条目, 条目的索引号 从0 开始
    • 使用arguments能够给实参重新复制
    • 可以用arguments能够检测函数的参数个数 arguments.length
    • 类似数组但不是数组的对象, 其具备数组相同的访问性质及方式, 能够由arguments[n]来访问对应参数的值

    函数的"重载"怎样实现

    • 重载是很多面向对象语言实现多态的手段之一, 相同名字的函数参数个数不同, 或者顺序不同, 都被认为是不同的函数
    • 在JavaScript中没有函数重载的概念, 函数通过名字确定唯一性, 参数不同也被认为是相同的函数, 后面的覆盖前面的
    • JavaScript可以通过自身属性模拟函数重载, 可以用arguments来实现函数的重载
    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');
    

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

    • 在JavaScript中, 一对圆括号()是一种运算符, 跟在函数明后, 表示调用该函数; 有时我们希望在定义函数之后, 立即调用该函数; 这时, 不能再函数的定义之后加圆括号, 会产生语法错误; 因为function这个关键字既可以当做语句, 也可当做表达式; 为了避免解析上的歧义, JavaScript引擎看到行首是function关键字之后, 认为这一段都是函数的定义 , 不应该以圆括号结尾, 所以报错;
    • 解决方法就是不要让function出现在行首, 让引擎将其理解外一个表达式, 最简单的方式, 是将其放在圆括号内
    //正确的写法:
      ( function(){ /* code */ }() );
      // 或者
      ( function(){ /* code */ } )();
    
    • 上述写法都是以圆括号开头, 引擎就会认为后面跟的是表达式, 而不是函数定义语句, 避免了错误; 这就是 立即执行函数表达式
    • 上面写法最后的分号都是必须的; 如果省略分号, 遇到连续的两个立即执行表达式, 可能会报错
    • 立即执行函数表达式一般不需要给函数命名, 如果要命名, 一般是用于递归函数
    • 中括号, 逗号, 取反运算符也能达到类似效果
    [function fn(){var a=3}]()
    ,function fn(){var a=3}()
    !function fn(){var a=3}()
    
    • 作用: 将全局变量与局部变量分隔开, 保证全局变量不受污染

    求n!,用递归来实现

    function recursion(n) {
      if (n === 1 || n === 0) {
        return 1;
      }
      else if (n<0) {
        return console.log("minus has no recursion");
      }
      return n*recursion(n-1);
    }
    console.log(recursion(8));
    

    以下代码输出什么?

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

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

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

    如下代码的输出?为什么

        console.log(a); //undefined, 变量声明会前置,并赋值undefined
        var a = 1;
        console.log(b); //报错, b未声明
    

    如下代码的输出?为什么

        sayName('world');
        sayAge(10);
        function sayName(name){
            console.log('hello ', name);
        }
        var sayAge = function(age){
            console.log(age);
        }; //输出hello  world,同时报错sayAge is not a function。因为这是一个函数表达式,声明必须放到调用的前面,而这里声明放在了后面。
    

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

    var x = 10
    bar() 
    function foo() {
      console.log(x)
    }
    function bar(){
      var x = 30
      foo()
    } //输出 10
    /*
    globalContent= {
      A0 {
           x: 10
           foo: function
           bar: function
      }
      scope: null
    }
    foo[[scope]] = globalContent.A0
    bar[[scope]] = globalContent.A0
    barContent= {
      A0 {
           x: 30
      }
      scope: globalContent.A0
    }
    fooContent= {
      A0 {}
      scope: globalContent.A0
    }
    */
    

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

    var x = 10;
    bar() 
    function bar(){
      var x = 30;
      function foo(){
        console.log(x) 
      }
      foo(); 
    } // 输出30
    /*
    globalContent= {
      A0 {
        x: 10
      }
      scope: null
    }
    bar[[scope]] = globalContent.A0
    barContent= {
      A0 {
        x: 30
        foo: function
      }
      scope: globalContent.A0
    }
    fooContent[[scope]] = barContent.A0
    fooContent = {
      A0 {}
      scope :barContent.A0
    }
    */
    

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

    var x = 10;
    bar() 
    function bar(){
      var x = 30;
      (function (){
        console.log(x)
      })()
    } //输出30
    /*
    globalContent = {
      A0 {
        x: 10
        bar: function
      }
      scope: null
    }
    bar[[scope]] = globalContent.A0
    barContent = {
      A0 {
        x: 30
        function()
      }
      scope: globalContent.A0
    }
    function()[[scope]] = barContext.AO
    functionContent = {
      A0 {}
      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. globalContext = {
             A0 {
               a: 1
               fn: function
               fn3: function
             }
             scope: null
           }
           fn[[scope]] = globalContext.A0
           fn3[[scope]] = globalContext.A0
    2. fnContent = {
          A0 {
            a: undefined, 5, 6
            fn2: function
          }
         scope: globalContext.A0
       }
       fn2[[scope]] = fnContext.A0
    3. fn2Content = {
          A0 {}
          scope: fnContext.A0 
        }
    4. fn3Content = {
        A0 {}
        scope: globalContext.A0
        }   
    */
    

    相关文章

      网友评论

          本文标题:函数与作用域

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