関数の引数として不変である変数の参照を渡すことはできますか?
例:
var x = 0;
function a(x)
{
x++;
}
a(x);
alert(x); //Here I want to have 1 instead of 0
関数の引数として不変である変数の参照を渡すことはできますか?
例:
var x = 0;
function a(x)
{
x++;
}
a(x);
alert(x); //Here I want to have 1 instead of 0
JavaScriptは参照によるパラメーターの受け渡しをサポートしていないため、代わりに変数をオブジェクトにする必要があります。
var x = {Value: 0};
function a(obj)
{
obj.Value++;
}
a(x);
document.write(x.Value); //Here i want to have 1 instead of 0
この場合、x
はオブジェクトへの参照です。がx
関数に渡されるとa
、その参照はにコピーされobj
ます。したがって、メモリ内の同じものを参照してくださいobj
。x
のプロパティを変更すると、のValue
プロパティにobj
影響しValue
ますx
。
Javascriptは常に関数パラメータを値で渡します。これは単に言語の仕様です。両方の関数に対してローカルなスコープで作成し、変数をまったく渡さないようにすることができます。x
この質問は役立つかもしれません: javascriptで参照によって変数を渡す方法は?複数の値を返すActiveX関数からデータを読み取ります
要約すると、Javascriptプリミティブ型は常に値によって渡されますが、オブジェクト内の値は参照によって渡されます(私の見落としを指摘してくれたコメント投稿者に感謝します)。したがって、これを回避するには、整数をオブジェクト内に配置する必要があります。
var myobj = {x:0};
function a(obj)
{
obj.x++;
}
a(myobj);
alert(myobj.x); // returns 1
私は、Cの観点からおそらくより一般的で理解しやすい(したがって、ユーザーの例の形式により適合している)ポインターを実装する少し異なる方法を見つけました。
JavaScriptでは、Cと同様に、配列変数は実際には配列への単なるポインターであるため、ポインターを宣言するのとまったく同じように配列を使用できます。このようにして、元のオブジェクトで変数に名前を付けたにもかかわらず、コード内のすべてのポインターを同じように使用できます。
また、ポインタのアドレスとポインタのアドレスにあるものを参照する2つの異なる表記法を使用することもできます。
次に例を示します(アンダースコアを使用してポインターを示します)。
var _x = [ 10 ];
function foo(_a){
_a[0] += 10;
}
foo(_x);
console.log(_x[0]);
収量
output: 20
ウィンドウオブジェクトから「x」を参照します
var x = 0;
function a(key, ref) {
ref = ref || window; // object reference - default window
ref[key]++;
}
a('x'); // string
alert(x);
遅い答えですが、クロージャを使って参照によってプリミティブ値を渡す方法に出くわしました。ポインタを作成するのはかなり複雑ですが、機能します。
function ptr(get, set) {
return { get: get, set: set };
}
function helloWorld(namePtr) {
console.log(namePtr.get());
namePtr.set('jack');
console.log(namePtr.get())
}
var myName = 'joe';
var myNamePtr = ptr(
function () { return myName; },
function (value) { myName = value; }
);
helloWorld(myNamePtr); // joe, jack
console.log(myName); // jack
ES6では、ラムダ式を使用するようにコードを短縮できます。
var myName = 'joe';
var myNamePtr = ptr(=> myName, v => myName = v);
helloWorld(myNamePtr); // joe, jack
console.log(myName); // jack
Javascriptは、多くの問題を解決するために、ポインタをミックスコズに配置する必要があります。これは、コードが未知の変数名または動的に作成された変数を参照できることを意味します。また、モジュラーコーディングとインジェクションが簡単になります。
これは、実際にcポインターに到達できる最も近いものと私が見ているものです。
jsで:
var a = 78; // creates a var with integer value of 78
var pointer = 'a' // note it is a string representation of the var name
eval (pointer + ' = 12'); // equivalent to: eval ('a = 12'); but changes value of a to 12
cで:
int a = 78; // creates a var with integer value of 78
int pointer = &a; // makes pointer to refer to the same address mem as a
*pointer = 12; // changes the value of a to 12
JavaScriptでは、それはグローバルになります。ただし、関数は次のようになります。
function a(){
x++;
};
はグローバルコンテキストにあるためx
、関数に渡す必要はありません。
JavaScriptには参照によってプリミティブを取得するためのPerlの「\」演算子がないため不可能かもしれませんが、このパターンを使用してプリミティブの「効果的なポインタ」オブジェクトを作成する方法があります。
このソリューションは、プリミティブがすでにある場合(つまり、他のコードを変更せずにオブジェクトに入れることができない場合)に最も理にかなっていますが、コードの他の部分をいじくり回すには、そのプリミティブへのポインターを渡す必要があります。その状態で; したがって、ポインタのように動作するシームレスプロキシを使用して、その状態をいじくり回すことができます。
var proxyContainer = {};
// | attaches a pointer-lookalike getter/setter pair
// | to the container object.
var connect = function(container) {
// | primitive, can't create a reference to it anymore
var cant_touch_this = 1337;
// | we know where to bind our accessor/mutator
// | so we can bind the pair to effectively behave
// | like a pointer in most common use cases.
Object.defineProperty(container, 'cant_touch_this', {
'get': function() {
return cant_touch_this;
},
'set': function(val) {
cant_touch_this = val;
}
});
};
// | not quite direct, but still "touchable"
var f = function(x) {
x.cant_touch_this += 1;
};
connect(proxyContainer);
// | looks like we're just getting cant_touch_this
// | but we're actually calling the accessor.
console.log(proxyContainer.cant_touch_this);
// | looks like we're touching cant_touch_this
// | but we're actually calling the mutator.
proxyContainer.cant_touch_this = 90;
// | looks like we touched cant_touch_this
// | but we actually called a mutator which touched it for us.
console.log(proxyContainer.cant_touch_this);
f(proxyContainer);
// | we kinda did it! :)
console.log(proxyContainer.cant_touch_this);
JavaScriptでは、関数を参照して変数を渡すことはできません。ただし、参照によってオブジェクトを渡すことができます。
Cやポインタのある言語とは対照的に、私は考えています:
/** Javascript **/
var o = {x:10,y:20};
var o2 = {z:50,w:200};
。
o == o2 // obviously false : not the same address in memory
o <= o2 // true !
o >= o2 // also true !!
それは大きな問題です:
これは、アプリケーションによって作成(割り当て)されたすべてのオブジェクトを一覧表示/管理できることを意味します。
その膨大なオブジェクトのリストから、これらに関するいくつかの情報を計算します(たとえば、オブジェクトがどのようにリンクされているか)。
ただし、特定のオブジェクトについて作成した情報を取得する場合、二分法で膨大なリストにその情報を見つけることはできません。実際のメモリアドレスの代わりに使用できるオブジェクトごとの一意の識別子はありません。
これは最終的に、JavaScriptで記述したい場合、これが大きな問題であることを意味します。
JavaScriptは、参照によるプリミティブ型の受け渡しをサポートしていません。ただし、回避策があります。
渡す必要のあるすべての変数をオブジェクトに入れます。この場合、変数は1つだけですx
。変数を渡す代わりに、変数名を文字列( 。)として渡します"x"
。
var variables = {x:0};
function a(x)
{
variables[x]++;
}
a("x");
alert(variables.x);
やりたいことに応じて、変数名を保存して、後で次のようにアクセスすることができます。
function toAccessMyVariable(variableName){
alert(window[variableName]);
}
var myFavoriteNumber = 6;
toAccessMyVariable("myFavoriteNumber");
特定の例に適用するには、次のようにします。
var x = 0;
var pointerToX = "x";
function a(variableName)
{
window[variableName]++;
}
a(pointerToX);
alert(x); //Here I want to have 1 instead of 0
ポインタ、話の終わりをサポートしていません:-(。
私はまったく新しいCのバックグラウンドを持っていますが、イベントループとスタックについて読んでいることから、どのオブジェクトも呼び出し元にできるだけ近づける必要があることを付け加えたいと思います。私は真新しいので、これは間違っている可能性があります。
ここでの多くの回答は、グローバルにすることを提案していますが、正しく読んでいると、スタックホップが増加し、ある意味で、イベントループが不必要に断片化する可能性があります(呼び出されたオブジェクトが現在実行していることによって異なります)。
また、ポインタを模倣する例は、同じことを行うための多くの点で1であり、ポインタではありません。
私は最も引用された答えに同意しますが、ポインタまたはポインティングオブジェクトはいつでも変更されるべきではないため、'var'引数から、'let'、またはこの場合は'const'を使用することに注意してください。
const x = {value: 0};
function foo(obj){
++obj.value;
}
foo(x);
alert(x.value);
あなたの例では、実際には同じ名前の2つの変数があります。(グローバル)変数xと関数スコープ変数x。同じ名前の2つの変数をどう処理するかを選択できる場合、javascriptは関数のスコープ名を使用し、スコープ外の変数を無視するのは興味深いことです。
javascriptが常にこのように動作すると仮定するのはおそらく安全ではありません...
乾杯!