回答(全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 は間違っている解説も多いので参考程度に留めるのが良いと思います(解説が古かったり、英語解説だけに載っていたり、用語が間違っていたりする記述を何度も見ています)。
コメント(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型は変数の解決における内部処理に使われるものであって、
紛らわしいですが渡され方の問題とは軸がズレていて本質的には関係ないものです。
コメント(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.
参考になれば幸いです。
コメント(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
0
まず最初に、言語の仕様に、『値渡しや参照渡し、あるいは共有渡しを使うのか』を明記する必要もなければ理由もありません(言語によるでしょうが少なくともJavaScriptでは必要ないと思われる)。
なぜかというと、『値渡しや参照渡し、あるいは共有渡しを使うのか』という話は、実装の問題だからです。
仕様では、変数の渡し方に関わらず、どういうコードを書いたらどういう結果になるのかだけ決めればよいだけなのです。
どのように変数の値を渡したらメモリ効率がよいのか、あるいは速度が速いのかなどは何を優先するかによっても変わってくるので、実装する側の人間が決めれば良い話なので仕様側で決める必要はありません(別に決めてしまっても良い)。
そこで改めて質問の趣旨を考えてみると、
1.ECMAScriptの仕様で『値渡しや参照渡し、あるいは共有渡しを使うのか』が決められているのか?
2.V8などの実際の実装で『値渡しや参照渡し、あるいは共有渡しを使うのか』がどうなっているのか?
という2種類の疑問がごっちゃになっているように思われます。
1のほうであれば、仕様を全部読めば、決められているのかいないのかははっきりすると思います。
(たぶん決められていなさそう…)
また、2のほうであれば、実際の実装のソースを読むしかないと思います。ただし、仮にV8の実装では共有渡しだったとしても、他の実装では違う可能性もあるので、すべての実装でどうなっているのか知りたいのならば、片っぱしからソースを読む必要が出てくるので現実的ではないと思われます。
課題や疑問を抱えているすべてのエンジニアが、あなたの回答を待っています。
関連した質問
-
解決済
findElement(By〜・・・)とfindElements(By〜・・・)の違いについて(Se...
Selenium2 WebDriverのfindElement(By〜・・・)とfindElements(By〜・・・)の違いについて教えてください。 分かる方は、どなたか教えて
-
解決済
<PHP>MySQLで今日・今週・今月のデータを選択するSQL文は?
SQL文を使って、MySQL上のあるテーブルから、特定の期間のレコードを取得しようとしています。 レコードを作成した時に、以下の形式で日時を入力しています。 date('
-
解決済
MySQLでWHERE句内でCOUNT(*)を使う方法
MySQLで以下を完成させようとしています。 SELECT DISTINCT user_id example_table10ORDER BY upd_date DESC WHE
-
解決済
SQL PLUSについての質問です。
SQL PLUSの、テーブルからの値の表示方法についての質問です。 MS_TABLE name job code A社 | MS製造 | 101 A社 | OS製
同じタグがついた質問を見る
- JavaScript
1369questions
JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。