JavaScript が値を渡す場合と参照を渡す場合、渡された項目を変更すると関数外の値に影響する場合とそうでない場合について、総合的に読みやすい資料を探しています。また、別の変数に割り当てる場合が参照による場合と値による場合のどちらなのか、また、関数パラメータとして渡す場合とは異なるルールに従うかどうかについても興味があります。
私は多くの検索を行い、実際のルールの一部をつなぎ合わせることができる多くの具体的な例(その多くは SO にあります)を見つけましたが、それをすべて説明する、よく書かれた単一のドキュメントはまだ見つかっていません。
また、言語には、参照渡しか値渡しかを制御する方法がありますか?
私が理解したい質問の種類をいくつか挙げます。これらは単なる例です。私は実際に、特定の例に対する答えだけでなく、言語が従うルールを理解したいのです。しかし、ここにいくつかの例を挙げます。
function f(a,b,c) {
a = 3;
b.push("foo");
c.first = false;
}
var x = 4;
var y = ["eeny", "miny", "mo"];
var z = {first: true};
f(x,y,z);
すべての異なる型について、x、y、z の内容が f のスコープ外で変更されるのはいつですか?
function f() {
var a = ["1", "2", "3"];
var b = a[1];
a[1] = "4";
// what is the value of b now for all possible data types that the array in "a" might hold?
}
function f() {
var a = [{yellow: "blue"}, {red: "cyan"}, {green: "magenta"}];
var b = a[1];
a[1].red = "tan";
// what is the value of b now and why?
b.red = "black";
// did the value of a[1].red change when I assigned to b.red?
}
オブジェクトの完全に独立したコピー(参照は一切なし)を作成したい場合、そのためのベストプラクティスの方法は何ですか?
ベストアンサー1
私の理解では、これは実際には非常に簡単です。
- Javascript は常に値渡しですが、変数がオブジェクト (配列を含む) を参照する場合、「値」はオブジェクトへの参照になります。
- 変数の値を変更しても、基礎となるプリミティブまたはオブジェクトは変更されず、変数が新しいプリミティブまたはオブジェクトを指すだけになります。
- ただし、変数によって参照されるオブジェクトのプロパティを変更すると、基になるオブジェクトは変更されます。
それで、あなたの例のいくつかを見てみましょう:
function f(a,b,c) {
// Argument a is re-assigned to a new value.
// The object or primitive referenced by the original a is unchanged.
a = 3;
// Calling b.push changes its properties - it adds
// a new property b[b.length] with the value "foo".
// So the object referenced by b has been changed.
b.push("foo");
// The "first" property of argument c has been changed.
// So the object referenced by c has been changed (unless c is a primitive)
c.first = false;
}
var x = 4;
var y = ["eeny", "miny", "mo"];
var z = {first: true};
f(x,y,z);
console.log(x, y, z.first); // 4, ["eeny", "miny", "mo", "foo"], false
例2:
var a = ["1", "2", {foo:"bar"}];
var b = a[1]; // b is now "2";
var c = a[2]; // c now references {foo:"bar"}
a[1] = "4"; // a is now ["1", "4", {foo:"bar"}]; b still has the value
// it had at the time of assignment
a[2] = "5"; // a is now ["1", "4", "5"]; c still has the value
// it had at the time of assignment, i.e. a reference to
// the object {foo:"bar"}
console.log(b, c.foo); // "2" "bar"