teratailでは、エンジニアの質問にすぐに答えが返ってきます。

teratailでは、今あなたが見ているQ&A以外にも、たくさんの課題解決が毎日行われています。

現在の回答率:

93.92%

teratailに登録する

受付中 JavaScriptは値渡しか?共有渡し(参照の値渡し)か?

  • JavaScript

    1369questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

2015/08/15 02:14 投稿

raccy score 369

  • 5

    回答

  • 7

    クリップ

  • 219

    view

7

JavaScriptは値渡しなのでしょうか?共有渡し(参照の値渡し)なのでしょうか?普通のObjectはすべて共有渡しだと思うのですが、プリミティブ型(?)については違うようなのです。しかし、StackOverflow(※)でもまとまっていないようで、よくわかりませんでした。詳細を分かる方がいれば、下記について教えて下さい。
※参考: StackOverflow: Is JavaScript a pass-by-reference or pass-by-value language?

1. 値渡しになる型はあるのでしょうか?ある場合は、どの型がなるのでしょうか?

2. 1.の型のうちmutableな型はあるのでしょうか?ある場合は、mutableな型の破壊的メソッドはどのようなものがあるのでしょうか?

3. 値渡しであることが分かる(共有渡しでは説明できない)コードはありますでしょうか?

4. C++やC#で言う所の参照渡しも存在するのでしょうか?その場合はどのような物が参照渡しになるのでしょうか?

5. ECMAScript2015仕様書MDN JavaScriptなどの公式または公式に準ずる資料で上のことに言及している部分はどこになるのでしょうか?

私の考えでは、インクリメント/デクリメント(++/--)を特殊なx+=1/x-=1であると解釈すれば、すべて共有渡しと解釈して問題ないのではないか?と思っています。反例があれば教えて欲しいです。

【注記】
ここでの値渡しはcall-by-value、参照渡しはcall-by-referenc、共有渡し(参照の値渡し)はcall-by-sharingを意味します。違いについては「値渡しと参照渡しの違いを理解する」の記事を参考にして下さい。回答の際は厳密に用語を分けていただきますようお願いします。

情報の追加・修正の依頼をする(0)

※回答は回答欄にご記入下さい。

記入例

  • ・質問の「○○○」の部分をもう少し具体的に書いてください。
  • ・開発環境は何ですか?(OSやバージョン)
  • ・「○○○」の部分に誤字脱字があります。

7

teratailでは、今あなたが見ているQ&A以外にも、たくさんの課題解決が毎日行われています。

現在の回答率:

93.92%

teratailに登録する
  • 新着順
  • 評価が高い順
  • 古い順

回答(全5件)

4

実装面で見るならば、Reference 型を「参照の値渡し」、Primitive 型 (ToPrimitive で値に変化がない型)を「値渡し」と呼称して良いと思います。

function foo (a) {
  a[0] = 1;
  a = {};
}

var array = [], string = '0';
foo(array);
foo(string);
console.log(array);   // [1] (参照の値渡し)
console.log(string);  // "0" (値渡し)

ただし、ECMAScript 仕様では「値渡し」「参照の値渡し」には言及されてなく、実装面の意味合いが強いと考えています。
詳細 ECMA-262-3 第8章 評価戦略 - mixi Engineers' Blogが比較的詳しいですが、説明をぼかして書いている部分も見受けられます。

MDN ではプリミティブなパラメータ (数値など) は値渡しで関数に渡されますとありますが、厳密な定義でいうなら MDN は間違っている解説も多いので参考程度に留めるのが良いと思います(解説が古かったり、英語解説だけに載っていたり、用語が間違っていたりする記述を何度も見ています)。

2015/08/15 08:52 投稿

2015/08/15 08:54 編集

think49 score 150

コメント(2)

2015/08/15 09:32

とても参考になる資料で、ありがとうございます。
immutableな場合は値渡しと共有渡し(参照の値渡し)で違いが出ないため、
実装依存という側面が強いと言うことでしょうか。

あと、例ですけど、
string = '0';
string[0] = 1;
console.log(string); // "0" ???
となるので、たとえStringが共有渡し(参照の値渡し)であっても、
問題なかったりします。
Stringはプリミティブ型ですが、本当に値渡しなのか、
本当に文字列全てを値として渡すなんて非効率なことをしているのか、
そこら辺がすごく気になるところなのです。
V8やSpidermonkeyのソースコードを見るしか無いんでしょうか…。

2015/08/15 10:02

string[0] は非破壊的だったのですね。失礼しました。
改めて考えてみると String.prototype の中で破壊的メソッドが思いつきませんね。
憶測ですが、「実は全てが『参照の値渡し』であって、Primitive 型には破壊的機構が存在しないから『値渡し』のように見えているのかもしれない」とふと思いました。

1

一言で言うなら、全て共有渡しです。
(ここでの共有渡しとは、値の実体を複製するのではなく、その存在を変数同士で共有するように渡すこと、
ただし参照の値渡しのような具体的な実装に踏み込んだものとも違って、
何かを渡すというよりむしろ、1つの値に別の名前を付けさせるという方向性(最も仕様の流れに近い)の概念とします。)

仕様ではプリミティブ型とオブジェクト型で渡され方が変わるようには書いていませんし、
オブジェクト値の実体が参照だとも書かれていません。
ならば全てが共有渡しと見るべきです。

そもそも渡され方は渡し方で決まるべきで、渡される値によって異なると言うのは不自然です。
JSでは渡し方はひと通りですから、渡され方もひと通りなのです。

因みに仕様のReference型は変数の解決における内部処理に使われるものであって、
紛らわしいですが渡され方の問題とは軸がズレていて本質的には関係ないものです。

2015/08/15 19:29 投稿

2015/08/15 19:41 編集

jser score 34

コメント(3)

2015/08/15 20:31

プリミティブ型が全てimmutableであれば、値渡しと共有渡しの違いは
コード上に現れないため、全て共有渡しと見なせる事には同意します。
ただ、自分で書いていてなんですが、"++"等を考えるとNumberはimmutableなのか?
という疑問もあるのです。

また、Javaは渡し方は一つしかありませんけど、プリミティブ型は値渡しで、
参照型は共有渡し(参照の値渡し)とはっきりとした違いがあります。
Rubyなんかはもっとおかしくて、普通のオブジェクトが共有渡しなのに、
Fixnumとか一部の即値はCでの実装レベルでは値渡しになっています。
※RubyのFixnumはimmutableなので、コードレベルでの違いは見えません。
渡し方が一種類だから渡され方も一種類は強引のような気がします。

2015/08/15 20:47

もうひとつ。
jserさんの「共有渡し」の説明ですと、C++やC#の参照渡しになると思います。
C++の参照渡しはまさしく変数の別名であり、同じ領域を「共有」するものです。
その意味で「共有渡し」と言っているのであれば、C++の参照渡しと同じ事が
できるはずですが、JavaScriptでそのようなことはできません。
jserさんがいう「共有渡し」について、詳しく書かれた資料等があれば、
教えていただけますでしょうか?

2015/08/15 22:24

numberはimmutableです。
++等はただ1を足した新しい値を作って変数に格納しなおしているだけで、元々変数に格納されていた数値に影響は与えていません。

また、私が言っているのは参照渡しとは違います。
参照渡しとは「変数」を共有することで、私が言っているのは値を複数変数間で共有すること、
つまり変数自体ではなく変数を解決した際の値が共有されている状態を言っています。
更に言い換えると、渡すというよりすでに存在する値に対して別の名前を与える行為でもあるのです。

0

何度もすみません。
一応読み直して基本的な疑問の答えにはなるかと思うので、検索に掛かったページを挙げておきます。

11.2. By Value Versus by Reference - JavaScript: The Definitive Guide, 4th Edition.

参考になれば幸いです。

2015/08/15 06:38 投稿

2015/08/15 06:49 編集

pikovolt score 337

コメント(5)

2015/08/15 08:58

SOの質問者もそうですが、"by reference"と言っている時点で、
その文章の作者のレベルが低いと思います。
それに比較を曖昧で役立たずな`==`でやってる時点でおかしいですし、
valueの例(Example 11-1)は変数そのものへの代入なのに、
referenceの例(Example 11-2)は変数そのものへの代入じゃ無くて
プロパティへの代入とか意味が異なる事やっているし、
その後変数そのものへの代入の例(Example 11-3)とか示して、
"by reference"の意味について言い訳しているようですが、
用語の使い方で読者(特にC++やC#ユーザー)を混乱するだけです。
まともな技術書が多いO'Reilly出版とは言え、信頼できる資料とは言いにくいです。

2015/08/15 09:08

横から失礼します。
参考までにお伺いしたいのですが、「SOの質問者」とは「Stack Overflow の質問者」という意味でしょうか。

2015/08/15 09:26

O'Reillyの本も玉石混交なので信用度は謎だったのですが、参考にならない情報で申し訳ない。

2015/08/15 09:37

>> think49さん
SO=StackOverflowです。すいません、そう略す人がおおかったもので、
私もなんもきにせず略しちゃいました。
>> pickovoldさん
いえいえ、資料は多いだけうれしいので、多少胡散臭いものであっても、
とても参考になりました。

2015/08/15 10:05

raccyさん
やはり、StackOverflow の略称だったのですね。何となくそうかなとは思ったのですが、略称について調べる手段を思いつかず…。参考になりました。

0

(私が初歩的な勘違いをしている気がするのですが)もし全てが共有渡しの場合、以下の例では全て2が出力されると思うのですが、これはbが値渡しである実証例にはならないでしょうか?

function foo (b,d) {
 a = 2;
 c[0] = 2;
 console.log(b); //1
 console.log(d[0]); //2
}

a =1,c=[1,0];
foo(a,c);
console.log(a); //2
console.log(c[0]); //2

2015/08/15 21:04 投稿

hirohiro score 270

コメント(2)

2015/08/15 21:37

"="の代入は中にある値を変化させるのでなく、箱を丸ごと入れ直しなので、
共有渡しでも結果はおなじになります。
最初のを`a={a:2}`、次のを`a={a:1}`などにしてみて見比べてみて下さい。

2015/08/16 01:27

ありがとうございます。なるほど勉強になります。質問者さんへの逆質問になってしまってすみません。

0

まず最初に、言語の仕様に、『値渡しや参照渡し、あるいは共有渡しを使うのか』を明記する必要もなければ理由もありません(言語によるでしょうが少なくともJavaScriptでは必要ないと思われる)。

なぜかというと、『値渡しや参照渡し、あるいは共有渡しを使うのか』という話は、実装の問題だからです。
仕様では、変数の渡し方に関わらず、どういうコードを書いたらどういう結果になるのかだけ決めればよいだけなのです。

どのように変数の値を渡したらメモリ効率がよいのか、あるいは速度が速いのかなどは何を優先するかによっても変わってくるので、実装する側の人間が決めれば良い話なので仕様側で決める必要はありません(別に決めてしまっても良い)。


そこで改めて質問の趣旨を考えてみると、

1.ECMAScriptの仕様で『値渡しや参照渡し、あるいは共有渡しを使うのか』が決められているのか?
2.V8などの実際の実装で『値渡しや参照渡し、あるいは共有渡しを使うのか』がどうなっているのか?

という2種類の疑問がごっちゃになっているように思われます。

1のほうであれば、仕様を全部読めば、決められているのかいないのかははっきりすると思います。
(たぶん決められていなさそう…)

また、2のほうであれば、実際の実装のソースを読むしかないと思います。ただし、仮にV8の実装では共有渡しだったとしても、他の実装では違う可能性もあるので、すべての実装でどうなっているのか知りたいのならば、片っぱしからソースを読む必要が出てくるので現実的ではないと思われます。

2015/08/18 15:30 投稿

JunSuzukiJapan score 23

課題や疑問を抱えているすべてのエンジニアが、あなたの回答を待っています。

関連した質問

同じタグがついた質問を見る

  • JavaScript

    1369questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

関連した質問

思考するエンジニアのためのQ&Aサイト「teratail」について詳しく知る