美文网首页
JS作用域链 & JS引用类型

JS作用域链 & JS引用类型

作者: antimony | 来源:发表于2019-03-14 23:22 被阅读0次

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

    在 Javascript 中,圆括号()是一种运算符,跟在函数名之后,表示调用该函数。比如,print()就表示调用print函数。

    有时,我们需要在定义函数之后,立即调用该函数。

    JavaScript 引擎规定,如果function关键字出现在行首,一律解释成语句。因此,JavaScript引擎看到行首是function关键字之后,认为这一段都是函数的定义,不应该以圆括号结尾,所以就报错了。

    解决方法就是不要让function出现在行首,让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里面。

    (function(){ /* code */ }());
    // 或者
    (function(){ /* code */ })();
    

    上面两种写法都是以圆括号开头,引擎就会认为后面跟的是一个表示式,而不是函数定义语句,所以就避免了错误。这就叫做“立即调用的函数表达式”(Immediately-Invoked Function Expression),简称 IIFE。

    通常情况下,只对匿名函数使用这种“立即执行的函数表达式”。它的目的有两个:一是不必为函数命名,避免了污染全局变量;二是 IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。

    // 写法一
    var tmp = newData;
    processData(tmp);
    storeData(tmp);
    
    // 写法二
    (function () {
      var tmp = newData;
      processData(tmp);
      storeData(tmp);
    }());
    

    求n!,用递归来实现。

    function factorial(num) {
      if(num>0) {
        return factorial(num-1)*num;
      }
      else return 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, '男');
        getInfo('小谷', 3);
        getInfo('男');
    

    输出:

    "name:"
    "饥人谷"
    "age:"
    2
    "sex:"
    "男"
    [object Arguments] {
      0: "饥人谷",
      1: 2,
      2: "男"
    }
    "name"
    "valley"
    "name:"
    "小谷"
    "age:"
    3
    "sex:"
    undefined
    [object Arguments] {
      0: "小谷",
      1: 3
    }
    "name"
    "valley"
    "name:"
    "男"
    "age:"
    undefined
    "sex:"
    undefined
    [object Arguments] {
      0: "男"
    }
    "name"
    "valley"
    

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

       function sumOfSquares(){
       }
       var result = sumOfSquares(2,3,4)
       var result2 = sumOfSquares(1,3)
       console.log(result)  //29
       console.log(result2)  //10
    

    答案:

    function sumOfSquares() {
      var result = 0;
       for(var i in arguments){
         result += (arguments[i]*arguments[i]);
       }
      return result;
    }
    

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

        console.log(a);
        var a = 1;
        console.log(b);
    

    undefined
    VM100:3 Uncaught ReferenceError: b is not defined at <anonymous>:3:17 (anonymous) @ VM100:3
    因为变量声明被提前变成:

    var a;
    console.log(a);
    a=1;
    console.log(b);
    

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

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

    输出:
    hello world
    VM1098:2 Uncaught TypeError: sayAge is not a function at <anonymous>:2:5 (anonymous) @ VM1098:2
    因为第一个函数声明被提前,变成:

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

    写一个函数squireArr,其参数是一个数组,作用是把数组中的每一项变为原值的平方

    var arr = [3, 4, 6]
    function squireArr( arr ){
        //var arr = 0x0011
        for(var i = 0; i < arr.length; i++){
            arr[i] = arr[i] * arr[i];
        }
    }
    squireArr(arr)
    console.log(arr)  // [9, 16, 36]
    

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

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

    输出:10
    因为变量和函数的声明被提前,所以代码等价于:

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

    又因为作用域链,所以:

    • 函数在执行的过程中,先从自己内部找变量
    • 如果找不到,再从创建当前函数所在的作用域去找, 以此往上
    • 注意找的是变量的当前的状态

    写一个函数squireArr,其参数是一个数组,返回一个新的数组,新数组中的每一项是原数组对应值的平方,原数组不变

    var arr = [3, 4, 6]
    function squireArr( arr ){
        var newArr = [];
        for(var i = 0; i < arr.length; i++){
            newArr[i] = arr[i] * arr[i];
        }
        return newArr;
    }
    var arr2 = squireArr(arr)
    console.log(arr)  // [3, 4, 6]
    console.log(arr2)  // [9, 16, 36]
    

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

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

    输出:30
    因为作用域链。

    • 函数在执行的过程中,先从自己内部找变量
    • 如果找不到,再从创建当前函数所在的作用域去找, 以此往上
    • 注意找的是变量的当前的状态

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

    var a = 1
    function fn1(){
      function fn2(){
        console.log(a)
      }
      function fn3(){
        var a = 4
        fn2()
      }
      var a = 2
      return fn3
    }
    var fn = fn1()
    fn() //输出多少
    

    输出2,因为作用域链。

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

    var a = 1
    function fn1(){
      function fn3(){
        var a = 4
        fn2()
      }
      var a = 2
      return fn3
    }
    function fn2(){
      console.log(a)
    }
    var fn = fn1()
    fn() //输出多少
    

    输出1,作用域链。


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

    var a = 1
    function fn1(){
    
      function fn3(){
        function fn2(){
          console.log(a)
        }
        fn2()
        var a = 4
      }
      var a = 2
      return fn3
    }
    var fn = fn1()
    fn() //输出多少
    

    输出:undefined
    因为声明提前和作用域链,fn3函数内等价于:

    function fn3(){
        var a;
        function fn2(){
          console.log(a)
        }
        fn2()
        a = 4
      }
      var a = 2
      return fn3
    

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

    var obj1 = {a:1, b:2};
    var obj2 = {a:1, b:2};
    console.log(obj1 == obj2);
    console.log(obj1 = obj2);
    console.log(obj1 == obj2);
    

    输出:
    false
    vendor.7ab21e702e7733b6b702.js:1 {a: 1, b: 2}
    vendor.7ab21e702e7733b6b702.js:1 true
    因为obj1和obj2一开始指向两个地址,在赋值后指向同一地址。


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

    var a = 1
    var c = { name: 'jirengu', age: 2 }
    
    function f1(n){
      ++n
    }
    function f2(obj){
      ++obj.age
    }
    
    f1(a) 
    f2(c) 
    f1(c.age) 
    console.log(a) 
    console.log(c)     
    

    输出:
    1
    {name: "jirengu", age: 3}
    因为第一个是值传递,第二个是引用传递。


    写一个深拷贝函数。

    function deepCopy(oldObj) {
            var newObj = {};
            for(var key in oldObj) {
                if(typeof oldObj[key] === 'object') {
                    newObj[key] = deepCopy(oldObj[key]);//递归调用
                }else{
                    newObj[key] = oldObj[key];
                }
            }
            return newObj;
        }
    

    相关文章

      网友评论

          本文标题:JS作用域链 & JS引用类型

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