美文网首页
函数传参的问题

函数传参的问题

作者: 209bd3bc6844 | 来源:发表于2017-05-27 14:32 被阅读0次

    函数传参

    值和引用

    JavaScript 中没有指针,引用的工作机制也不尽相同。在 JavaScript 中变量不可能成为指向 另一个变量的引用。
    JavaScript 引用指向的是值。如果一个值有 10 个引用,这些引用指向的都是同一个值,它 们相互之间没有引用 / 指向关系。
    JavaScript 对值和引用的赋值 / 传递在语法上没有区别,完全根据值的类型来决定。

    var a = 2;
    var b = a; // b是a的值的一个副本 b++;
    a; // 2
    b; // 3
    var c = [1,2,3];
    var d = c; // d是[1,2,3]的一个引用 d.push( 4 );
    c; // [1,2,3,4]
    d; // [1,2,3,4]
    
    

    上例中 2 是一个标量基本类型值,所以变量 a 持有该值的一个复本,b 持有它的另一个复 本。b 更改时,a 的值保持不变。
    c 和 d 则分别指向同一个复合值 [1,2,3] 的两个不同引用。请注意,c 和 d 仅仅是指向值 [1,2,3],并非持有。所以它们更改的是同一个值(如调用 .push(4)),随后它们都指向更 改后的新值 [1,2,3,4]。
    由于引用指向的是值本身而非变量,所以一个引用无法更改另一个引用的指向。

    var a = [1,2,3];
         var b = a;
         a; // [1,2,3]
         b; // [1,2,3]
    // 然后
    b = [4,5,6]; 
    a; // [1,2,3]
     b; // [4,5,6]
    

    b=[4,5,6] 并不影响 a 指向值 [1,2,3],除非 b 不是指向数组的引用,而是指向 a 的指针, 但在 JavaScript 中不存在这种情况!
    函数参数就经常让人产生这样的困惑:

    function foo(x) {
             x.push( 4 );
             x; // [1,2,3,4]
            // 然后
            x = [4,5,6]; 
            x.push( 7 ); 
            x; // [4,5,6,7]
    }
    var a = [1,2,3];
    foo( a );
    a; // 是[1,2,3,4],不是[4,5,6,7]
    

    我们向函数传递 a 的时候,实际是将引用 a 的一个复本赋值给 x,而 a 仍然指向 [1,2,3]。 在函数中我们可以通过引用x来更改数组的值(push(4)之后变为[1,2,3,4])。但x = [4,5,6] 并不影响 a 的指向,所以 a 仍然指向 [1,2,3,4]。
    我们不能通过引用 x 来更改引用 a 的指向,只能更改 a 和 x 共同指向的值。如果要将 a 的值变为 [4,5,6,7],必须更改 x 指向的数组,而不是为 x 赋值一个新的数组。

    传参中有this隐式丢失

    function foo() {
     console.log( this.a );
    }
    var obj = {
       a: 2,
       foo: foo
     };
    var bar = obj.foo; // 函数别名!
    var a = "oops, global"; // a是全局对象的属性 bar(); // "oops, global"
    

    虽然 bar 是 obj.foo 的一个引用,但是实际上,它引用的是 foo 函数本身,因此此时
    的 bar() 其实是一个不带任何修饰的函数调用,因此应用了默认绑定。

    一种更微妙、更常见并且更出乎意料的情况发生在传入回调函数时:

    var foo = {
        bar: function() { return this.baz; },
        baz: 1
      };
    var baz = 2;
      (function(fn){
        // fn其实引用的是foo
        return    fn(); // <-- 调用位置! fn和foo.bar指向同一块内存函数。
      })(foo.bar);   // 2
    
    

    参数传递其实就是一种隐式赋值,因此我们传入函数时也会被隐式赋值,所以结果和上一 个例子一样。并且因为this是动态作用域所以调用时候决定值,打印出2

    var foo = {
        bar: function() { alert(baz); },
        baz: 1
      };
    var baz = 2;
      (function(fn){
        // fn其实引用的是foo
        var baz = 3;
        return    fn(); // <-- 调用位置!
      })(foo.bar);   // 2  这里不是this所以是词法作用域解析时候就决定了这里打印2而不是3
    

    使用arguments改变参数指向环境

    
    var foo = {
        bar: function() { return this.baz; },
        baz: 1
      };
    var baz = 2;
      (function(){
        arguments.baz = 3;
        return arguments[0]();  // arguments是一个结构可以转换为数组的对象。所以这里 arguments[0] 把this上下文指向了 arguments。 不是foo  也不是window。
      })(foo.bar);  //  3
    
    

    相关文章

      网友评论

          本文标题:函数传参的问题

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