参照渡し
活字になってしまってるのでことさらに言及するわけだが(ネット上には同様のものがぶぁぁぁぁあってあるわけだが)
Software Design 2010/11 p129 より
オブジェクトは「参照渡し」に
これらのオブジェクト型の変数は、C 言語でいうところのポインタに相当するため、関数の引数としてオブジェクト型の変数を指定した場合は、自動的に参照渡しとなってしまいます。関数の引数にはポインタの参照が渡されるので、関数の呼び出し先で引数のプロパティを書き換えると呼び出し元の変数の値も書き換わってしまいます(リスト 5 )
リスト 5 関数の引数でオブジェクト型はつねに参照渡しとなる
function object_by_reference(x) { return (x.i = 999); // プロパティを変更 } var a = ({i : 123}); object_by_reference(x) // <= 999 が返る a.i; // <= 999 に変わっている!
それは参照渡しではなく、"pass by sharing"(定訳はまだない?)と呼ばれているセマンティクスであって、というか「ポインタの参照が渡されるので」というのも微妙という気もするが、ともかく、「呼び出し元と呼び出し先でオブジェクトが共有されるもの」が「参照渡し」ではない
C 言語と同様(Java や Python や Ruby もそうだが)JavaScript の引数は全て値渡しである
(もしかして、オブジェクトを複製して渡すことを「値渡し」と呼んでる言語がどこかにあるのか? あと検索してみると pass by sharing は pass by reference の別名と説明してるページもあったりして少々混乱するのだけど)
では本物の参照渡しとはどういうものかというと、C++ には参照渡しがあるので C++ のコードで説明するのだが
#include <cstdio> class C0 { public: int a; }; static void byref_sample(C0 &x) { C0 *newObj = new C0(); newObj->a = 2; x = *newObj; } int main(void) { C0 c0; c0.a = 1; printf("%d\n", c0.a); byref_sample(c0); printf("%d\n", c0.a); return 0; }
$ g++ foo.cc $ ./a.out 1 2
関数 byref_sample で、メンバをいじるのではなく、新しいオブジェクトを作って、それを仮引数に代入していること、そしてその結果が呼び出し元に反映していることがわかると思う。これが参照渡しである
(オブジェクトがリークしてるのはサンプルということで見逃してほしい)
「仮引数の変数が、あたかも実引数の変数そのものであるかのようなふるまいをする」のが、参照渡しである
余談。C++ の、呼び出し元では見た目に何の変化もなく参照渡しになってしまう言語デザインはちょっとよくないと思うのだけど、理由はあって、代入演算子(のオーバーライド)を自然なものにするためにはこうなってないといけないのである
(明示的な、関数呼び出しの形をしている関数呼び出しの場合と、演算子式による呼び出しで区別すればいいのか?)