web-dev-qa-db-ja.com

Javascriptは参照渡しですか?

Javascriptは参照渡しか値渡しか?これはJavascriptからの例です:Good Parts。私は長方形関数のmyパラメータについて非常に混乱しています。これは実際にはundefinedであり、関数内で再定義されています。元の参照はありません。関数のパラメータから削除した場合、内部領域関数はそれにアクセスできません。

それは閉鎖ですか?しかし、関数は返されません。

var shape = function (config) {
    var that = {};
    that.name = config.name || "";
    that.area = function () {
        return 0;
    };
    return that;
};
var rectangle = function (config, my) {
    my = my || {};
    my.l = config.length || 1;
    my.w = config.width || 1;
    var that = shape(config);
    that.area = function () {
        return my.l * my.w;
    };
    return that;
};
myShape = shape({
    name: "Unhnown"
});
myRec = rectangle({
    name: "Rectangle",
    length: 4,
    width: 6
});
console.log(myShape.name + " area is " + myShape.area() + " " + myRec.name + " area is " + myRec.area());
324
J Any

プリミティブは値によって渡され、オブジェクトは「参照のコピー」によって渡されます。

具体的には、オブジェクト(または配列)を渡すとき、あなたは(見えないことに)そのオブジェクトへの参照を渡しています、そしてそのオブジェクトの内容を修正することは可能です。参照を上書きしようとしても、呼び出し側が保持している参照のコピーには影響しません。つまり、参照自体が値によって渡されます。

function replace(ref) {
    ref = {};           // this code does _not_ affect the object passed
}

function update(ref) {
    ref.key = 'newvalue';  // this code _does_ affect the _contents_ of the object
}

var a = { key: 'value' };
replace(a);  // a still has its original value - it's unmodfied
update(a);   // the _contents_ of 'a' are changed
598
Alnitak

このように考えてください。

ECMAscriptでオブジェクトを作成すると、このオブジェクトはmystiqueECMAscriptの普遍的な場所に形成されますだれも手に入れることができないところ。返されるのは、この神秘的な場所にあるそのオブジェクトへの参照だけです。

var obj = { };

たとえobjでさえも(その特別な素晴らしい場所にある)オブジェクトへの参照にすぎないので、あなたはこの参照を渡すことしかできません。実質的に、objにアクセスするコードは、オブジェクトを変更します。遠く、遠くにあります。

56
jAndy

私の2セント....それはJavascriptが参照または値によってパラメータを渡すかどうかは無関係です。本当に重要なのは、割り当てと突然変異です。

ここではより長く、より詳細な説明を書きました( JavaScriptは参照渡しまたは値渡しの言語ですか?

オブジェクトやプリミティブに関わらず、何でも渡すと、javascriptは関数内で新しい変数を代入するだけです。等号(=)を使用するのと同じです。

そのパラメータが関数内でどのように振る舞うかは、等号を使用して新しい変数を代入した場合とまったく同じです。これらの簡単な例を見てください。

var myString = 'Test string 1';

// Assignment - A link to the same place as myString
var sameString = myString;

// If I change sameString, it will not modify myString, 
// it just re-assigns it to a whole new string
sameString = 'New string';

console.log(myString); // logs 'Test string 1';
console.log(sameString); // logs 'New string';

MyStringを関数のパラメータとして渡すと、単に新しい変数に代入したように動作します。それでは、単純な代入ではなく関数を使って、同じことをしましょう。

function myFunc(sameString) {

    // Re assignment.. again, it will not modify myString
    sameString = 'New string';
}

var myString = 'Test string 1';

// This behaves the same as if we said sameString = myString
myFunc(myString);

console.log(myString); // Again, logs 'Test string 1';

オブジェクトを関数に渡したときにオブジェクトを変更できる唯一の理由は、再割り当てしていないからです。代わりに、オブジェクトを変更または変更することができます。これも同じように機能します。

var myObject = { name: 'Joe'; }

// Assignment - We simply link to the same object
var sameObject = myObject;

// This time, we can mutate it. So a change to myObject affects sameObject and visa versa
myObject.name = 'Jack';
console.log(sameObject.name); // Logs 'Jack'

sameObject.name = 'Jill';
console.log(myObject.name); // Logs 'Jill'

// If we re-assign it, the link is lost
sameObject = { name: 'Howard' };
console.log(myObject.name); // Logs 'Jill'

MyObjectをパラメータとして関数に渡した場合は、単純に新しい変数に代入したように動作します。繰り返しますが、まったく同じ振る舞いをしますが、機能は同じです。

function myFunc(sameObject) {

    // We mutate the object, so the myObject gets the change too... just like before.
    sameObject.name = 'Jill';

    // But, if we re-assign it, the link is lost
    sameObject = { name: 'Howard' };
}

var myObject = { name: 'Joe'; }

// This behaves the same as if we said sameObject = myObject;
myFunc(myObject);
console.log(myObject.name); // Logs 'Jill'

関数に変数を渡すたびに、等号(=)を使用した場合と同じように、パラメータの名前に関係なく「代入」が行われます。

等号(=)は代入を意味することを常に覚えておいてください。また、関数にパラメータを渡すことは代入を意味します。それらは同じで、2つの変数はまったく同じ方法で接続されています。

変数の変更が別の変数に影響を与えるのは、基になるオブジェクトが変更されたときだけです。

オブジェクトとプリミティブを区別することに意味はありません。関数を持たず、等号を使用して新しい変数に代入するのとまったく同じように機能するからです。

38
Ray Perea

Cと同様に、最終的にはすべてが値によって渡されます。 Cとは異なり、実際にはバックアップして変数の場所を渡すことはできません。これは、参照だけではポインタがないためです。

そしてそれが持っている参照はすべて変数ではなくオブジェクトへのものです。同じ結果を得るにはいくつかの方法がありますが、呼び出しサイトまたは宣言サイトにキーワードを追加するだけでなく、手作業で実行する必要があります。

17
jmoreno

関数の引数は、値渡しまたは共有渡しのいずれかで渡されますが、Javascriptでは参照によって絶対に絶対にはなりません。

値による呼び出し

プリミティブ型は値渡しされます。

var num = 123, str = "foo";

function f(num, str) {
  num += 1;
  str += "bar";
  console.log("inside of f:", num, str);
}

f(num, str);
console.log("outside of f:", num, str);

関数スコープ内の再割り当ては周囲のスコープには表示されません。

これはStringsにも当てはまります。これは複合データ型でありながら不変です。

var str = "foo";

function f(str) {
  str[0] = "b"; // doesn't work, because strings are immutable
  console.log("inside of f:", str);
}

f(str);
console.log("outside of f:", str);

共有による呼び出し

オブジェクト、つまり、プリミティブではないすべての型は共有によって渡されます。オブジェクトへの参照を保持する変数は、実際にはこの参照のコピーだけを保持します。 JavascriptがCall-by-reference評価戦略を追求する場合、変数は元の参照を保持します。これがby-sharingとby-referenceの決定的な違いです。

この区別の実際的な影響は何ですか?

var o = {x: "foo"}, p = {y: 123};

function f(o, p) {
  o.x = "bar"; // mutation
  p = {x: 456}; // reassignment
  console.log("o inside of f:", o);
  console.log("p inside of f:", p);
}

f(o, p);

console.log("o outside of f:", o);
console.log("p outside of f:", p);

突然変異は、既存のObjectの特定のプロパティを変更することを意味します。変数がバインドされ、このオブジェクトを参照する参照コピーは同じままです。したがって、変異は呼び出し元のスコープ内に表示されます。

再割り当ては、変数にバインドされている参照コピーを置き換えることを意味します。これは単なるコピーなので、同じ参照のコピーを保持している他の変数は影響を受けません。そのため、再割り当ては、参照による評価戦略を使用した場合のように呼び出し元のスコープには表示されません。

Ecmascriptの 評価戦略 に関する詳細情報。

16
user6445533

JavaScriptは値渡しです。プリミティブの場合は、プリミティブの値が渡されます。オブジェクトの場合は、オブジェクトの参照「値」が渡されます。

オブジェクトの例:

var f1 = function(inputObject){
    inputObject.a=2;
}
var f2 = function(){
    var inputObject={"a":1};
    f1(inputObject); 
    console.log(inputObject.a);
}

f2を呼び出すと、参照が渡され参照内の "a"値が更新されるため、 "a"値は1ではなく2として出力されます。

プリミティブを使った例

var f1 = function(a){
    a=2;
}
var f2 = function(){
    var a =1;
    f1(a); 
    console.log(a);
}

f2を呼び出すと、 "a"値が1として出力されます。

6
yallam

実際的には、Alnitakは正しく、理解しやすくなっていますが、最終的にはJavaScriptでは、すべてが値によって渡されます。

オブジェクトの「価値」とは何ですか?それはオブジェクト参照です。

オブジェクトを渡すと、この値のコピー(つまりAlnitakが説明した「参照のコピー」)が得られます。この値を変更しても、元のオブジェクトは変更されず、その参照のコピーが変更されます。

4
Pete Campbell

Constを使用した簡単な例を作成するために...

const myRef = { foo: 'bar' };
const myVal = true;

function passes(r, v) {
  r.foo = 'baz';
  v = false;
}

passes(myRef, myVal);

console.log(myRef, myVal); // Object {foo: "baz"} true
4
4m1r

「グローバル」JavaScript変数は、ウィンドウオブジェクトのメンバーです。あなたはウィンドウオブジェクトのメンバーとして参照にアクセスすることができます。

var v = "initialized";
function byref(ref) {
 window[ref] = "changed by ref";
}
byref((function(){for(r in window){if(window[r]===v){return(r);}}})());
// could also be called like... byref('v');
console.log(v); // outputs changed by ref

上記の例は、関数内で宣言された変数に対しては機能しません。

3
tony41780

純粋主義がなければ、Javascriptで参照によってスカラー引数をエミュレートする最善の方法は、前の答えが示すように、オブジェクトを使用することです。

しかし、私は少し違います。

関数呼び出しの中でオブジェクト割り当てを行ったので、関数呼び出しの近くで参照パラメーターを見ることができます。ソースの読みやすさが向上します

関数宣言では、読みやすさと同じ理由で、コメントのようにプロパティを配置しました。

var r;

funcWithRefScalars(r = {amount:200, message:null} );
console.log(r.amount + " - " + r.message);


function funcWithRefScalars(o) {  // o(amount, message)
  o.amount  *= 1.2;
  o.message = "20% increase";
}

上記の例で、nullは明らかに出力参照パラメータを示します。

出口:

240 - 20% Increase

クライアントサイドでは、console.logalertに置き換えられるべきです。

★★★

さらに読みやすくなる別の方法:

var amount, message;

funcWithRefScalars(amount = [200], message = [null] );
console.log(amount[0] + " - " + message[0]);

function funcWithRefScalars(amount, message) {  // o(amount, message)
   amount[0]  *= 1.2;
   message[0] = "20% increase";
}

ここでは、上記のrのように、新しいダミー名を作成する必要すらありません。

1
Paulo Buchsbaum

プリミティブは値渡しされます。しかし、もしあなたがプリミティブの値を読むだけでいいのであれば(そしてfunctionが呼ばれた時にはvalueはわからない)、あなたはそれを必要な瞬間に値を検索するfunctionを渡すことができます。

function test(value) {
  console.log('retrieve value');
  console.log(value());
}

// call the function like this
var value = 1;
test(() => value);
0
jabko87

オブジェクトは常に参照渡しで、プリミティブは値渡しで、オブジェクトに対して同じアドレスにそのパラメータを保持するだけです。これが私が何を意味するのかを説明するためのコードです( https://js.do/ のようなJavaScriptサンドボックスで試してください)。パラメータのアドレスを保持すると、元のメンバ値もすべて保持されます。

a = { key: 'bevmo' };
testRetain(a);
document.write(' after function ');
document.write(a.key);


function testRetain (b)
 {
 document.write(' arg0 is ');
 document.write(arguments[0].key);
 b.key='passed by reference';
 var retain = b; //retaining the original address of the parameter

 //address of left set to address of right, changes address of parameter
 b={key: 'vons'}; //right is a new object with a new address
 document.write(' arg0 is ');
 document.write(arguments[0].key);

 //now retrieve the original address of the parameter for pass by reference
 b=retain; 
 document.write(' arg0 is ');
 document.write(arguments[0].key);
}

結果:arg0は無効ですarg0は無効ですarg0は参照渡しされた関数の後に参照渡しされます

0
user3015682

私は人々がそのようなことを実証しようとする例で参照渡しを見ることができません。 値渡ししか表示されません。

オブジェクトへの参照を保持する変数の場合、その参照はそれらの変数のであるため、参照は渡されます。その結果、値渡し.

このような文で:

var a = {
  b:"foo", 
  c:"bar"
};

'a'の値はObjectではなく、(これまでのところ)それに対する参照です。言い換えれば、オブジェクトは変数aには含まれていません。これは、JavaScriptにしか精通していないプログラマにとっては難しいように思われることです。でも知っている人にとっては簡単です。 Java、C#、およびC.

0
Juhani