私はJSで、オブジェクトが参照によって渡されることを知っています、例えば:
function test(obj) {
obj.name = 'new name';
}
var my_obj = { name: 'foo' };
test(my_obj);
alert(my_obj.name); // new name
しかし、なぜ以下は機能しません:
function test(obj) {
obj = {};
}
var my_obj = { name: 'foo' };
test(my_obj);
alert(my_obj.name); // foo
オブジェクトを{}
(空)に設定しましたが、まだfoo
と表示されています。
この背後にある論理を説明できる人はいますか?
ポインタに精通している場合、それはあなたが取ることができる類推です。実際にはポインタを渡しているので、obj.someProperty
はそのプロパティを間接参照し、実際にそれをオーバーライドしますが、obj
をオーバーライドするだけでは、ポインターが削除され、オブジェクトは上書きされません。
JavaScriptは実際にはオブジェクトをpass-by -copy-referenceで渡します。
test
関数にmy_obj
を渡すと、そのオブジェクトへの参照のcopyが渡されます。その結果、test
でオブジェクトを再度割り当てると、元のオブジェクトへの参照のコピーの再割り当てのみ;元のmy_obj
は変更されません。
オブジェクトではなく参照を上書きしているためです。
// Create a new object and assign a reference to it
// to the variable my_obj
var my_obj = { name: 'foo' };
// Pass the reference to the test function
test(my_obj);
// Assign the reference to a variable called obj
// (since that is the first argument)
function test(obj) {
// Create a new (empty) object and assign a reference to it to obj
// This replaces the existing REFERENCE
obj = {};
}
// my_obj still has a reference to the original object,
// because my_obj wasn't overwritten
alert(my_obj.name); // foo
Javascriptには参照渡しのサポートがありません(ただし、オブジェクトは参照渡しされ、割り当ては=
を使用して上書きされない限り、参照は維持されます)のref
キーワードを模倣できます次の手法を使用したC#:
function test(obj) {
obj.Value = {};
//obj.Value = {name:"changed"};
}
var my_obj = { name: 'foo' };
(function ()
{
my_obj = {Value: my_obj};
var $return = test(my_obj);
my_obj = my_obj.Value;
return $return;
}).call(this);
alert(my_obj.name); // undefined, as expected
// In the question this returns "foo" because
// assignment causes dereference
もちろん、グローバルを使用して、引数なしで関数を呼び出すことができます。その場合、参照は次のように見逃されません。
var obj = { name: 'foo' };
function test() {
obj = {};
}
test();
alert(obj.name); // undefined
すべてのコードがクロージャーにある場合、グローバルはグローバル名前空間を汚染しないように、物事はよりシンプルで上です。
(function(){
var obj = { name: 'foo' };
function test() {
obj = {};
}
test();
alert(obj.name); // undefined
}).call(this);
上記の「クロージャ内のグローバル」技術は、ref
引数を含むC#コードをJavascriptに移植する必要がある場合に最適です。例えば。次のC#コード:
void MainLoop()
{
// ...
MyStruct pt1 = CreateMyStruct(1);
MyStruct pt2 = CreateMyStruct(2);
SwapPoints(ref pt1, ref pt2);
// ...
}
void SwapPoints(ref MyStruct pt1, ref MyStruct pt2)
{
MyStruct tmp = pt1;
pt1 = pt2;
pt2 = tmp;
}
次のようなものを使用してJavaScriptに移植できます:
(function(){
var pt1, pt2;
function CreateMyStruct(myvar)
{
return {"myvar":myvar}
}
function MainLoop()
{
// ...
pt1 = CreateMyStruct(1);
pt2 = CreateMyStruct(2);
console.log("ORIG:",pt1,pt2);
SwapPoints();
console.log("SWAPPED:",pt1,pt2);
// ...
}
function SwapPoints()
{
var tmp = pt1;
pt1 = pt2;
pt2 = tmp;
}
MainLoop();
}).call(this);
または、ローカル変数と関数引数を使用することが不可欠である場合、解決策は次のような私の答えの最初の例に基づくことができます:
(function(){
function CreateMyStruct(myvar)
{
return {"myvar":myvar}
}
function MainLoop()
{
// ...
var pt1 = CreateMyStruct(1);
var pt2 = CreateMyStruct(2);
console.log("ORIG:",pt1,pt2);
(function ()
{
pt1 = {Value: pt1};
pt2 = {Value: pt2};
var $return = SwapPoints(pt1, pt2);
pt1 = pt1.Value;
pt2 = pt2.Value;
return $return;
}).call(this);
console.log("SWAPPED:",pt1,pt2);
// ...
}
function SwapPoints(pt1, pt2)
{
var tmp = pt1.Value;
pt1.Value = pt2.Value;
pt2.Value = tmp;
}
MainLoop();
}).call(this);
ネイティブref
がない場合、Javascriptには多くのものが欠けていると言う必要があります。コードははるかに単純になります。