javascript是传递引用还是传递值语言?

Is JavaScript a pass-by-reference or pass-by-value language?

《原始类型(数字、字符串等)是通过城市的价值,但目标是未知的,因为他们可以通过两个城市的价值(在情况下,我们考虑一个变量控股是在调查对象的参考对象)和通过城市的参考,当我们考虑的变量"球队的两个对象的对象本身)。

尽管它不比物,真的,我想知道什么是正确的方式通过指尖的题元公约。有个excerpt从JavaScript的规范,这场"语义应该怎么对我吗?


它在javascript中很有趣。考虑这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function changeStuff(a, b, c)
{
  a = a * 10;
  b.item ="changed";
  c = {item:"changed"};
}

var num = 10;
var obj1 = {item:"unchanged"};
var obj2 = {item:"unchanged"};

changeStuff(num, obj1, obj2);

console.log(num);
console.log(obj1.item);    
console.log(obj2.item);

这将产生输出:

1
2
3
10
changed
unchanged
  • 如果它是纯传递值,那么更改obj1.item将不会对函数外的obj1产生影响。
  • 如果它是纯引用传递的,那么一切都会发生变化。num100obj2.item"changed"

相反,情况是传入的项是按值传递的。但通过值传递的项本身就是一个引用。从技术上讲,这叫做共享呼叫。

实际上,这意味着,如果您更改参数本身(与numobj2一样),将不会影响输入参数的项。但是,如果您更改参数的内部结构,这将传播到备份(与obj1相同)。


它总是传递值,但对于对象,变量的值是一个引用。因此,当您传递一个对象并更改其成员时,这些更改将在函数之外持久存在。这使得它看起来像引用传递。但是,如果您实际更改了对象变量的值,您将看到更改不会持久,这证明它是传递值。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function changeObject(x) {
  x = {member:"bar"};
  alert("in changeObject:" + x.member);
}

function changeMember(x) {
  x.member ="bar";
  alert("in changeMember:" + x.member);
}

var x = {member:"foo"};

alert("before changeObject:" + x.member);
changeObject(x);
alert("after changeObject:" + x.member); /* change did not persist */

alert("before changeMember:" + x.member);
changeMember(x);
alert("after changeMember:" + x.member); /* change persists */

输出:

1
2
3
4
5
6
7
before changeObject: foo
in changeObject: bar
after changeObject: foo

before changeMember: foo
in changeMember: bar
after changeMember: bar


变量不"保存"对象,它保存一个引用。您可以将该引用赋给另一个变量,现在这两个变量都引用同一个对象。它总是传递值(即使该值是引用…)。

无法更改作为参数传递的变量所持有的值,如果JS支持通过引用传递,这是可能的。


我的2美分…这就是我理解它的方式。(如果我错了,请随时纠正我)

是时候抛开你所知道的关于传递值/引用的一切了。

因为在JavaScript中,不管它是通过值传递还是通过引用传递还是通过其他方式传递。重要的是变异与传递给函数的参数分配。

好吧,让我尽力解释一下我的意思。假设你有一些物品。

1
2
var object1 = {};
var object2 = {};

我们做的是"任务"…我们为变量"object1"和"object2"分配了两个独立的空对象。

现在,假设我们更喜欢对象1…所以,我们"分配"一个新的变量。

1
var favoriteObject = object1;

接下来,不管出于什么原因,我们决定我们更喜欢对象2。所以,我们只是做了一点重新分配。

1
favoriteObject = object2;

对象1或对象2没有发生任何事情。我们根本没有更改任何数据。我们所做的就是重新分配我们最喜欢的对象。重要的是要知道Object2和FavoriteObject都分配给同一个对象。我们可以通过这些变量中的任何一个来改变这个对象。

1
2
3
4
object2.name = 'Fred';
console.log(favoriteObject.name) // logs Fred
favoriteObject.name = 'Joe';
console.log(object2.name); // logs Joe

好吧,现在让我们来看看像字符串这样的原语

1
2
var string1 = 'Hello world';
var string2 = 'Goodbye world';

再次,我们选择一个最喜欢的。

1
var favoriteString = string1;

FavoriteString和String1变量都分配给"Hello World"。现在,如果我们想更改FavoriteString呢????会发生什么????

1
2
3
favoriteString = 'Hello everyone';
console.log(favoriteString); // Logs 'Hello everyone'
console.log(string1); // Logs 'Hello world'

哦…发生了什么。无法通过更改FavoriteString更改字符串1…为什么?因为字符串是不变的,我们没有改变它。我们所做的就是将FavoriteString"重新分配"到一个新字符串。这基本上使它与字符串1断开了连接。在上一个示例中,当我们重命名对象时,没有分配任何内容。(实际上…我们这样做了,我们将name属性分配给了一个新的字符串。)相反,我们只是改变了对象,它保持了2个变量和基础对象之间的连接。

现在,关于函数和传递参数……当您调用一个函数并传递一个参数时,实际上您要做的是对一个新变量进行"赋值",它的工作原理与您简单地使用等号(=)进行赋值时完全相同。

举个例子。

1
2
3
4
5
6
7
8
var myString = 'hello';

// Assign to a new variable (just like when you pass to a function)
var param1 = myString;
param1 = 'world'; // Re assignment

console.log(myString); // logs 'hello'
console.log(param1);   // logs 'world'

现在,同样的事情,但是有一个函数

1
2
3
4
5
6
7
8
9
10
11
function myFunc(param1) {
    param1 = 'world';

    console.log(param1);   // logs 'world'
}

var myString = 'hello';
// Calls myFunc and assigns param1 to myString just like param1 = myString
myFunc(myString);

console.log(myString); // logs 'hello'

好吧,现在让我们用对象来举几个例子…首先,没有这个功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var myObject = {
    firstName: 'Joe',
    lastName: 'Smith'
};

// Assign to a new variable (just like when you pass to a function)
var otherObj = myObject;

// Let's mutate our object
otherObj.firstName = 'Sue'; // I guess Joe decided to be a girl

console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Sue'

// Now, let's reassign
otherObj = {
    firstName: 'Jack',
    lastName: 'Frost'
};

// Now, otherObj and myObject are assigned to 2 very different objects
// And mutating one object no longer mutates the other
console.log(myObject.firstName); // Logs 'Sue'
console.log(otherObj.firstName); // Logs 'Jack';

现在,同样的事情,但是有一个函数调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function myFunc(otherObj) {

    // Let's mutate our object
    otherObj.firstName = 'Sue';
    console.log(otherObj.firstName); // Logs 'Sue'

    // Now let's re-assign
    otherObj = {
        firstName: 'Jack',
        lastName: 'Frost'
    };
    console.log(otherObj.firstName); // Logs 'Jack'

    // Again, otherObj and myObject are assigned to 2 very different objects
    // And mutating one object no longer mutates the other
}

var myObject = {
    firstName: 'Joe',
    lastName: 'Smith'
};

// Calls myFunc and assigns otherObj to myObject just like otherObj = myObject
myFunc(myObject);

console.log(myObject.firstName); // Logs 'Sue', just like before

好吧,如果你通读了这篇文章,也许你现在对函数调用如何在JavaScript中工作有了更好的理解。什么东西是通过引用还是通过值传递都无关紧要…重要的是分配与变异。

每次将变量传递给函数时,都会"分配"参数变量的名称,就像使用等号(=)一样。

始终记住等号(=)表示赋值。始终记住,向函数传递参数也意味着赋值。它们是相同的,两个变量以完全相同的方式连接。

修改一个变量影响另一个变量的唯一时间是在基础对象发生变化时。

区分对象和原语没有意义,因为它的工作方式与没有函数的工作方式完全相同,只是使用等号来分配给一个新变量。

唯一的问题是,当传递给函数的变量名与函数参数名相同时。当发生这种情况时,必须将函数中的参数视为函数私有的一个全新变量(因为它是)

1
2
3
4
5
6
7
8
9
10
function myFunc(myString) {
    // myString is private and does not affect the outer variable
    myString = 'hello';
}

var myString = 'test';
myString = myString; // Does nothing, myString is still 'test';

myFunc(myString);
console.log(myString); // logs 'test'


考虑以下事项:

  • 变量是指向内存中值的指针。
  • 重新分配变量只会将指针指向新值。
  • 重新分配变量不会影响指向同一对象的其他变量。
  • 因此,forget about"pass by reference/value"don't get hung up on"pass by reference/value"because:

  • 这些术语仅用于描述语言的行为,不一定是实际的底层实现。由于这种抽象,对于一个恰当的解释来说至关重要的关键细节会丢失,这不可避免地导致当前的情况,即一个术语不能充分描述实际行为,必须提供补充信息。
  • 这些概念最初并不是为了特别描述JavaScript而定义的,所以当它们只是增加了混乱时,我不觉得有必要使用它们。
  • 回答你的问题:指针被传递。

    < BR>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // code
    var obj = {
        name: 'Fred',
        num: 1
    };

    // illustration
                   'Fred'
                  /
                 /
    (obj) ---- {}
                 \
                  \
                   1

    < BR>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // code
    obj.name = 'George';


    // illustration
                     'Fred'


    (obj) ---- {} ----- 'George'
                 \
                  \
                   1

    < BR>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // code
    obj = {};

    // illustration
                     'Fred'


    (obj)      {} ----- 'George'
      |          \
      |           \
     { }            1

    < BR>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // code
    var obj = {
        text: 'Hello world!'
    };

    /* function parameters get their own pointer to
     * the arguments that are passed in, just like any other variable */

    someFunc(obj);


    // illustration
    (caller scope)        (someFunc scope)
               \             /
                \           /
                 \         /
                  \       /
                   \     /
                     { }
                      |
                      |
                      |
                'Hello world'

    一些最终意见:

    • 人们很容易认为原语是由特殊规则强制执行的,而对象不是,但原语只是指针链的末端。
    • 最后一个例子,考虑一下为什么清除数组的公共尝试不能按预期工作。

    < BR>

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

    a = [];
    console.log(b); // [1,2]
    // doesn't work because `b` is still pointing at the original array


    通过向外部obejct提供引用,将函数外部的对象传递给函数。当您使用该引用来操纵其对象时,外部对象就会受到影响。但是,如果在函数内部决定将引用指向其他对象,则根本不会影响外部的对象,因为您所做的只是将引用重新定向到其他对象。


    这样想:它总是按值传递的。但是,对象的值不是对象本身,而是对该对象的引用。

    下面是一个例子,传递一个数字(基元类型)

    1
    2
    3
    4
    5
    6
    7
    8
    function changePrimitive(val) {
        // At this point there are two '10's in memory.
        // Changing one won't affect the other
        val = val * 10;
    }
    var x = 10;
    changePrimitive(x);
    // x === 10

    对对象重复此操作会产生不同的结果:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function changeObject(obj) {
        // At this point there are two references (x and obj) in memory,
        // but these both point to the same object.
        // changing the object will change the underlying object that
        // x and obj both hold a reference to.
        obj.val = obj.val * 10;
    }
    var x = { val: 10 };
    changeObject(x);
    // x === { val: 100 }

    再举一个例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function changeObject(obj) {
        // Again there are two references (x and obj) in memory,
        // these both point to the same object.
        // now we create a completely new object and assign it.
        // obj's reference now points to the new object.
        // x's reference doesn't change.
        obj = { val: 100 };
    }
    var x = { val: 10 };
    changeObject(x);
    // x === { val: 10}

    javascript总是按值传递,所有内容都是值类型。对象是值,对象的成员函数是值本身(记住函数是JavaScript中的第一类对象)。另外,对于javascript中的所有内容都是对象的概念,这是错误的。字符串、符号、数字、布尔值、空值和未定义值都是基元。有时,它们可以利用从基本原型继承的一些成员函数和属性,但这只是为了方便起见,并不意味着它们本身就是对象。请参考以下内容

    1
    2
    3
    4
    x ="test";
    alert(x.foo);
    x.foo = 12;
    alert(x.foo);

    在这两个警报中,您将发现未定义的值。


    (P)在Javascript,the type of the value solely controls whether that value will be assigned by value-copy or by reference-copy.(p)(P)Primitive values are always assigned/passed by value-copy:(p)

    • 字母名称
    • 字母名称
    • 斯特朗
    • Number
    • 布尔
    • Symbol in EDOCX1音标2

    (P)Compound values are always assigned/passed by reference-copy(p)

    • Objects
    • 阿拉斯
    • 函数

    (P)For example(p)字母名称(P)In the above snippet,because ause EDOCX1 communal 3 is a scalar priority,EDOCX1 penal 4 communal holds one initial copy of that value,and EDOCX1 penal 5 communal is assigned another copy of the value.When changing EDOCX1 penography 5 sill,you are in no way changing the value in EDOCX1 penography 4.(p)(P)但是,EDOCX1的英文字母8和EDOCX1的英文字母9是分开的参考资料,即相同的共同价值EDOCX1的英文字母10,这是一个compound value。重要的是要注意到,Neither EDOCX1(英文)8/Nor EDOCX1(英文)9/more"owns"the EDOCX1(英文)10/Americal Value-both are just equal peer references to the value.So,when using either reference to modify(EDOCX1 penographic 14)the actual shared EDOCX1 penographic 15 welcue itself,it's affecting just the one shared value,and both reference s will reference the newly modified value EDOCX1.(p)字母名称(P)当我们把EDOCX1列为英文字母17时,我们绝对不想影响EDOCX1列为英文4的地方。To do that,EDOCX1 psychological 5 would be a point to EDOCX1 original 4-rather than a reference to the EDOCX1 psychological 15-but no such capability exists in JS!(p)字母名称(P)当我们通过在Argument EDOCX1的英文第4个字母,它将为EDOCX1的英文第4个字母提供参考。EDOCX1英文本25和EDOCX1英文本4在同一个EDOCX1英文本10中分选参考点。Now,Inside the Function,we can use that reference to mutate the value itself(EDOCX1 original 29).但是,当我们把EDOCX1拼写为30时,这不是一种方式来影响最初的参考书目EDOCX1的英文第4个字母是指向的地方——在(新修订的)EDOCX1的英文第16个字母是16个字母。(p)(P)为了有效地通过一个复合价值(类似于一个EDOCX1的字体15),由价值-copy确定,你需要手动使它成为一个联合体,因此,所通过的参考资料并不总是指向原始资料。For example:(p)字母名称(P)Compound value(object,array,etc)that can be passed by reference-copy(p)字母名称(P)这里,EDOCX1的第34个音符作为一个错误的行为为原始财产EDOCX1的字母4。When passed to EDOCX1 penographical 36,a copy of the EDOCX1 penographic 34 welcx1We now can use the EDOCX1 plograph 38 original reference to access the shared object,and update its property.在函数确定后,EDOCX1的英文字母40将看到最新的英文价值EDOCX1。(p)(P)Source(p)


    有关按值和参照复制、传递和比较的详细说明,请参阅"javascript:最终指南"一章。

    Before we leave the topic of
    manipulating objects and arrays by
    reference, we need to clear up a point
    of nomenclature. The phrase"pass by
    reference" can have several meanings.
    To some readers, the phrase refers to
    a function invocation technique that
    allows a function to assign new values
    to its arguments and to have those
    modified values visible outside the
    function. This is not the way the term
    is used in this book. Here, we mean
    simply that a reference to an object
    or array -- not the object itself --
    is passed to a function. A function
    can use the reference to modify
    properties of the object or elements
    of the array. But if the function
    overwrites the reference with a
    reference to a new object or array,
    that modification is not visible
    outside of the function. Readers
    familiar with the other meaning of
    this term may prefer to say that
    objects and arrays are passed by
    value, but the value that is passed is
    actually a reference rather than the
    object itself.

    有一件事我还是搞不清。检查下面的代码。有什么想法吗?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    function A() {}
    A.prototype.foo = function() {
        return 'initial value';
    }


    function B() {}
    B.prototype.bar = A.prototype.foo;

    console.log(A.prototype.foo()); //initial value
    console.log(B.prototype.bar()); //initial value

    A.prototype.foo = function() {
        return 'changed now';
    }

    console.log(A.prototype.foo()); //changed now
    console.log(B.prototype.bar()); //Why still 'initial value'???


    javascript通过值传递基元类型,通过引用传递对象类型

    Now, people like to bicker endlessly about whether"pass by reference"
    is the correct way to describe what Java et al. actually do. The point
    is this:

  • Passing an object does not copy the object.
  • An object passed to a function can have its members modified by the function.
  • A primitive value passed to a function cannot be modified by the function. A copy is made.
  • In my book that's called passing by reference.

    &#brian bi-哪些编程语言是通过引用传递的?

    更新

    以下是对此的反驳:

    在javascript中没有可用的"pass-by-reference"。


    语义学!!设置具体的定义必然会使某些答案和注释不兼容,因为即使使用相同的单词和短语,它们也不能描述相同的内容,但必须克服这种混淆(尤其是对于新程序员)。好的。

    首先,有多个抽象层次,并非每个人都能理解。学习过第4代或第5代语言的新程序员可能难以将自己的思想集中在汇编或C程序员所熟悉的概念上,而这些概念并不是由指向指向指针的指针来分段的。传递引用并不仅仅意味着能够使用函数参数变量更改被引用对象。好的。

    变量:符号的组合概念,它引用内存中特定位置的值。这个术语通常太重,不能单独用于讨论细节。好的。

    符号:用于引用变量(即变量名)的文本字符串。好的。

    值:存储在内存中并使用变量符号引用的特定位。好的。

    内存位置:存储变量值的位置。(位置本身由一个与存储在该位置的值分开的数字表示。)好的。

    函数参数:在函数定义中声明的变量,用于引用传递给函数的变量。好的。

    函数参数:调用方传递给函数的函数外部的变量。好的。

    对象变量:其基本基础值不是"对象"本身的变量,而是指向存储对象实际数据的内存中其他位置的指针(内存位置值)。在大多数高级语言中,"指针"方面通过在各种上下文中自动取消引用而被有效隐藏。好的。

    原语变量:其值为实际值的变量。即使这个概念被自动装箱和各种语言的类似对象的上下文复杂化,但是一般的观点是变量的值是由变量的符号表示的实际值,而不是指向另一个内存位置的指针。好的。

    函数参数和参数不同。此外,变量的值不是变量的对象(正如许多人已经指出的那样,但显然被忽略了)。这些区别对于正确理解至关重要。好的。

    传递值或共享调用(对于对象):函数参数的值被复制到另一个内存位置,该位置由函数的参数符号引用(无论它是在堆栈上还是堆上)。换句话说,函数参数收到了传递参数值的副本…和(关键)参数的值不会被调用函数更新/更改/更改。记住,对象变量的值不是对象本身,而是指向对象的指针,因此逐值传递对象变量会将指针复制到函数参数变量。函数参数的值指向内存中完全相同的对象。对象数据本身可以通过函数参数直接更改,但函数参数的值永远不会更新,因此它将在函数调用期间甚至之后继续指向同一个对象(即使其对象的数据被更改或函数参数被分配到一个不同的对象)。仅仅因为被引用的对象可以通过函数参数变量更新,所以推断函数参数是通过引用传递的是不正确的。好的。

    通过引用调用/传递:函数参数的值可以/将直接由相应的函数参数更新。如果有帮助,函数参数就成为参数的有效"别名"——它们在相同的内存位置有效地引用相同的值。如果函数参数是对象变量,则更改对象数据的能力与传递值的大小写没有区别,因为函数参数仍将指向与参数相同的对象。但是在对象变量的情况下,如果函数参数设置为完全不同的对象,那么参数也同样指向不同的对象——这在传递值的情况下不会发生。好的。

    javascript不通过引用传递。如果仔细阅读,您会发现所有相反的观点都误解了传递值的含义,并且错误地得出结论,即通过函数参数更新对象数据的能力与"传递值"同义。好的。

    对象克隆/复制:创建新对象并复制原始对象的数据。这可以是深拷贝或浅拷贝,但关键是创建了一个新对象。创建一个对象的副本是一个独立于传递值的概念。有些语言区分类对象和结构(或类似的),并且在传递不同类型的变量时可能有不同的行为。但在传递对象变量时,javascript不会自动执行类似的操作。但是缺少自动对象克隆并不能转化为按引用传递。好的。好啊。


    在javascript中向函数传递参数类似于传递C中指针值的参数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    /*
    The following C program demonstrates how arguments
    to JavaScript functions are passed in a way analogous
    to pass-by-pointer-value in C. The original JavaScript
    test case by @Shog9 follows with the translation of
    the code into C. This should make things clear to
    those transitioning from C to JavaScript.

    function changeStuff(num, obj1, obj2)
    {
        num = num * 10;
        obj1.item ="changed";
        obj2 = {item:"changed"};
    }

    var num = 10;
    var obj1 = {item:"unchanged"};
    var obj2 = {item:"unchanged"};
    changeStuff(num, obj1, obj2);
    console.log(num);
    console.log(obj1.item);    
    console.log(obj2.item);

    This produces the output:

    10
    changed
    unchanged
    */


    #include <stdio.h>
    #include <stdlib.h>

    struct obj {
        char *item;
    };

    void changeStuff(int *num, struct obj *obj1, struct obj *obj2)
    {
        // make pointer point to a new memory location
        // holding the new integer value
        int *old_num = num;
        num = malloc(sizeof(int));
        *num = *old_num * 10;
        // make property of structure pointed to by pointer
        // point to the new value
        obj1->item ="changed";
        // make pointer point to a new memory location
        // holding the new structure value
        obj2 = malloc(sizeof(struct obj));
        obj2->item ="changed";
        free(num); // end of scope
        free(obj2); // end of scope
    }

    int num = 10;
    struct obj obj1 = {"unchanged" };
    struct obj obj2 = {"unchanged" };

    int main()
    {
        // pass pointers by value: the pointers
        // will be copied into the argument list
        // of the called function and the copied
        // pointers will point to the same values
        // as the original pointers
        changeStuff(&num, &obj1, &obj2);
        printf("%d
    "
    , num);
        puts(obj1.item);
        puts(obj2.item);
        return 0;
    }


    这里有一些关于在JS中使用"pass-by-reference"一词的讨论,但要回答您的问题:

    A object is automatically passed by reference, without the need to specifically state it

    (摘自上述文章。)


    我理解这个的简单方法…

    • 调用函数时,您正在传递内容(引用或值),而不是变量本身。

      1
      2
      3
      4
      5
      var var1 = 13;
      var var2 = { prop: 2 };

      //13 and var2's content (reference) are being passed here
      foo(var1, var2);
    • 在函数内部,参数变量inVar1inVar2接收正在传递的内容。

      1
      2
      3
      4
      5
      function foo(inVar1, inVar2){
          //changing contents of inVar1 and inVar2 won't affect variables outside
          inVar1 = 20;
          inVar2 = { prop: 7 };
      }
    • 由于inVar2接收到{ prop: 2 }的引用,可以更改对象属性的值。

      1
      2
      3
      function foo(inVar1, inVar2){
          inVar2.prop = 7;
      }

    (P)In a low level language,if you want to pass a variable by reference you have to use a specific syntax in the creation of the function:(p)字母名称(P)The EDOCX1 Emoriginal 42 is a reference to EDOCX1 penographic 43,but if you want the value you have to turn the reference,using EDOCX1 penal 44.(p)(P)Javascript is a high level language that does this conversion for you.So,although objects are passed by reference,the language transforms the reference parameter to the value.You don't need to use EDOCX1 penal 45 nique,on the function definition,to pass it by reference,neither EDOCX1 pensic 46,on the function body,to turn the reference to the value,JS does it for you.(p)(P)That's why when you try to change an object inside a function,by replacing i t's value(I.E.EDOCX1 universal 47),the change doesn't persistent,but if you change i t's properties(I.E.EDOCX1),i t does.(p)(P)Learn More(p)


    (P)I've read through these answers multiple times,but did't really get i t until I learned about the technical definition of"call by sharing"as tered by Barbara Liskov(p)布尔奇1(P)如果你去和准军事人员接触,参数参考资料就会改变。On the other hand,assignment to a parameter will disappear after evaluation,and is non-accessible to the function caller.(p)


    对于编程语言律师,我已经阅读了ecmascript 5.1的以下部分(比最新版本更容易阅读),并在ecmascript邮件列表中询问了这些内容。

    tl;dr:所有的东西都是按值传递的,但是对象的属性都是引用,而且对象的定义在标准中极为缺乏。

    论元表的构造

    第11.2.4节"参数列表"说明了以下内容:生成仅由1个参数组成的参数列表:

    The production ArgumentList : AssignmentExpression is evaluated as follows:

  • Let ref be the result of evaluating AssignmentExpression.
  • Let arg be GetValue(ref).
  • Return a List whose sole item is arg.
  • 本节还列举参数列表中参数为0或大于1的情况。

    因此,所有的都是通过引用传递的。

    访问对象属性

    第11.2.1节"属性访问器"

    The production MemberExpression : MemberExpression [ Expression ] is evaluated as follows:

  • Let baseReference be the result of evaluating MemberExpression.
  • Let baseValue be GetValue(baseReference).
  • Let propertyNameReference be the result of evaluating Expression.
  • Let propertyNameValue be GetValue(propertyNameReference).
  • Call CheckObjectCoercible(baseValue).
  • Let propertyNameString be ToString(propertyNameValue).
  • If the syntactic production that is being evaluated is contained in strict mode code, let strict be true, else let
    strict be false.
  • Return a value of type Reference whose base value is baseValue and whose referenced name is
    propertyNameString, and whose strict mode flag is strict.
  • 因此,对象的属性始终可用作参考。

    参考文献

    第8.7节"引用规范类型"中描述了引用不是语言中的真实类型-它们仅用于描述删除、类型和赋值运算符的行为。

    "对象"的定义

    5.1版中定义了"对象是属性集合"。因此,我们可以推断,对象的值是集合,但是关于集合的值是什么在规范中定义不好,需要做一些努力才能理解。


    sharing what I know of references in javascript

    在javascript中,对象存储为引用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var a = {
      a: 1,
      b: 2,
      c: 3
    };
    var b = a;

    //b.c is referencing to a.c value
    console.log(b.c) //output: 3
    //changing value of b.c
    b.c = 4
    //also changes the value of a.c
    console.log(a.c) //output: 4


    对于pass-by值和pass-by引用(javascript),这只是一个小小的解释。在这个概念中,他们谈论的是通过引用传递变量和通过引用传递变量。

    传递值(基元类型)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var a = 3;
    var b = a;

    console.log(a); // a = 3
    console.log(b); // b = 3

    a=4;
    console.log(a); // a = 4
    console.log(b); // b = 3
    • 适用于JS中的所有基元类型(字符串、数字、布尔值、未定义、空)。
    • A被分配一个内存(比如说0x001),B在内存中创建一个值的副本(比如说0x002)。
    • 因此,改变一个变量的值不会影响另一个变量,因为它们都位于两个不同的位置。

    传递引用(对象)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var c = {"name" :"john" };    
    var d = c;

    console.log(c); // {"name" :"john" }
    console.log(d); // {"name" :"john" }

    c.name ="doe";

    console.log(c); // {"name" :"doe" }    
    console.log(d); // {"name" :"doe" }
    • JS引擎将对象分配给变量C,它指向一些内存,例如(0x012)
    • 当d=c时,在此步骤中,d指向相同的位置(0x012)。
    • 更改任何变量的值都会更改这两个变量的值。
    • 函数是对象

    特殊情况,通过引用(对象)

    1
    2
    3
    c = {"name" :"jane"};
    console.log(c); // {"name" :"jane" }    
    console.log(d); // {"name" :"doe" }
    • equal(=)运算符设置新的内存空间或地址


    我发现最简洁的解释是在Airbnb样式指南中:

    • 原语:当您访问原语类型时,您直接处理它的价值

      • 一串
      • 布尔
      • 无效的
      • 未定义

    例如。:

    1
    2
    3
    4
    5
    6
    var foo = 1,
        bar = foo;

    bar = 9;

    console.log(foo, bar); // => 1, 9
    • 复杂:当您访问复杂类型时,您处理对其值的引用。

      • 对象
      • 数组
      • 功能

    例如。:

    1
    2
    3
    4
    5
    6
    var foo = [1, 2],
        bar = foo;

    bar[0] = 9;

    console.log(foo[0], bar[0]); // => 9, 9

    也就是说,有效的基元类型通过值传递,复杂类型通过引用传递。


    MDN文档清楚地解释了这一点,而不是过于冗长:

    The parameters of a function call are the function's arguments.
    Arguments are passed to functions by value. If the function changes
    the value of an argument, this change is not reflected globally or in
    the calling function. However, object references are values, too, and
    they are special: if the function changes the referred object's
    properties, that change is visible outside the function, (...)

    来源:https://developer.mozilla.org/en-us/docs/web/javascript/reference/functions描述


  • 基元(数字、布尔值)按值传递。
    • 字符串是不可变的,所以对它们来说并不重要。
  • 对象通过引用传递(引用通过值传递)

  • 我发现当我想将对象作为一个参数传入时,underline.js库的extend方法非常有用,这个参数可以完全修改或替换。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function replaceOrModify(aObj) {
      if (modify) {

        aObj.setNewValue('foo');

      } else {

       var newObj = new MyObject();
       // _.extend(destination, *sources)
       _.extend(newObj, aObj);
      }
    }


    我想说是传过去的-

    考虑参数和变量对象是在函数调用开始时创建的执行上下文中创建的对象,而传递给函数的实际值/引用只存储在这个参数+变量对象中。

    简单地说,对于基元类型,值在函数调用的开头被复制,对于对象类型,引用被复制。


    确定某个东西是否是"通过引用传递"的一个简单方法是,您是否可以编写一个"交换"函数。例如,在C语言中,可以执行以下操作:

    1
    2
    3
    4
    5
    6
    7
    void swap(int *i, int *j)
    {
        int t;
        t = *i;
        *i = *j;
        *j = t;
    }

    如果你不能在javascript中做同样的工作,它就不是"通过引用"。


  • 基本类型变量,如string,number始终作为pass传递按价值计算。
  • 数组和对象根据这两个条件作为传递引用或传递值传递。

    • 如果用新对象或数组更改该对象或数组的值,则它是传递值。

      object1 = {item:"car"};
      array1=[1,2,3];

    在这里,您要将新对象或数组分配给旧对象或数组。旧对象的。所以它是传递值。

    • 如果要更改对象或数组的属性值,则它是按引用传递的。

      object1.key1="car";
      array1[0]=9;

    这里您正在更改旧对象的属性值。您没有将新对象或数组分配给旧对象或数组。因此它是按引用传递的。

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
        function passVar(object1, object2, number1) {

            object1.key1="laptop";
            object2 = {
                key2:"computer"
            };
            number1 = number1 + 1;
        }

        var object1 = {
            key1:"car"
        };
        var object2 = {
            key2:"bike"
        };
        var number1 = 10;

        passVar(object1, object2, number1);
        console.log(object1.key1);
        console.log(object2.key2);
        console.log(number1);

    Output: -
        laptop
        bike
        10


    在某些情况下,这可能有助于更改anArg

    1
    2
    3
    4
    5
    6
    7
    function alterMyArg(func) {
        // process some data
        // ...
        func(data);
    }

    alertMyArg(function(d) {anArg = d;});

    函数内部的简单值不会改变函数外部的那些值(它们是通过值传递的),而复杂值(它们是通过引用传递的)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    function willNotChange(x) {

    x = 1;

    }

    var x = 1000;

    willNotChange(x);

    document.write('After function call, x = ' + x + ''); //still 1000

    function willChange(y) {

    y.num = 2;

    }

    var y = {num: 2000};

    willChange(y);
    document.write('After function call y.num = ' + y.num + ''); //now 2, not 2000


    原语通过值传递,对象通过引用传递。这与C、VB或Delphi等其他语言截然不同。我不能说它们如何精确地处理对象和原语,但我知道vb和delphi可以(也应该)指定它。

    从版本5开始,PHP做了类似的事情:所有对象都是通过引用传递的,但是如果前面有一个和号(&;),所有原语都可以通过引用传递。否则,原语按值传递。

    所以在javascript中,如果我通过一个参数将一个对象x传递给一个函数,它仍然是x。如果你在函数内部更改数据(或者其他任何对象,但这并不重要),那么新的值也可以在函数外部使用。