Javascript - 原始与引用类型

时间:2014-12-07 08:32:22

标签: javascript pass-by-reference

在下面的代码中,我们传递一个对象。所以,根据javascript我们正在传递引用和操作。

var a = new Number(10);
x(a);
alert(a);

function x(n) {
n = n + 2;
}

但是警告10而不是12.为什么?

6 个答案:

答案 0 :(得分:10)

n位于x的本地,首先它设置为与全局a相同的引用。然后将右侧n + 2评估为数字(基元)。 作业的左侧n永远不会被评估,只是一个标识符。所以我们的局部变量现在设置为右侧的原始值。 a引用的值永远不会被实际修改。参见

var a = new Number(10);
x(a);
alert(a);  // 10

function x(n) {
  alert(typeof n);  // object
  n = n + 2;
  alert(typeof n);  // number
}

答案 1 :(得分:4)

计算时

n + 2

这导致一个新的"本机号码"即使n确实是Number对象实例。

分配给n然后只更改本地变量n引用的内容,并且不会更改Number对象实例。你可以用

看到
n = new Number(10);
console.log(typeof n);     // ---> "object"
console.log(n + 2);        // ---> 12
console.log(typeof (n+2)); // ---> "number"
n = n + 2;
console.log(typeof n);     // ---> "number"

在Javascript(或Python或Lisp)中,没有办法传递"地址"一个变量,以便被调用的函数改变它。你唯一能做的就是传递一个setter函数......例如:

function foo(setter) {
    setter(42);
}

funciton bar() {
    var x = 12;
    foo(function(newx){x = newx;});
    console.log(x); // ---> 42
}

答案 2 :(得分:2)

让我试着用例子来回答:

function modify(obj) {
    // modifying the object itself
    // though the object was passed as reference
    // it behaves as pass by value
    obj = {c:3};
}

var a = {b:2}
modify(a);
console.log(a)
// Object {b: 2}

function increment(obj) {
    // modifying the value of an attribute
    // working on the same reference
    obj.b = obj.b + 1;
}

var a = {b:2}
increment(a);
console.log(a)
// Object {b: 3}

function augument(obj) {
    // augument an attribute
    // working on the same reference
    obj.c = 3;
}

var a = {b:2}
augument(a);
console.log(a)
// Object {b: 2, c: 3}

请参阅JSFiddle了解工作演示。

答案 3 :(得分:2)

答案很简单:因为ECMAScript是按值传递而不是传递引用,并且您的代码证明了这一点。 (更确切地说,它是分享呼叫,这是一种特定的传递值。)

请参阅Is JavaScript a pass-by-reference or pass-by-value language?了解更多信息。

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

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

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

这是一个简单的例子,您可以运行以确定传递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#,这也不难理解。)

struct MutableCell
{
    public string value;
}

class Program
{
    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." };

        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 :(得分:0)

var a = new Number(10);    
x(a);
alert(a);

function x(n) {
    n = n + 2; // NOT VALID as this would essentially mean 10 = 10 + 2 since you are passing the 'value' of a and not 'a' itself
}

您需要编写以下内容才能使其正常工作

var a = new Number(10);
x(a);
alert(a);

function x(n) {
    a = n + 2; // reassign value of 'a' equal to the value passed into the function plus 2
}

答案 5 :(得分:0)

JavaScript参数传递的工作方式类似于Java。单个值按值传递,但对象属性通过其指针值通过引用传递。值本身不会在函数中修改,但会修改对象的属性。

请考虑以下代码:

function doThis(param1, param2) {
    param1++;
    if(param2 && param2.value) {
        param2.value++;
    }
}

var initialValue = 2;
var initialObject = {value: 2};

doThis(initialValue, initialObject);

alert(initialValue); //2
alert(initialObject.value); //3

http://jsfiddle.net/bfm01b4x/