JavaScriptは参照渡しまたは値渡しの言語ですか?

1462
Danail Nachev 2009-02-06 11:23.

プリミティブ型(数値、文字列など)は値で渡されますが、両方とも値で渡される可能性があるため、オブジェクトは不明です(オブジェクトを保持する変数が実際にはオブジェクトへの参照であると考える場合) )および参照渡し(オブジェクトへの変数がオブジェクト自体を保持していると見なす場合)。

最終的にはそれほど重要ではありませんが、規則を渡す引数を提示する正しい方法を知りたいと思います。これに関するセマンティクスを定義するJavaScript仕様からの抜粋はありますか?

23 answers

1665
deworde 2010-09-04 07:17.

JavaScriptで面白いです。この例を考えてみましょう。

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);

これにより、次の出力が生成されます。

10
changed
unchanged
  • obj1がまったく参照ではなかった場合、変更obj1.itemしてもobj1関数の外部には影響しません。
  • 引数が適切な参照である場合、すべてが変更されているはずです。numになり100、をobj2.item読み取ります"changed"

代わりに、渡されたアイテムが値で渡されるという状況です。ただし、値によって渡される項目自体は参照です。技術的には、これはcall-by-sharingと呼ばれます。

実際には、これは、パラメーター自体を(numおよびのようにobj2)変更しても、パラメーターに入力されたアイテムには影響しないことを意味します。ただし、パラメータのINTERNALSを変更すると、(のようにobj1)元に戻ります。

493
Tim Goodman 2011-03-16 06:38.

常に値で渡されますが、オブジェクトの場合、変数の値は参照です。このため、オブジェクトを渡してそのメンバーを変更すると、それらの変更は関数の外部で持続します。これにより、参照渡しのように見えます。しかし、実際にオブジェクト変数の値を変更すると、変更が持続しないことがわかり、実際に値が渡されていることが証明されます。

例:

function changeObject(x) {
  x = { member: "bar" };
  console.log("in changeObject: " + x.member);
}

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

var x = { member: "foo" };

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

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

出力:

before changeObject: foo
in changeObject: bar
after changeObject: foo

before changeMember: foo
in changeMember: bar
after changeMember: bar
156
Shog9 2009-02-06 11:37.

変数はオブジェクトを「保持」しません。参照を保持します。その参照を別の変数に割り当てることができ、両方が同じオブジェクトを参照するようになります。それは常に値によって渡されます(その値が参照である場合でも...)。

パラメータとして渡された変数が保持する値を変更する方法はありません。これは、JavaScriptが参照による受け渡しをサポートしている場合に可能です。

115
Ray Perea 2014-08-05 01:06.

私の2セント...これは私がそれを理解する方法です。(私が間違っている場合は、遠慮なく訂正してください)

値渡し/参照について知っていることをすべて捨てる時が来ました。

JavaScriptでは、値によって渡されるか、参照によって渡されるかなどは関係ありません。重要なのは、関数に渡されるパラメーターの突然変異と割り当てです。

OK、私が何を意味するのかを説明するために最善を尽くします。いくつかのオブジェクトがあるとしましょう。

var object1 = {};
var object2 = {};

私たちが行ったことは「割り当て」です...変数「object1」と「object2」に2つの別々の空のオブジェクトを割り当てました。

ここで、object1の方が好きだとしましょう...そこで、新しい変数を「割り当て」ます。

var favoriteObject = object1;

次に、何らかの理由で、オブジェクト2の方が好きだと判断します。そのため、少し再割り当てを行います。

favoriteObject = object2;

object1にもobject2にも何も起こりませんでした。データは一切変更していません。私たちがしたのは、お気に入りのオブジェクトを再割り当てすることだけでした。object2とfavoriteObjectの両方が同じオブジェクトに割り当てられていることを知っておくことが重要です。これらの変数のいずれかを介してそのオブジェクトを変更できます。

object2.name = 'Fred';
console.log(favoriteObject.name) // Logs Fred
favoriteObject.name = 'Joe';
console.log(object2.name); // Logs Joe

では、たとえば文字列などのプリミティブを見てみましょう。

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

繰り返しになりますが、お気に入りを選びます。

var favoriteString = string1;

私たちのfavoriteString変数とstring1変数の両方が「Helloworld」に割り当てられています。さて、favoriteStringを変更したい場合はどうなりますか?何が起こるか???

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

ええと....何が起こったのか。favouriteStringを変更してもstring1を変更できませんでした...なぜですか?? 文字列オブジェクトを変更しなかったためです。私たちが行ったのは、favoriteString変数を新しい文字列に「REASSIGN」することだけでした。これにより、基本的にstring1から切断されました。前の例では、オブジェクトの名前を変更したときに、何も割り当てませんでした。(まあ、変数自体ではなく、...ただし、nameプロパティを新しい文字列に割り当てました。)代わりに、2つの変数と基になるオブジェクトの間の接続を維持するオブジェクトを変更しました。(私たちは変更またはたいと思っていた場合であっても変異させる文字列オブジェクト自体を文字列はJavaScriptで実際に不変であるので、我々は、ありませんでした。)

次に、関数とパラメーターの受け渡しについて説明します。関数を呼び出してパラメーターを渡すと、基本的には新しい変数への「割り当て」が行われ、を使用して割り当てた場合とまったく同じように機能します。等号(=)。

これらの例を見てください。

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'

さて、同じことですが、機能があります

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'

では、代わりにオブジェクトを使用した例をいくつか挙げましょう...まず、関数を使用しません。

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 the variable
otherObj = {
    firstName: 'Jack',
    lastName: 'Frost'
};

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

さて、同じことですが、関数呼び出しがあります

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 doesn't magically mutate 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

OK、この投稿全体を読んだら、JavaScriptで関数呼び出しがどのように機能するかをよりよく理解できたと思います。何かが参照によって渡されるか値によって渡されるかは関係ありません...重要なのは割り当てと突然変異です。

変数を関数に渡すたびに、等号(=)を使用した場合と同じように、パラメーター変数の名前に「割り当て」ます。

等号(=)は代入を意味することを常に覚えておいてください。JavaScriptの関数パラメーターを渡すことは、代入も意味することを常に覚えておいてください。それらは同じであり、2つの変数はまったく同じ方法で接続されています(つまり、同じオブジェクトに割り当てられていると数えない限り、そうではありません)。

「変数の変更」が別の変数に影響を与えるのは、基になるオブジェクトが変更されたときだけです(この場合、変数は変更されていませんが、オブジェクト自体が変更されています。

オブジェクトとプリミティブを区別しても意味がありません。これは、関数がなく、等号を使用して新しい変数に割り当てる場合とまったく同じように機能するためです。

唯一の落とし穴は、関数に渡す変数の名前が関数パラメーターの名前と同じである場合です。これが発生した場合、関数内のパラメーターを、関数専用のまったく新しい変数であるかのように扱う必要があります(そうであるため)

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'
75
geg 2015-09-26 18:06.

次のことを考慮してください。

  1. 変数は、メモリ内の値へのポインタです。
  2. 変数を再割り当てすると、そのポインターが新しい値を指すだけです。
  3. 変数を再割り当てしても、同じオブジェクトを指している他の変数には影響しません。

したがって、「参照/値による受け渡し」 について 忘れてください。「参照/値による受け渡し」とらわれないでください 。理由は次のとおりです。

  1. これらの用語は、言語の動作を説明するためにのみ使用され、必ずしも実際の基礎となる実装ではありません。この抽象化の結果、適切な説明に不可欠な重要な詳細が失われ、必然的に、単一の用語が実際の動作を適切に説明せず、補足情報を提供する必要があるという現在の状況につながります。
  2. これらの概念は元々、特にjavascriptを説明することを目的として定義されていなかったため、混乱を招くだけの場合に使用する必要はありません。

あなたの質問に答えるために:ポインタが渡されます。


// code
var obj = {
    name: 'Fred',
    num: 1
};

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


// code
obj.name = 'George';


// illustration
                 'Fred'


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


// code
obj = {};

// illustration
                 'Fred'


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


// 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'

いくつかの最後のコメント:

  • プリミティブは特別なルールによって強制され、オブジェクトは強制されないと考えたくなりますが、プリミティブは単にポインタチェーンの終わりです。
  • 最後の例として、配列をクリアする一般的な試みが期待どおりに機能しない理由を検討してください。


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
24
user779764 2011-06-03 13:04.

関数の外部のオブジェクトは、外部のオブジェクトへの参照を与えることによって関数に渡されます。

その参照を使用してオブジェクトを操作すると、外部のオブジェクトが影響を受けます。ただし、関数内で参照を他の何かに向けることを決定した場合、参照を他の何かにリダイレクトするだけなので、外部のオブジェクトにはまったく影響しませんでした。

22
Phil Mander 2015-02-14 01:00.

このように考えてください:それは常に価値によって渡されます。ただし、オブジェクトの値はオブジェクト自体ではなく、そのオブジェクトへの参照です。

これは、数値(プリミティブ型)を渡す例です。

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

オブジェクトでこれを繰り返すと、異なる結果が得られます。

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つの例:

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}
20
igor 2011-05-13 12:20.

値と参照によるコピー、受け渡し、比較に関する非常に詳細な説明は、「JavaScript:TheDefinitiveGuide」ブックのこの章にあります

オブジェクトと配列を参照によって操作するというトピックを離れる前に、命名法のポイントを明確にする必要があります。

「参照渡し」というフレーズには、いくつかの意味があります。一部の読者にとって、この句は、関数が引数に新しい値を割り当て、それらの変更された値を関数の外部に表示できるようにする関数呼び出し手法を指します。これは、この本でこの用語が使用されている方法ではありません。

ここでは、オブジェクト自体ではなく、オブジェクトまたは配列への参照が関数に渡されることを意味します。関数は、参照を使用して、オブジェクトまたは配列の要素のプロパティを変更できます。ただし、関数が参照を新しいオブジェクトまたは配列への参照で上書きする場合、その変更は関数の外部には表示されません。

この用語の他の意味に精通している読者は、オブジェクトと配列は値によって渡されると言いたいかもしれませんが、渡される値は実際にはオブジェクト自体ではなく参照です。

18
Michael Roberts 2009-02-06 11:49.

JavaScriptは常に値渡しです; すべてが値タイプです。

オブジェクトは値であり、オブジェクトのメンバー関数はそれ自体が値です(関数はJavaScriptのファーストクラスオブジェクトであることを忘れないでください)。また、JavaScriptのすべてがオブジェクトであるという概念に関して; これは間違っています。文字列、記号、数値、ブール値、null、および未定義はプリミティブです。

場合によっては、ベースプロトタイプから継承された一部のメンバー関数とプロパティを利用できますが、これは便宜上のものです。それ自体がオブジェクトであるという意味ではありません。参考までに以下を試してください。

x = "test";
alert(x.foo);
x.foo = 12;
alert(x.foo);

どちらのアラートでも、値が未定義であることがわかります。

13
zangw 2015-12-30 16:20.

JavaScriptでは、値のタイプは、その値がvalue-copyまたはreference-copyのどちらで割り当てられるかを制御するだけです。

プリミティブ値は常に値コピーによって割り当て/渡されます

  • null
  • undefined
  • ストリング
  • ブール値
  • の記号 ES6

複合値は常に参照コピーによって割り当て/渡されます

  • オブジェクト
  • 配列
  • 関数

例えば

var a = 2;
var b = a; // `b` is always a copy of the value in `a`
b++;
a; // 2
b; // 3

var c = [1,2,3];
var d = c; // `d` is a reference to the shared `[1,2,3]` value
d.push( 4 );
c; // [1,2,3,4]
d; // [1,2,3,4]

上記のスニペットで2は、はスカラープリミティブであるためa、その値の1つの初期コピーを保持しb、値の別のコピーが割り当てられます。をb変更する場合、の値を変更することはありませんa

ただし、cdは両方とも[1,2,3]、複合値である同じ共有値への個別の参照です。値を「所有」することもcdそれ以上のこともしないことに注意することが重要です。どちらも[1,2,3]、値への同等のピア参照です。したがって、いずれかの参照を使用し.push(4)て実際の共有array値自体を変更()すると、1つの共有値にのみ影響し、両方の参照が新しく変更された値を参照します[1,2,3,4]

var a = [1,2,3];
var b = a;
a; // [1,2,3]
b; // [1,2,3]

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

割り当てを行うときb = [4,5,6]aまだ参照している場所に影響を与えることはまったくありません([1,2,3])。そのためには、-への参照ではなくbへのポインタである必要がありますが、JSにはそのような機能はありません!aarray

function foo(x) {
    x.push( 4 );
    x; // [1,2,3,4]

    // later
    x = [4,5,6];
    x.push( 7 );
    x; // [4,5,6,7]
}

var a = [1,2,3];

foo( a );

a; // [1,2,3,4]  not  [4,5,6,7]

引数を渡すaと、a参照のコピーがに割り当てられxます。xaは、同じ[1,2,3]値を指す個別の参照です。これで、関数内で、その参照を使用して値自体を変更できます(push(4))。ただし、割り当てを行う場合x = [4,5,6]、これは最初の参照aが指している場所にはまったく影響しません。それでも(現在変更されている)[1,2,3,4]値を指します。

複合値(のようなarray)をvalue-copyで効果的に渡すには、手動でコピーを作成して、渡された参照が元の値を指さないようにする必要があります。例えば:

foo( a.slice() );

参照コピーで渡すことができる複合値(オブジェクト、配列など)

function foo(wrapper) {
    wrapper.a = 42;
}

var obj = {
    a: 2
};

foo( obj );

obj.a; // 42

ここでobjは、スカラープリミティブプロパティのラッパーとして機能しますa。に渡されるfoo(..)と、obj参照のコピーが渡され、wrapperパラメータに設定されます。これで、wrapper参照を使用して共有オブジェクトにアクセスし、そのプロパティを更新できます。関数が終了obj.aすると、更新された値が表示されます42

ソース

10
kia nasirzadeh 2019-11-14 14:48.

まあ、それはプログラミング言語の「パフォーマンス」と「スピード」、そして簡単な言葉で「メモリ管理」についてです。

JavaScriptでは、私たちは2層に値を入れることができます:TYPE1 -objectsタイプ2のような値の-all他のタイプstringboolean&など

記憶を正方形の下のように想像すると、それらのすべてに1つのtype2値だけを保存できます。

すべてのtype2値(緑)は単一の正方形ですが、type1値(青)はそれらのグループです

重要なのは、type2値を示したい場合、アドレスは単純ですが、type1値に対して同じことをしたい場合は、まったく簡単ではないということです。:

そしてもっと複雑な話では:

したがって、ここでの参照は私たちを救うことができます:

ここでの緑色の矢印は典型的な変数ですが、紫色の矢印はオブジェクト変数です。したがって、緑色の矢印(典型的な変数)にはタスクが1つしかないため(つまり、典型的な値を示しています)、その値をから分離する必要はありません。そのため、緑色の矢印をその値とともに移動し、すべての割り当て、関数などで移動します...

しかし、紫色の矢印で同じことを行うことはできません。ここで「ジョン」セルを移動したい場合があります...したがって、紫色の矢印はその場所に固定され、それに割り当てられた典型的な矢印だけが移動します....。

非常に紛らわしい状況は、参照される変数がどのように変化するかを理解できない場合です。非常に良い例を見てみましょう。

let arr = [1, 2, 3, 4, 5]; //arr is an object now and a purple arrow is indicating it
let obj2 = arr; // now, obj2 is another purple arrow that is indicating the value of arr obj
let obj3 = ['a', 'b', 'c'];
obj2.push(6); // first pic below - making a new hand for the blue circle to point the 6
//obj2 = [1, 2, 3, 4, 5, 6]
//arr = [1, 2, 3, 4, 5, 6]
//we changed the blue circle object value (type1-value) and due to arr and obj2 are indicating that so both of them changed
obj2 = obj3; //next pic below - changing the direction of obj2 array from blue circle to orange circle so obj2 is no more [1,2,3,4,5,6] and it's no more about changing anything in it but we completely changed its direction and now obj2 is pointing to obj3
//obj2 = ['a', 'b', 'c'];
//obj3 = ['a', 'b', 'c'];

8
Ashish Singh Rawat 2018-09-26 07:31.

これは、値渡しと参照渡し(JavaScript)のもう少し説明です。この概念では、変数を参照で渡すことと、変数を参照で渡すことについて話し合っています。

値渡し(プリミティブ型)

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
  • JavaScriptのすべてのプリミティブ型(文字列、数値、ブール値、未定義、およびnull)に適用されます。
  • aにはメモリ(たとえば0x001)が割り当てられ、bはメモリ(たとえば0x002)に値のコピーを作成します。
  • したがって、変数の値を変更しても、どちらも2つの異なる場所にあるため、もう一方には影響しません。

参照渡し(オブジェクト)

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" }
  • JavaScriptエンジンは、オブジェクトを変数に割り当て、c(0x012)などのメモリを指します。
  • d = cの場合、このステップでdは同じ場所(0x012)を指します。
  • 値を変更すると、両方の変数の値が変更されます。
  • 関数はオブジェクトです

特殊なケース、参照渡し(オブジェクト)

c = {"name" : "jane"};
console.log(c); // { "name" : "jane" }
console.log(d); // { "name" : "doe" }
  • equal(=)演算子は、新しいメモリ空間またはアドレスを設定します
6
Zameer Ansari 2017-08-11 02:43.

JavaScriptでの参照について私が知っていることを共有する

JavaScriptでは、オブジェクトを変数に割り当てる場合、変数に割り当てられる値はオブジェクトへの参照です。

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

4
C Perkins 2016-12-24 08:43.

セマンティクス!! 具体的な定義を設定すると、同じ単語やフレーズを使用しても同じことを説明していないため、必然的に一部の回答とコメントに互換性がなくなりますが、混乱を乗り越えることが重要です(特に新しいプログラマーにとって)。

まず第一に、誰もが理解しているとは限らないように見える抽象化の複数のレベルがあります。第4世代または第5世代の言語で学習した新しいプログラマーは、アセンブリーに馴染みのある概念や、ポインターからポインターへのポインターによって段階的に実行されないCプログラマーに頭を悩ませることが難しい場合があります。参照渡しは、関数パラメーター変数を使用して参照オブジェクトを変更する機能を単に意味するものではありません。

変数:メモリ内の特定の場所にある値を参照するシンボルの概念を組み合わせたもの。この用語は通常、負荷が大きすぎて、詳細を説明する際に単独で使用することはできません。

記号:変数(つまり変数の名前)を参照するために使用されるテキスト文字列。

:メモリに格納され、変数のシンボルを使用して参照される特定のビット。

メモリの場所:変数の値が格納される場所。(場所自体は、その場所に格納されている値とは別の番号で表されます。)

関数パラメーター:関数定義で宣言された変数。関数に渡された変数を参照するために使用されます。

関数の引数:呼び出し元によって関数に渡される関数外の変数。

オブジェクト変数:基本的な基になる値が「オブジェクト」自体ではなく、その値がオブジェクトの実際のデータが格納されているメモリ内の別の場所へのポインタ(メモリ位置値)である変数。ほとんどの高世代言語では、「ポインタ」の側面は、さまざまなコンテキストでの自動参照解除によって効果的に隠されています。

プリミティブ変数:値が実際の値である変数。この概念でさえ、さまざまな言語の自動ボクシングやオブジェクトのようなコンテキストによって複雑になる可能性がありますが、一般的な考え方は、変数の値は、別のメモリ位置へのポインタではなく、変数のシンボルによって表される実際の値であるということです。

関数の引数とパラメーターは同じものではありません。また、変数の値は変数のオブジェクトではありません(さまざまな人々によってすでに指摘されていますが、明らかに無視されています)。これらの違いは、適切に理解するために重要です。

値渡しまたは共有呼び出し(オブジェクトの場合):関数の引数の値は、関数のパラメーターシンボルによって参照される別のメモリ位置にコピーされます(スタックまたはヒープのどちらにあるかに関係なく)。言い換えると、関数パラメーターは渡された引数の値のコピーを受け取りました... AND(クリティカル)引数の値は、呼び出し元の関数によって決して更新/変更/変更されません。オブジェクト変数の値はオブジェクト自体ではなく、オブジェクトへのポインターであるため、オブジェクト変数を値で渡すと、ポインターが関数パラメーター変数にコピーされることに注意してください。関数パラメーターの値は、メモリー内のまったく同じオブジェクトを指します。オブジェクトデータ自体は関数のパラメータを経由して直接変更することができますが、それがポイントに継続されますので、関数の引数の値は、更新されることはありません同じそのオブジェクトのデータが変更された場合でも(全体、さらには関数呼び出しの後にオブジェクトまたは場合関数パラメータには、まったく別のオブジェクトが割り当てられます)。参照されたオブジェクトが関数パラメーター変数を介して更新可能であるという理由だけで、関数の引数が参照によって渡されたと結論付けるのは誤りです。

呼び出し/参照渡し:関数の引数の値は、対応する関数パラメーターによって直接更新できます。それが役立つ場合、関数パラメータは引数の効果的な「エイリアス」になります。つまり、同じメモリ位置にある同じ値を効果的に参照します。関数の引数がオブジェクト変数の場合、関数のパラメーターは引数と同じオブジェクトを指すため、オブジェクトのデータを変更する機能は値渡しの場合と同じです。ただし、オブジェクト変数の場合、関数パラメーターが完全に異なるオブジェクトに設定されていると、引数も同様に別のオブジェクトを指します。これは、値渡しの場合には発生しません。

JavaScriptは参照渡しされません。よく読むと、すべての反対意見が値渡しの意味を誤解しており、関数パラメーターを介してオブジェクトのデータを更新する機能は「値渡し」と同義であると誤って結論付けていることがわかります。

オブジェクトの複製/コピー:新しいオブジェクトが作成され、元のオブジェクトのデータがコピーされます。これはディープコピーでもシャローコピーでもかまいませんが、重要なのは新しいオブジェクトが作成されるということです。オブジェクトのコピーの作成は、値渡しとは別の概念です。一部の言語は、クラスオブジェクトと構造体(など)を区別し、さまざまなタイプの変数を渡すための動作が異なる場合があります。ただし、JavaScriptは、オブジェクト変数を渡すときにこのようなことを自動的に行いません。ただし、オブジェクトの自動複製がないことは、参照渡しにはなりません。

4
georgeawg 2018-07-26 05:47.

JavaScriptは、プリミティブ型を値で渡し、オブジェクト型を参照で渡します

今、人々は、「参照渡し」がJava etal。を説明する正しい方法であるかどうかについて際限なく口論するのが好きです。実際にそうします。ポイントはこれです:

  1. オブジェクトを渡しても、オブジェクトはコピーされません。
  2. 関数に渡されるオブジェクトは、そのメンバーを関数によって変更することができます。
  3. 関数に渡されるプリミティブ値は、関数で変更することはできません。コピーが作成されます。

私の本では、それは参照渡しと呼ばれています。

-ブライアン・ゲイ-プログラミング言語は、参照渡しされていますか?


更新

これに対する反論は次のとおりです。

JavaScriptで利用できる「参照渡し」はありません。

3
dpp 2014-09-16 23:19.

これを理解する私の簡単な方法...

  • 関数を呼び出すときは、変数自体ではなく、引数変数の内容(参照または値)を渡します。

    var var1 = 13;
    var var2 = { prop: 2 };
    
    //13 and var2's content (reference) are being passed here
    foo(var1, var2); 
    
  • 関数内で、パラメーター変数、inVar1およびはinVar2、渡される内容を受け取ります。

    function foo(inVar1, inVar2){
        //changing contents of inVar1 and inVar2 won't affect variables outside
        inVar1 = 20;
        inVar2 = { prop: 7 };
    }
    
  • inVar2の参照を受け取ったので{ prop: 2 }、オブジェクトのプロパティの値を変更できます。

    function foo(inVar1, inVar2){
        inVar2.prop = 7; 
    }
    
3
John Sonderson 2014-11-02 02:43.

JavaScriptで関数に引数を渡すことは、Cでポインター値によってパラメーターを渡すことに似ています。

/*
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\n", num);
    puts(obj1.item);
    puts(obj2.item);
    return 0;
}
3
DannyNiu 2017-07-29 03:17.

プログラミング言語の弁護士のために、私はECMAScript 5.1(最新版よりも読みやすい)の次のセクションを読み、ECMAScriptメーリングリストでそれを尋ねるところまで行きました。

TL; DR:すべてが値で渡されますが、オブジェクトのプロパティは参照であり、オブジェクトの定義は標準に不気味に欠けています。

引数リストの作成

セクション11.2.4「引数リスト」は、1つの引数のみで構成される引数リストの作成について次のように述べています。

本番のArgumentList:AssignmentExpressionは、次のように評価されます。

  1. refをAssignmentExpressionの評価結果とします。
  2. argをGetValue(ref)とします。
  3. 唯一の項目がargであるリストを返します。

このセクションでは、引数リストに0または> 1の引数がある場合も列挙します。

したがって、すべてが参照によって渡されます。

Access of Object Properties

Section 11.2.1 "Property Accessors"

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

  1. Let baseReference be the result of evaluating MemberExpression.
  2. Let baseValue be GetValue(baseReference).
  3. Let propertyNameReference be the result of evaluating Expression.
  4. Let propertyNameValue be GetValue(propertyNameReference).
  5. Call CheckObjectCoercible(baseValue).
  6. Let propertyNameString be ToString(propertyNameValue).
  7. If the syntactic production that is being evaluated is contained in strict mode code, let strict be true, else let strict be false.
  8. Return a value of type Reference whose base value is baseValue and whose referenced name is propertyNameString, and whose strict mode flag is strict.

Thus, properties of Objects are always available as reference.

On Reference

It is described in section 8.7 "The Reference Specification Type", that references are not real types in the language - they're only used to describe the behavior of the delete, the typeof, and the assignment operators.

Definition of "Object"

It is defined in 5.1 edition that "An Object is a collection of properties". Therefore, we can infer, that the value of the object is the collection, but as to what is the value of the collection is poorly defined in the spec, and requires a bit of effort to understand.

3
miguelr 2019-04-20 20:06.

The MDN docs explain it clearly, without being too verbose:

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, (...)

Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Description

2
Jonas Wilms 2020-07-27 05:32.

observation: If there is no way for an observer to examine the underlying memory of the engine, there is no way to determine wether an immutable value gets copied or a reference gets passed.

JavaScript is more or less agnostic to the underlying memory model. There is no such thing as a reference². JavaScript has values. Two variables can hold the same value (or more accurate: two environment records can bind the same value). The only type of values that can be mutated are objects through their abstract [[Get]] and [[Set]] operations. If you forget about computers and memory, this is all you need to describe JavaScripts behaviour, and it allows you to understand the specification.

 let a = { prop: 1 };
 let b = a; // a and b hold the same value
 a.prop = "test"; // the object gets mutated, can be observed through both a and b
 b = { prop: 2 }; // b holds now a different value
 

Now you might ask yourself how two variables can hold the same value on a computer. You might then look into the sourcecode of a JavaScript engine and you'll most likely find something which a programmer of the language the engine was written in would call a reference.

So in fact you can say that JavaScript is "pass by value", whereas the value can be shared, you can say that JavaScript is "pass by reference", which might be a useful logical abstraction for programmers from low level languages, or you might call the behaviour "call by sharing". As there is no such thing as a reference in JavaScript, all of these are neither wrong nor on point. Therefore I don't think the answer is particularily useful to search for.

² The term Reference in the specification is not a reference in the traditional sense. It is a container for an object and the name of a property, and is an intermediate value (e.g. a.b evaluates to Reference { value = a, name = "b" }). The term reference also sometimes appears in the specification in unrelated sections.

1
lid 2014-05-17 15:01.

The most succinct explanation I found was in the AirBNB style guide:

  • Primitives: When you access a primitive type you work directly on its value

    • string
    • number
    • boolean
    • null
    • undefined

E.g.:

var foo = 1,
    bar = foo;

bar = 9;

console.log(foo, bar); // => 1, 9
  • Complex: When you access a complex type you work on a reference to its value

    • object
    • array
    • function

E.g.:

var foo = [1, 2],
    bar = foo;

bar[0] = 9;

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

I.e. effectively primitive types are passed by value, and complex types are passed by reference.

1
steviejay 2016-10-30 04:50.

I've read through these answers multiple times, but didn't REALLY get it until I learned about the technical definition of "Call by sharing" as termed by Barbara Liskov

The semantics of call by sharing differ from call by reference in that assignments to function arguments within the function aren't visible to the caller (unlike by reference semantics)[citation needed], so e.g. if a variable was passed, it is not possible to simulate an assignment on that variable in the caller's scope. However, since the function has access to the same object as the caller (no copy is made), mutations to those objects, if the objects are mutable, within the function are visible to the caller, which may appear to differ from call by value semantics. Mutations of a mutable object within the function are visible to the caller because the object is not copied or cloned — it is shared.

That is, parameter references are alterable if you go and access the parameter value itself. On the other hand, assignment to a parameter will disappear after evaluation, and is non-accessible to the function caller.

1
Narayon 2016-10-20 02:07.

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:

int myAge = 14;
increaseAgeByRef(myAge);
function increaseAgeByRef(int &age) {
  *age = *age + 1;
}

The &age is a reference to myAge, but if you want the value you have to convert the reference, using *age.

JavaScript is a high level language that does this conversion for you.

So, although objects are passed by reference, the language converts the reference parameter to the value. You don't need to use &, on the function definition, to pass it by reference, neither *, on the function body, to convert the reference to the value, JavaScript does it for you.

That's why when you try to change an object inside a function, by replacing it's value (i.e. age = {value:5}), the change doesn't persist, but if you change it's properties (i.e. age.value = 5), it does.

Learn more

Related questions

MORE COOL STUFF

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは、夫に会ったとき、典型的な交際のアドバイスに逆らいました。

マイケルシーンが非営利の俳優である理由

マイケルシーンが非営利の俳優である理由

マイケルシーンは非営利の俳優ですが、それは正確にはどういう意味ですか?

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。

「たどりつけば」をオンラインでストリーミングできない理由

「たどりつけば」をオンラインでストリーミングできない理由

ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

サロンからのヘアトリミングや個人的な寄付は、油流出を吸収して環境を保護するのに役立つマットとして再利用できます。

ホワイトハウスの最も記憶に残る結婚式を見てください

ホワイトハウスの最も記憶に残る結婚式を見てください

過去200年以上の間にホワイトハウスで結婚したのはほんの数人です。彼らは誰でしたか、そしてそこで結婚式を獲得するために何が必要ですか?

この太陽に優しいショルダーバッグで一日中外出してください

この太陽に優しいショルダーバッグで一日中外出してください

画像クレジット:Richard Mackney / Flickrトラベリングライトは必需品だけを運ぶことを意味するかもしれませんが、デバイスを補充する方法がない外出先では、接続を維持するのが難しくなる可能性があります。それはあなたがすべての生き物の快適さやクールなガジェットを捨てる必要があるという意味ではありません、ただあなたがいくつかのより小さなものを手に入れる必要があるということです、そしておそらくあなた自身をジュースに保つためにいくつかの、例えば非正統的な充電装置を使うでしょう。

ミッドセンチュリーリゾートのポストカードが廃墟に変わるのを見る

ミッドセンチュリーリゾートのポストカードが廃墟に変わるのを見る

ニューヨーク州スプリンググレンにある放棄されたホモワックロッジのボーリング場。キャッツキル南部のこの地域は、ニューヨーク市からのユダヤ人の行楽客に人気があることから、かつてはボルシチベルトとして知られていました。

ブルックリンスレートの美しいボードをあなたのテーブルに座らせましょう

ブルックリンスレートの美しいボードをあなたのテーブルに座らせましょう

ブルックリンスレートブルックリンスレートのマグカップとコースターの賞賛をすでに歌っており、それらの食器製品も同様に堅実です。ブルックリンスレートは、さまざまなサイズとテクスチャのスレートの完全な採石場を販売しています。一部のオプションは赤でも利用できます。上で見ることができるように、彼らは同様にカスタマイズをします。

遺伝子分析により、私たちの体内に生息する微生物の99%がカタログ化されていないことが明らかになりました

遺伝子分析により、私たちの体内に生息する微生物の99%がカタログ化されていないことが明らかになりました

画像:Juan Gaertner / Shutterstock私たちの体の内部は、私たちの細胞とは何の関係もない何十億もの微生物が住んでいる本物の生態系です。これがまだ少し気になることではなかったかのように、これらの微生物の99%が研究されたことがないことがわかりました。

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、生後4か月の娘、モナコに母乳育児をしていると語った。

投資ノート:Bioscout AU$300万シード

投資ノート:Bioscout AU$300万シード

Bioscoutは、農家を運転席に置くという使命を負っています。Artesian(GrainInnovate)やUniseedと並んで、最新のシードラウンドでチームを支援できることをうれしく思います。問題真菌症による重大な作物の損失は、農民にとって試練であることが証明されています。

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

リトルマーケットリサーチ1| 2022年のクイックグリンプス遠隔医療市場

遠隔医療は、パンデミック後の時代では新しいものではなく、時代遅れの分野でもありません。しかし、業界を詳しく見ると、需要と供給の強力な持続可能性と、米国で絶え間ない革命となる強力な潜在的成長曲線を示しています。

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

スタートアップ資金調達環境:タイのスタートアップエコシステムの次は何ですか?

2021年は、世界的なベンチャーキャピタル(VC)の資金調達にとって記録的な年でした。DealStreetAsiaによると、東南アジアも例外ではなく、この地域では年間で記録的な25の新しいユニコーンが採掘されました。

ムーアの法則を超えて

ムーアの法則を超えて

計算に対する私たちの欲求とムーアの法則が提供できるものとの間には、指数関数的に増大するギャップがあります。私たちの文明は計算に基づいています—建築と想像力の現在の限界を超える技術を見つけなければなりません。

Language