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


1404

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

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


2
値渡しと参照渡しの定義を誤って反転させたと思います... "値渡し"(オブジェクトを保持する変数が実際にはオブジェクトへの参照であると考える場合)と参照による(オブジェクトへの変数がオブジェクト自体を保持していると考える場合) "
Niko Bellic 2014

5
はい。構文に関係なく、プログラミング言語の関数呼び出しでは、参照渡しは、渡された変数に関連付けられたデータが関数に渡されたときにコピーされないため、渡された変数に対して関数によって行われた変更は保持されます。関数呼び出しが終了した後のプログラム内。値渡しとは、変数に関連付けられたデータが関数に渡されるときに実際にコピーされることを意味し、関数が戻るときに変数が関数の本体のスコープから外れると、そのような関数によってそのような変数に加えられた変更は失われます。
John Sonderson 2014年

5
この古い質問は、かなり支持されている答えが正しくないため、やや有毒です。JavaScriptは厳密に値渡しです
2015年

6
@DanailNachev用語は残念ながら混乱しています。問題は、「値渡し」と「参照渡し」は、より多くの最新のプログラミング言語機能に先行する用語です。「値」および「参照」という語は、関数呼び出し式に現れるパラメーターを具体的に指します。JavaScriptは常に、関数を呼び出す前に関数呼び出しパラメーターリストの各式を評価するため、パラメーターは常に値です。混乱する部分は、オブジェクトへの参照が一般的なJavaScript値であることです。ただし、「参照渡し」言語にはなりません。
2015

2
@DanailNachev「参照渡し」は、具体的にあなたが持っている場合ことを意味しvar x=3, y=x; f(x); alert(y === x);、関数がf()警告レポートを作ることができません。JavaScriptではそれができないため、参照渡しではありません。変更可能なオブジェクトへの参照を渡すことができるのは良いことですが、それが「参照渡し」が意味するものではありません。私が言ったように、用語がとても混乱しているのは残念です。falsetrue
先のとがっ

回答:


1598

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)上に伝搬します。


32
これはC#とまったく同じ(または少なくとも意味的に)です。オブジェクトには、値(プリミティブ型)と参照の2つのタイプがあります。
Peter Lee

53
これはJavaでも使用されていると思います。値による参照です。
Jpnh

296
本当の理由は、changeStuff内で、num、obj1、およびobj2が参照であることです。itemobj1によって参照されるオブジェクトのプロパティを変更すると、元々「変更なし」に設定されていたアイテムプロパティの値が変更されます。obj2に{item: "changed"}の値を割り当てると、新しいオブジェクトへの参照が変更されます(関数が終了するとすぐにスコープから外れます)。関数paramsにnumf、obj1f、obj2fなどの名前を付けると、何が起こっているかがより明確になります。次に、paramsが外部変数名を隠していたことがわかります。
jinglesthula 2012年

13
@BartoNaz本当に。必要なのは、参照を値で渡すのではなく、参照で渡すことです。しかし、JavaScriptは常に他のすべてを値で渡すように、参照を値で渡します。(比較のために、C#にはJavaScriptやJavaに似た値渡しの動作がありますが、refキーワードを使用して参照渡しを指定できます。)通常、関数は新しいオブジェクトを返すだけで、関数を呼び出すポイントでの割り当て。たとえば、foo = GetNewFoo();代わりにGetNewFoo(foo);
Tim Goodman

56
この回答が最も一般的ですが、「値による純粋な受け渡し」であると記載されているため、少し混乱する可能性があります。JavaScript 純粋な値渡しです。ただし、渡される値は参照です。これは、パラメーターの受け渡しにまったく制約されません。変数をコピーするだけvar obj1 = { item: 'unchanged' }; var obj2 = obj1; obj2.item = 'changed';で、例と同じ効果が得られます。したがって、私は個人的にTim Goodmanの答えを参照します
チッコドロ

476

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

例:

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

14
@daylight:実際、あなたは間違っています。const refによって渡された場合、changeObjectを実行しようとすると、失敗するだけでなくエラーが発生します。C ++でconst参照に新しい値を割り当ててみてください。コンパイラーはそれを拒否します。ユーザー用語では、それが値渡しとconst参照渡しの違いです。
deworde 2011

5
@daylight:一定の参照ではありません。ではchangeObjectx新しいオブジェクトへの参照を含むように変更しました。x = {member:"bar"};同等であるx = new Object(); x.member = "bar"; 方法によって、また、Cの#の真実である私は何を言っています。
Tim Goodman

2
@daylight:C#の場合、あなたが使用している場合、関数外部からこれを見ることができるrefキーワードを使用すると、(代わりに値によって参照を渡すデフォルトの)参照によって参照を渡すことができ、その後にポイントが変更さnew Object() れます存続。
Tim Goodman、

11
@adityamenon「なぜ」と答えるのは難しいですが、JavaとC#の設計者が同様の選択をしたことに気づくでしょう。これは単なるJavaScriptの奇妙さではありません。実際、これは非常に一貫して値渡しであり、人々を混乱させるのは、値が参照になる可能性があることです。C ++で(値によって)ポインターを渡し、それを逆参照してメンバーを設定することと大差ありません。その変化が持続することに誰も驚かないでしょう。しかし、これらの言語はポインタを抽象化し、静かに逆参照を行うため、人々は混乱します。
Tim Goodman

41
言い換えれば、ここで混乱するのは、値渡し/参照渡しではありません。すべてが値渡しの完全なストップです。混乱するのは、オブジェクトを渡すことも、変数にオブジェクトを格納することもできないということです。あなたがそうしていると思うたびに、あなたは実際にそのオブジェクトへの参照を渡したり保存したりしています。しかし、そのメンバーにアクセスすると、サイレント逆参照が発生し、変数が実際のオブジェクトを保持しているというフィクションが永続します。
Tim Goodman

150

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

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


2
これは私を少し混乱させます。参照渡しの参照を渡していませんか?

8
著者は、参照を渡すことによって、参照値を渡すことを意味します(メモリアドレスの値を渡すことで、別の見方をすることができます)。したがって、オブジェクトを再宣言しても、別のメモリ位置に新しいオブジェクトを作成しているため、元のオブジェクトは変更されません。プロパティを変更すると、元のメモリ位置(再割り当てされなかった)で変更されたため、元のオブジェクトが変更されます。
Huy-Anh Hoang 2017年

113

私の2セント...これが私の理解です。(私が間違っている場合は自由に修正してください)

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

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

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

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変数の両方が「Hello world」に割り当てられています。では、favoriteStringを変更したい場合はどうでしょうか??? 何が起こるか???

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

ええと....何が起こったのですか。FavoriteStringを変更してstring1を変更できませんでした...なぜですか?文字列オブジェクトを変更しなかったためです。私たちが行ったのは、favoriteString 変数を新しい文字列に "RE ASSIGN"することだけです。これは本質的にそれを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

わかりました。この投稿全体を読んでおけば、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'

2
すべてのCプログラマーにとって、char *を考えてください。 foo(char *a){a="hello";} 何もしませんが、文字列(char配列)を参照する値によって渡されるメモリの場所foo(char *a){a[0]='h';a[1]='i';a[2]=0;}であるためa、変更すると外部で変更されます。Cの値で構造体(jsオブジェクトと同様)を渡すことは許可されていますが、お勧めできません。JavaScriptは単にこれらのベストプラクティスを適用し、不必要な、通常は望ましくない残骸を隠します...そしてそれは確かに読みやすくなります。
テクノサウルス2015年

2
これは正しいです。値渡し参照渡しという用語は、プログラミング言語の設計では意味があり、それらの意味はオブジェクトの変更とはまったく関係がありません。関数のパラメーターがどのように機能するかがすべてです。
2015年

2
obj1 = obj2は、obj1とobj2の両方が同じ参照場所を指していることを理解したので、obj2の内部を変更すると、obj1を参照すると同じ内部が公開されます。オブジェクトをコピーして、source = { "id":"1"}; copy = source /*this is wrong*/; copy.id="2"そのソースがまだ{"id": "1"}であるようにするにはどうすればよいですか?
Machtyn 2016

1
混乱を減らすために、従来の定義で別の回答を投稿しました。「値渡し」と「参照渡し」の従来の定義は、自動逆参照の前のメモリポインタの日に定義されていました。オブジェクト変数の値が実際にはオブジェクトではなくメモリポインタの場所であることは完全に理解されていました。代入vs変異についてのあなたの議論はおそらく有用ですが、従来の用語やその定義を捨てる必要はありません。突然変異、代入、値渡し、参照渡しなどは、互いに矛盾してはなりません。
Cパーキンス

「数値」も「不変」ですか?
エブラムハリル2017年

72

以下を検討してください。

  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

追加のクレジットのフォローアップ質問;)ガベージコレクションはどのように機能しますか?変数を100万個の{'George', 1}値に循環させても、一度に1つしか使用しない場合、他の値はどのように管理されますか?また、変数を別の変数の値に代入するとどうなりますか?次に、ポインタを指しているのか、それとも正しいオペランドの指示先を指しているのか?DOESのvar myExistingVar = {"blah", 42}; var obj = myExistingVar;中に結果objを指し{"blah", 42}、またはにmyExistingVar
Michael Hoffmann

@MichaelHoffmannこれらは独自のSOの質問に値するものであり、おそらく私が管理できる範囲よりも適切に回答されています。そうは言っても、1)私はあなたが記述したようなループ機能のためにブラウザー開発ツールでメモリプロファイルを実行し、ループプロセス全体のメモリ使用量のスパイクを見ました。これは、ループの各反復で新しい同一のオブジェクトが実際に作成されていることを示しているようです。スパイクが突然落ちると、ガベージコレクターはこれらの未使用のオブジェクトのグループをクリーンアップしました。
geg

1
@MichaelHoffmannの2)ようなものに関してはvar a = b、JavaScriptはポインターを使用するためのメカニズムを提供しないため、基礎となるJavaScriptエンジンは間違いなくそれらを使用しますが、変数はポインターを指すことができません(Cの場合と同様)。だから... 「正しいオペランドの指示先var a = bを指すa
geg

(実装はすべてのブラウザでは異なる可能性がありますので、特にクロムについて)私はここに質問#1を尋ねstackoverflow.com/q/42778439/539997し、私はまだどのように単語の質問#2に考えるしようとしています。どんな助けでもありがたいです。
Michael Hoffmann

1
「参照/値による受け渡し」忘れる必要はありません。これらの用語には、あなたが説明しようとしていることを正確に説明する歴史的な意味があります。歴史的な用語や定義を捨て、怠惰になり、本来の意味を学ぶことができなくなると、世代間で効果的にコミュニケーションする能力が失われます。異なる言語やシステムの違いを議論する良い方法はありません。代わりに、新しいプログラマーは、従来の用語とその理由、およびその由来を学び、理解する必要があります。そうでなければ、私たちは集合的に知識と理解を失います。
Cパーキンス2017年

24

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

その参照を使用してオブジェクトを操作すると、外部のオブジェクトが影響を受けます。ただし、関数内で参照を別のものにポイントすることにした場合、参照を別のものにリダイレクトするだけであったため、オブジェクトの外部にはまったく影響を与えませんでした。


20

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

以下は、数値を渡す例です(プリミティブ型)

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}

19

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

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

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

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

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


うわー、これは信じられないほど混乱しています。彼らの正しい心の誰が、正反対のことを意味する確立された用語を定義し、それをそのように使用するでしょうか?この質問に対するここでの多くの回答が非常に混乱しているのも不思議ではありません。
イェルクWミッターク

16

JavaScriptは常に値渡しです。すべてが値型です。

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

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

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

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


12
-1、常に値渡しではありません。MDCから:「オブジェクト(配列やユーザー定義オブジェクトなどのプリミティブでない値)をパラメーターとして渡すと、オブジェクトへの参照が関数に渡されます。」
Nick

37
@Nick:常に値渡しです。限目。オブジェクトへの参照は、値によって関数に渡されます。参照渡しではありません。「参照渡し」は、変数の値ではなく、変数自体を渡すものと考えることができます。いずれかが(!完全に異なるオブジェクトに置き換えることを含む)関数は、引数になります変更、呼び出し元に反映されるだろう。JSは参照渡しではなく、値渡しで参照を渡すため、JSでこの最後のビットを使用することはできません。区別は微妙ですが、その制限を理解するためにかなり重要です。
cHao

1
将来のスタッカーについて...このリファレンスについて:x = "teste"; x.foo = 12;など。プロパティが永続的ではないからといって、それがオブジェクトではないという意味ではありません。MDNが言うように:JavaScriptでは、ほとんどすべてがオブジェクトです。nullおよびundefinedを除くすべてのプリミティブ型はオブジェクトとして扱われます。これらにはプロパティを割り当てることができ(一部のタイプの割り当てられたプロパティは永続的ではありません)、オブジェクトのすべての特性を備えています。 リンク
slacktracer 2012

9
MDNはユーザーが編集したwikiであり、誤りです。規範的な参照はECMA-262です。参照の解決方法を説明するS. 8「参照仕様タイプ」、および参照へのAssignmentExpressionを説明するために使用される8.12.5「[[Put]]」、およびオブジェクト変換9.9のToObjectを参照してください。プリミティブ値の場合、Michaelは仕様のようにToObjectの機能をすでに説明しています。しかし、sも参照してください。4.3.2プリミティブ値。
Garrett、

1
@WonderLand:いいえ、そうではありません。参照渡しができなかった人は、参照渡しと値渡しの違いを理解できないかもしれません。しかし、それらはそこにあり、重要です。簡単に聞こえるようにするだけで、人々に誤解を与えることは気にしません。
cHao 2016

12

JavaScriptでは、値のタイプは、その値がvalue-copyによって割り当てられるかreference-copyによって割り当てられるかを単独で制御します

プリミティブ値は常にvalue-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

ただし、cおよびdは、同じ共有値[1,2,3](複合値)への個別の参照です。値を「所有」していcないこと、または値をd「所有」していないことに注意することが重要です。どちらも[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へのポインタでなけれaばなりarrayません-しかし、JSにはそのような機能はありません!

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ます。xそして、a同じで指して別々の参照である[1,2,3]値。これで、関数内で、その参照を使用して値自体を変更できます(push(4))。しかし、割り当てを行うときx = [4,5,6]、これは最初の参照aが指している場所に影響を与えることはありません。まだ(変更された)[1,2,3,4]値を指しています。

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

foo( a.slice() );

reference-copyで渡すことができる複合値(オブジェクト、配列など)

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

var obj = {
    a: 2
};

foo( obj );

obj.a; // 42

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

ソース


あなた第1の状態「化合物の値は常に参照コピーによって渡さ/割り当てられている」、そしてあなたの状態「を代入コピーのxへの参照の」。「複合値」と呼ぶものの場合、実際の変数値は参照(つまり、メモリポインタ)です。説明したように、参照がコピーされます...変数の値がコピーされます。ここでも、参照はであることを強調しています。つまり、JavaScriptはすべてのタイプの値渡しです。値渡しは、変数値のコピーを渡すことを意味します。値がオブジェクト/配列への参照であることは問題ではありません。
Cパーキンス2017年

あなたは新しい用語(値のコピー/参照のコピー)を導入し、それは物事をより複雑にします。ちょうどコピー、期間があります。プリミティブを渡すと、実際のプリミティブデータのコピーが渡され、オブジェクトを渡すと、オブジェクトのメモリ位置のコピーが渡されます。あなたが言う必要があるのはそれだけです。それ以上のものは人々をさらに混乱させます。
Scott Marcus

9

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

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

メモリを四角形の下にあると想像すると、それらのすべてに1つのtype2値しか保存できません。

ここに画像の説明を入力してください

すべてのタイプ2の値(緑)は単一の正方形であり、タイプ1の値(青)はそれらのグループです

ここに画像の説明を入力してください

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

ここに画像の説明を入力してください

より複雑な話では:

ここに画像の説明を入力してください

だからここでの参照は私たちを救うことができます: ここに画像の説明を入力してください

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

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

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

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

これは、値渡しと参照渡し(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(=)演算子は、新しいメモリ空間またはアドレスを設定します

いわゆる特殊なケースでは、メモリスペースの割り当てを引き起こすのは代入演算子ではなく、オブジェクトリテラルそのものです。カーリーブラケット表記により、新しいオブジェクトが作成されます。プロパティcは、新しいオブジェクトの参照のコピーに設定されます。
georgeawg

6

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


1
これは過度に単純化した回答であり、以前の回答では説明が不十分であったことは何も述べられていません。なぜ配列を特別なケースとして呼び出すのか混乱しています。
クエンティン

1
オブジェクトは参照として保存されます」は誤解を招く可能性があります。つまり、オブジェクトを変数に割り当てる場合、変数に割り当てられる値はオブジェクトへの参照であるということです。
RobG

これは、関数外のオブジェクトを更新しない関数内のオブジェクトを更新する問題に対処していません。それは参照ではなく値として機能するように見える全体像です。したがって、-1
マスター

@amasterそれを指摘してくれてありがとう!編集
xameeramir

はは、私が試した...私の提案した編集はあまりにも多くのamdを変更しました
amaster

4

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

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

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

シンボル:変数(変数名)を参照するために使用されるテキスト文字列。

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

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

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

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

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

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

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

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

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

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

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


4

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

現在、人々は、「参照渡し」がJava et alの内容を説明する正しい方法であるかどうかについて、際限なく口論したいと思っています。実際に。ポイントはこれです:

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

参照渡しと呼ばれる私の本では。

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


更新

これはこれに対する反論です:

JavaScriptで利用可能な「参照渡し」はありません。


@Amyこれは値渡しであり、参照渡しではないためです。この答えは違いを示す良い答えです:stackoverflow.com/a/3638034/3307720
nasch

@nasch違いを理解しています。#1と#2は、参照渡しのセマンティクスを説明しています。#3は、値渡しのセマンティクスを説明しています。
エイミー

@Amy 1、2、および3はすべて、値渡しと一致しています。参照渡しを行うには、4も必要です。(=演算子を使用して)関数内の新しい値に参照を割り当てると、関数外の参照も再割り当てされます。これはJavascriptの場合とは異なり、値によってのみ渡されます。オブジェクトを渡すときは、オブジェクトへのポインターを渡し、そのポインターを値で渡します。
nasch

これは、「参照渡し」が意味するものではありません。あなたは私の質問に満足しました、そして私はあなたに同意しません。ありがとう。
エイミー

「参照渡しと呼ばれる私の本では。」–これまでに作成されたすべてのコンパイラブック、インタプリタブック、プログラミング言語理論ブック、およびコンピュータサイエンスブックでは、そうではありません。
イェルクWミッターク

3

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

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

    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

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

1
私はこれがJavaScriptの場合だとは思いません: `` `javascript var num = 5;
Danail Nachev 2015

@DanailNachev:技術的にはそうかもしれませんが、その違いはECMAScriptプリミティブではない変更可能なオブジェクトでのみ観察できます。
イェルクWミッターク

3

プログラミング言語の弁護士のために、ECMAScript 5.1の次のセクション(最新版よりも読みやすい)を読み、ECMAScriptメーリングリストで質問をしました。

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

引数リストの作成

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

プロダクションArgumentList:AssignmentExpressionは次のように評価されます。

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

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

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

オブジェクトプロパティへのアクセス

11.2.1項「プロパティ・アクセッサ」

プロダクションMemberExpression:MemberExpression [Expression]は次のように評価されます。

  1. baseReferenceをMemberExpressionの評価結果とします。
  2. baseValueをGetValue(baseReference)とします。
  3. propertyNameReferenceを式の評価結果とします。
  4. propertyNameValueをGetValue(propertyNameReference)にします。
  5. CheckObjectCoercible(baseValue)を呼び出します。
  6. propertyNameStringをToString(propertyNameValue)にします。
  7. 評価される構文生成がstrictモードのコードに含まれている場合は、strictをtrueにし、そうでない場合はstrictをfalseにします。
  8. 基本値がbaseValueであり、参照名がpropertyNameStringであり、strictモードフラグがstrictであるReferenceタイプの値を返します。

したがって、オブジェクトのプロパティは常に参照として使用できます。

参考に

これは、セクション8.7「参照仕様タイプ」で説明されています。参照は、言語の実際のタイプではありません。削除、typeof、および代入演算子の動作を説明するためにのみ使用されます。

「オブジェクト」の定義

5.1版では、「オブジェクトはプロパティのコレクション」と定義されています。したがって、オブジェクトの値はコレクションであると推測できますが、コレクションの値は仕様で十分に定義されておらず、理解するには少し労力が必要です。


値によって渡される引数、参照によって渡される引数、オブジェクト全体の操作、およびそれらのプロパティの操作の違いに戸惑う人がどれほどいるかに驚かされます。1979年、私はコンピュータサイエンスの学位を取得しませんでした。代わりに、私のMBAプログラムに15時間程度のCS選択科目を追加することを選択しました。それでも、これらの概念に対する私の理解は、少なくともコンピューターサイエンスまたは数学の学位を取得している同僚が持っているものと同じくらい優れていることがすぐにわかりました。アセンブラを研究し、それはかなり明らかになるでしょう。
デビッドA.グレイ

3

MDNのドキュメントは、冗長になりすぎずに、それを明確に説明しています。

関数呼び出しのパラメーターは、関数の引数です。引数は値によって関数に渡されます。関数が引数の値を変更した場合、この変更はグローバルまたは呼び出し元の関数には反映されません。ただし、オブジェクト参照も値であり、それらは特別です。関数が参照されたオブジェクトのプロパティを変更した場合、その変更は関数の外に表示されます(...)

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


1

低水準言語で、変数を参照渡しする場合は、関数の作成に特定の構文を使用する必要があります。

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

&age参照ですmyAgeが、あなたが値をしたい場合は、使用して、参照を変換する必要があります*age

Javascriptは、この変換を行う高水準言語です。したがって、オブジェクトは参照によって渡されますが、言語は参照パラメーターを値に変換します。&関数定義でを使用して参照で渡す必要はありません。また*、関数本体でを使用して、参照を値に変換する必要はありません。JSが実行します。

そのため、関数内のオブジェクトを変更しようとするとage = {value:5}、その値(つまり)を置き換えることで、変更は持続しませんが、プロパティ(つまりage.value = 5)を変更すると、持続します。

もっと詳しく知る


1

私はこれらの回答を何度も読みましたが、Barbara Liskovによって呼ばれた「共有して呼び出す」の技術的な定義について学ぶまで、実際には理解しませんでした

共有による呼び出しのセマンティクスは、参照による呼び出しとは異なります(参照によるセマンティクスとは異なり)関数内の関数引数への割り当ては呼び出し元に表示されないため、たとえば、変数が渡された場合、それは不可能です呼び出し元のスコープでその変数の割り当てをシミュレートします。ただし、関数は呼び出し元と同じオブジェクトにアクセスできるため(コピーは作成されません)、オブジェクトが変更可能な場合、関数内のそれらのオブジェクトへの変更は呼び出し元に表示され、値による呼び出しとは異なる可能性があります。セマンティクス。関数内の変更可能なオブジェクトの変更は、オブジェクトがコピーまたは複製されないため、呼び出し側に表示されます—共有されます。

つまり、パラメータ値自体にアクセスしてアクセスすると、パラメータ参照を変更できます。一方、パラメータへの割り当ては評価後に消え、関数の呼び出し元はアクセスできなくなります。


いいえ、オブジェクトが変更可能かどうかは、実際には問題ではありません。すべては常に値で渡されます。それは単にあなたが渡そうとしているもの(値または参照)に依存します。参照してくださいこれを
Scott Marcus

彼女が説明しているのは、BY-VALUE参照を渡すことです。新しい用語を導入する理由はありません。
Sanjeev

1

最も簡単な方法

// Copy JS object without reference
var first = {"a":"value1","b":"value2"};
var clone = JSON.parse( JSON.stringify( first ) ); 

var second = ["a","b","c"];
var clone = JSON.parse( JSON.stringify( second ) ); 

JSON.parse( JSON.stringify( obj ) )オブジェクトをディープクローンする恐ろしい方法です。遅いだけでなく、データの損失を引き起こす可能性もあります。
D.パーダル

0

私が発見した拡張メソッドUnderscore.jsライブラリは、私はどちらか完全に変更または交換することができるパラメータとしてオブジェクトを渡したいときに非常に便利。

function replaceOrModify(aObj) {
  if (modify) {

    aObj.setNewValue('foo');

  } else {

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

0

私が見つけた最も簡潔な説明はAirBNBスタイルガイドにありました

  • プリミティブ:プリミティブ型にアクセスすると、その値を直接処理します

    • ストリング
    • ブール
    • ヌル
    • 未定義

例えば:

var foo = 1,
    bar = foo;

bar = 9;

console.log(foo, bar); // => 1, 9
  • Complex:複雑な型にアクセスすると、その値への参照に取り組みます

    • オブジェクト
    • アレイ
    • 関数

例えば:

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

bar[0] = 9;

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

つまり、プリミティブ型は値で渡され、複合型は参照で渡されます。


いいえ、すべてが常に値で渡されます。それはあなたが渡そうとしているもの(値か参照)に依存します。参照してくださいこれを
Scott Marcus

-1

私はそれがパスバイコピーだと思います-

引数と変数オブジェクトは、関数呼び出しの最初に作成された実行コンテキスト中に作成されたオブジェクトであり、関数に渡された実際の値/参照は、この引数+変数オブジェクトに格納されるだけです。

簡単に言えば、プリミティブ型の場合、値は関数呼び出しの最初にコピーされ、オブジェクト型の場合、参照はコピーされます。


1
"pass-by-copy" ===値渡し
Scott Marcus

-1

JavaScript での「参照渡し」という用語の使用についての議論がここにありますが、あなたの質問に答えるために:

オブジェクトは、明示的に指定する必要なく、参照によって自動的に渡されます

(上記の記事から。)


7
リンクされた記事にはそのステートメントが含まれなくなり、「参照渡し」をまったく使用しないようになりました。
Cパーキンス

値は、基準となる

-2

「参照渡し」かどうかを判別する簡単な方法は、「スワップ」関数を作成できるかどうかです。たとえば、Cでは次のことができます。

void swap(int *i, int *j)
{
    int t;
    t = *i;
    *i = *j;
    *j = t;
}

JavaScriptでそれと同等のことができない場合は、「参照渡し」ではありません。


21
これは実際には参照渡しではありません。関数にポインターを渡し、それらのポインターは値で渡されます。より良い例は、C ++の&演算子またはC#の「ref」キーワードです。どちらも実際には参照渡しです。
マットグリア

さらに簡単なのは、すべてがJavaScriptで値によって渡されることです。
Scott Marcus


-3
  1. string、numberのようなプリミティブ型変数は、常に値渡しとして渡されます。
  2. 配列とオブジェクトは、参照渡しまたはこれら2つの条件に基づく値渡しとして渡されます。

    • そのオブジェクトまたは配列の値を新しいオブジェクトまたは配列で変更する場合、値によって渡されます。

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

    ここでは、古いオブジェクトに新しいオブジェクトまたは配列を割り当てています。古いオブジェクトのプロパティの値は変更しないので、値渡しです。

    • オブジェクトまたは配列のプロパティ値を変更する場合は、参照によって渡されます。

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

    ここでは、古いオブジェクトのプロパティ値を変更しています。新しいオブジェクトまたは配列を古いものに割り当てていないため、参照渡しです。

コード

    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

1
代入演算子は、関数呼び出しと混同しないでください。新しいデータを既存の変数に割り当てると、古いデータの参照カウントが減少し、新しいデータが古い変数に関連付けられます。基本的に、変数は新しいデータをポイントします。プロパティ変数についても同様です。これらの割り当ては関数呼び出しではないため、値渡しまたは参照渡しとは関係ありません。
John Sonderson 2014年

1
いいえ、すべてが常に値で渡されます。それはあなたが渡そうとしているもの(値か参照)に依存します。参照してくださいこれを
Scott Marcus

-3
  1. プリミティブ(数値、ブール値など)は値で渡されます。
    • 文字列は不変であるため、実際には問題になりません。
  2. オブジェクトは参照によって渡されます(参照は値によって渡されます)。

いいえ、すべてが常に値で渡されます。それはあなたが渡そうとしているもの(値か参照)に依存します。参照してくださいこれを
Scott Marcus

2番目のステートメントは、それ自体と矛盾しています。
イェルクWミッターク

-5

関数内の単純な値は、関数外の値を変更しません(値によって渡されます)が、複雑な値は変更されます(参照によって渡されます)。

function willNotChange(x) {

    x = 1;
}

var x = 1000;

willNotChange(x);

document.write('After function call, x = ' + x + '<br>'); // Still 1000

function willChange(y) {

    y.num = 2;
}

var y = {num: 2000};

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

それはばかげています、機能レベルのスコープのためにyは変化します。参照によって渡されるのではなく、巻き上げられます。
Parijat Kalia 2015

いいえ、すべてが常に値で渡されます。それはあなたが渡そうとしているもの(値か参照)に依存します。参照してくださいこれを
Scott Marcus
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.