美文网首页
JS函数与作用域

JS函数与作用域

作者: billa_8f6b | 来源:发表于2017-06-09 14:20 被阅读0次

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

    函数声明:

    function fn(){}
    

    函数表达式:

    var fn = function(){}
    

    区别:

    1. 使用函数声明方式定义的函数,可以在声明前调用
    2. 使用函数表达式定义的函数,只能在声明后再调用

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

    变量前置:在一个作用域下,var 声明的变量和function 声明的函数会前置

    console.log(a); //undefined 由于声明前置,可以在a声明前使用变量a,但由于a未赋值,所以值为undefined
    
    var a = 3;
    console.log(a); //3
    
    //由于声明前置,可以在sayHello()方法声明前调用
    sayHello();
    
    function sayHello(){
      console.log('hello');
    }
    

    3.arguments 是什么

    在函数内部,你可以使用arguments对象获取到该函数的所有传入参数

    function printPersonInfo(name, age, sex){
        console.log(name);
        console.log(age);
        console.log(sex);
        console.log(arguments);
      }
    

    arguments对象不是一个 Array
    。它类似于数组,但除了 长度之外没有任何数组属性。例如,它没有 pop 方法。但是它可以被转换为一个真正的数组:

    let args = Array.prototype.slice.call(arguments); 
    let args = [].slice.call(arguments);
    

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

    js没有函数重载! 同名函数会覆盖。 但可以在函数体针对不同的参数调用执行相应的逻辑

    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');
    

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

    有两种写法:

    (function(){
      ...
    })()
    
    (function(){ 
        ...
    }());
    

    通常情况下,只对匿名函数使用这种“立即执行的函数表达式”。它的目的有两个:

    • 一是不必为函数命名,避免了污染全局变量;
    • 二是IIFE内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。

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

    function factorial(num) {
        if(num <= 1) {
          return num;    
        }
        return num*factorial(num-1);
    }
    

    7. 以下代码输出什么?

    image.png
    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);
    }
    /*输出:
     name: 小谷
     age: 3
     sex: undefined
     ["小谷", 3, callee: function, Symbol(Symbol.iterator): function]
      name valley*/
    getInfo('饥人谷', 2, '男');
    
    /*输出:
      name: 小谷
      age 3
      sex undefined
      ["小谷", 3, callee: function, Symbol(Symbol.iterator): function
    name valley
    */
    getInfo('小谷', 3);
    
    /*输出:
    name: 男
    age: undefined
    sex: undefined
    ["男", callee: function, Symbol(Symbol.iterator): function]
      name valley
    */
    getInfo('男');
    

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

    image.png
    function sumOfSquares() {
        var len = arguments.length;
        var sum = 0;
        for (var i = 0; i < len; i++) {
            sum = sum + parseInt(arguments[i]) * parseInt(arguments[i]);
        }
        return sum;
    }
    

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

    image.png
    //输出undefined 因为a变量的声明会被前置,但a还没被赋值,所以值为undefined
    console.log(a);
    var a = 1;
    //会报错:b is not defined 因为b没有声明
    console.log(b);
    

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

    image.png
    //输出'hello world' 函数声明会被前置,可以在声明前调用
    sayName('world');
    //会报错:sayAge is not a function 因为sayAge是个函数表达式,        sayAge会被前置,但还没赋值,所以不能作为函数对象执行
    sayAge(10);
    
    function sayName(name) {
       console.log('hello ', name);
    }
    var sayAge = function(age) {
        console.log(age);
    };
    

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

    image.png

    调用foo()时,进入foo的执行上下文,所以输出10

    //全局上下文
    globalContext = {
        AO: {
            x: 10,
            foo: function,
            bar: function
        },
        scope: null
    }
    //在foo与bar声明时,自动生成如下作用域链引用
    foo.[[scope]] = globalContext.AO
    bar.[[scope]] = globalContext.AO
    
    //foo执行时
    fooContext = {
        AO: {
        
        },
        scope: foo.[[scope]]   //globalContext.AO
    }
    
    //bar执行时
    barContext = {
        AO: {
            x: 30
        },
        scope: bar.[[scope]]    //globalContext.AO
    }
    

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

    image.png

    输出30,调用foo()时,进入foo执行上下文,先查找bar的执行上下文中的x,所以输出30

    //全局上下文
    globalContext = {
        AO: {
            x: 10,
            bar: function
        },
        scope: null
    }
    //bar声明时自动生成
    bar.[[scope]] = globalContext.AO
    
    //bar执行时上下文
    barContext = {
        AO: {
            x: 30,
            foo: function
        }
        scope: bar.[[scope]]    //globalContext.AO
    }
    //foo声明时自动生成
    foo.[[scope]] = barContext.AO
    
    //foo执行上下文
    fooContext = {
        AO: {
    
        }
        scope: foo.[[scope]]    //barContext.AO
    }
    

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

    image.png

    输出30,立即执行函数执行时,进入匿名执行函数的执行上下文,先查找bar的执行上下文中的x,所以输出30

    //全局上下文
    globalContext = {
        AO: {
            x: 10,
            bar: function
        },
        scope: null
    }
    //bar声明时自动生成
    bar.[[scope]] = globalContext.AO
    
    //bar执行上下文
    barContext = {
        AO: {
            x: 30,
        }
        scope: bar.[[scope]]    //globalContext.AO
    }
    //匿名函数声明时自动生成
    function.[[scope]] = barContext.AO
    
    //匿名立即执行函数执行上下文
    functionContext = {
        AO: {
    
        }
        scope: function.[[scope]]   //barContext.AO
    }
    

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

    image.png
    var a = 1;
    
    function fn(){
      //输出undefined 先取fnContext中的a,此时a未赋值,所以是undefined
      console.log(a)
      var a = 5
      //输出5
      console.log(a)
      //此时 a = 6
      a++
      //相当于两次声明a,a会被覆盖,然后赋值
      var a
      //输出1 先取fn3Context中的a,未找到的情况下找globalContext中的a,此时globalContext中的a=1
      //fn3()执行完后,globalContext中的a=200
      fn3()
      //输出6 先取fn2Context中的a,未找到的情况下找fnContext中的a,此时fnContext中的a=6
      //fn2()执行完后,fnContext中的a=20
      fn2()
      //输出20
      console.log(a)
    
      function fn2(){
        console.log(a)
        a = 20
      }
    }
    
    function fn3(){
      console.log(a)
      a = 200
    }
    
    fn()
    //输出200
    console.log(a)
    

    作用域链伪代码:

    //全局上下文
    globalContext = {
        AO: {
            a: 1,
            fn: function,
            fn3: function 
        }
        scope: null
    }
    //fn声明时,自动生成作用域链引用
    fn.[[scope]] = globalContext.AO
    //fn3声明时,自动生成作用域链引用
    fn3.[[scope]] = globalContext.AO
    
    //fn执行时,fn的执行上下文
    fnContext = {
        AO: {
            a: 5.
            fn2: function
        },
        scope: fn.[[scope]]  //globalContext.AO
    }
    //fn2声明时,自动生成作用域链引用
    fn2.[[scope]] = fnContext.AO
    
    //fn3执行时,fn3的执行上下文
    fn3Context = {
        AO:{
    
        },
        scope: fn3.[[scope]]    //globalContext.AO
    }
    
    //fn2执行时,fn2的执行上下文
    fn2Context = {
       AO:{
    
        }
        scope: fn2.[[scope]]    //fnContext.AO
    }

    相关文章

      网友评论

          本文标题:JS函数与作用域

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