javascript中的范围很奇怪

时间:2015-06-19 05:30:53

标签: javascript function scope pass-by-reference

在javascript中传递对象及其引用。意味着应该反映任何地方对象的变化。 在这种情况下,console.log(a)的预期输出为{}

function change(a,b) {
    a.x = 'added';
    a = b;//assigning a as {} to b
}
a={}
b={}
change(a,b);
console.log(a); //expected {} but output {x:'added'}
console.log(b)

这里发生了什么?据我所知,这不应该是因为功能范围。 谢谢

6 个答案:

答案 0 :(得分:38)

如果您添加了另一行,您可以更清楚地了解正在发生的事情:

function change(a,b) {
    a.x = 'added';
    a = b;
    a.x = 'added as well';
};
a={};
b={};
change(a,b);
console.log(a);  //{x:'added'}
console.log(b);  //{x:'added as well'}

当您执行a = b时,您已将本地变量a分配给b所持有的引用。

答案 1 :(得分:22)

对象通过引用传递是正确的,对函数中对象所做的任何更改都将反映在任何地方。这正是为什么在函数中添加x属性修改了它之外的对象。

您缺少的是,a = b; 行不会修改对象 ,它会修改 对象的引用< / EM> 即可。如果需要设置引用,则可以传递另一个容器对象/数组中的两个对象:

function change(container) {
    container.a.x = 'added';
    container.a = container.b;//assigning a as {} to b
}
var container = { a: {}, b: {}};
change(container);
console.log(container.a);
console.log(container.b)

答案 2 :(得分:13)

变量&#39; a&#39;在你的功能上下文与&#39; a&#39;函数外的变量。此代码在语义上等同于您的代码:

function change(foo,bar) {
    foo.x = 'added';
    foo = bar;//assigning foo as {} to bar
}
a={}
b={}
change(a,b);
console.log(a); //expected {} but output {x:'added'}
console.log(b)

在这种情况下很明显,“foo”&#39; foo&#39;变量仅存在于函数内部,并且foo = bar不会更改a,因为引用按值传递。

答案 3 :(得分:10)

  

在javascript中传递对象及其引用。

不,他们不是。 ECMAScript / JavaScript严格按值传递。 (更准确地说,是分享呼叫,这是传递值的特殊情况。)

  

这里发生了什么?

这只是正常的按值传递。

你的困惑源于这样一个事实:你错误地认为ECMAScript / JavaScript是传递引​​用的,而实际上并非如此。

ECMAScript使用按值传递,或者更准确地说,是传递值的特殊情况,其中传递的值总是指针。这种特殊情况有时也称为分享呼叫,按对象分享或逐个呼叫。

它与Java(用于对象),C#(默认情况下用于引用类型),Smalltalk,Python,Ruby以及或多或少的所有面向对象语言所使用的约定相同。

注意:某些类型(例如Number s)实际上是通过直接传递的,而不是通过中间指针传递。但是,由于这些是不可变的,在这种情况下,传值和对象共享之间没有可观察到的行为差异,因此您可以通过简单地处理所有内容来大大简化您的心理模型作为对象分享。只需将这些特殊情况解释为内部编译器优化,您无需担心。

这是一个简单的例子,您可以运行以确定传递ECMAScript(或任何其他语言,翻译后)约定的参数:

function isEcmascriptPassByValue(foo) {
  foo.push('More precisely, it is call-by-object-sharing!');
  foo = 'No, ECMAScript is pass-by-reference.';
  return;
}

var bar = ['Yes, of course, ECMAScript *is* pass-by-value!'];

isEcmascriptPassByValue(bar);

console.log(bar);
// Yes, of course, ECMAScript *is* pass-by-value!,
// More precisely, it is call-by-object-sharing!

如果您熟悉C#,那么理解值类型和引用类型的传值和传递引用之间的差异是非常好的方法,因为C#支持所有4种组合:pass-by-值类型的值(“传统的按值传递”),引用类型的值传递(按共享调用,按对象调用,在ECMAScript中按对象分享),传递 - 引用类型的引用,以及值类型的引用传递。

(实际上,即使你知道C#,这也不难理解。)

// In C#, struct defines a value type, class defines a reference type
struct MutableCell
{
    public string value;
}

class Program
{
    // the ref keyword means pass-by-reference, otherwise it's pass-by-value
    // You must explicitly request pass-by-reference both at the definition and the call
    static void IsCSharpPassByValue(string[] foo, MutableCell bar, ref string baz, ref MutableCell qux)
    {
        foo[0] = "More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.";
        foo = new string[] { "C# is not pass-by-reference." };

        bar.value = "For value types, it is *not* call-by-sharing.";
        bar = new MutableCell { value = "And also not pass-by-reference." };

        baz = "It also supports pass-by-reference if explicitly requested.";

        qux = new MutableCell { value = "Pass-by-reference is supported for value types as well." };
    }

    static void Main(string[] args)
    {
        var quux = new string[] { "Yes, of course, C# *is* pass-by-value!" };

        var corge = new MutableCell { value = "For value types it is pure pass-by-value." };

        var grault = "This string will vanish because of pass-by-reference.";

        var garply = new MutableCell { value = "This string will vanish because of pass-by-reference." };

        // the first two are passed by value, the other two by reference
        IsCSharpPassByValue(quux, corge, ref grault, ref garply);

        Console.WriteLine(quux[0]);
        // More precisely, for reference types it is call-by-object-sharing, which is a special case of pass-by-value.

        Console.WriteLine(corge.value);
        // For value types it is pure pass-by-value.

        Console.WriteLine(grault);
        // It also supports pass-by-reference if explicitly requested.

        Console.WriteLine(garply.value);
        // Pass-by-reference is supported for value types as well.
    }
}

答案 4 :(得分:8)

好的,所以你已经发现JavaScript对象具有引用语义,因此修改引用对原始范围内的同一对象有影响。

您还需要意识到=不是这些规则的一部分;它不仅执行赋值,还会重新绑定对新对象的引用。

可以说,这基本上就是你的原始参考文献是如何形成的。

答案 5 :(得分:-1)

这应该有助于解决您的问题:

//populate pagination
function pagination(data) {
    var options = $("ul.pagination");
    var count = Object.keys(data).length;
    var buttons = (count / 12);
    //alert(buttons);
    for (var i = 1; i <= buttons; i++) {
        options.append($("<li />").html('<a class="page" id="' + i + '" href="#">' + i + '</a>'));
    }
}