次のJavaScriptコードを検討してください。
var bar = function () { alert("A"); }
var foo = bar;
bar = function () { alert("B"); };
foo();
このコードを実行すると、「A」が表示されます。この動作はjavascript仕様の一部ですか?信頼できますか?
はい、それは予想通りであり、仕様です。
あなたの質問は基本的に:foo
はbar
をポインターまたは参照として別の言語で参照しますか?
答えはノーです。割り当て時のbar
の-valueがfoo
に割り当てられます。
他の例では、値によって何も渡されませんでした。すべてが参照渡しされました。
barとfooは両方のポインターです
JavaScriptのNONプリミティブオブジェクトへのすべての変数/ハンドルはポインターです。ポインターはjavascriptにネイティブであり、デフォルトです。
var bar = function () { alert("A"); } //bar is a pointer to function1
var foo = bar; //pointer copied; foo is now also a pointer to function1
bar = function () { alert("B"); }; //bar points to function2
foo(); //foo is still a pointer to function1
コピーと思われる場合、隠れたエラーやバグが発生します。特に複雑なオブジェクトを扱う場合。例えば
function person(name){this.name = name}
var john = new person("john")
var backup = john
backup.name //john
john.name = "jack"
backup.name //jack, NOT john
Javascriptの非プリミティブを実際にコピーするには、a = bよりも多くの作業が必要です。例えば:
function person(name){ this.name = name}
var john = new person("john")
var backup = new Object()
backup = JSON.parse(JSON.stringify(john))
backup.__proto__ = john.__proto__ //useful in some cases
john.name = "jack"
backup.name //john
私はここに少し遅れていますが、とにかく答えて何かを肉付けしようと思いました。
仕様を扱う際にJavaScript(またはECMAScript)の内部について議論するときは、ポインターとメモリ参照の観点から考えないことが最善です。変数は内部的に環境レコードであり、メモリアドレスではなく名前で保存および参照されます。割り当てステートメントは、内部的におよび設計により、環境レコード名(「foo」または「bar」)を検索し、そのレコードに値を割り当てています。
そう、
var bar = function () { alert("A"); }
環境レコード「バー」に値を割り当てています(匿名関数)。
var foo = bar;
レコード "bar"に関連付けられた値を取得し、その値をレコード "foo"に関連付けるGetValue( "bar")を内部的に呼び出します。したがって、その後はfooに関連付けられているため、barの元の値を引き続き使用できます。
JavaScriptはメモリアドレスではなく文字列による参照であるため、次のようなことができます。
someObject["someProperty"]
プロパティ名に基づいて値を検索しています。
無名関数の値をポインターではなく変数に割り当てています。
ポインターを使用する場合は、コピーではなく参照で渡されるオブジェクトを使用できます。
ここではいくつかの例を示します。
「obj2」は「obj1」の参照です。「obj2」を変更すると、「obj1」が変更されます。 false
に警告します。
var obj1 = {prop:true},
obj2 = obj1;
obj2.prop = false;
alert(obj1.prop);
「prop」はオブジェクトではないプロパティを指し、「prop」はこのオブジェクトへのポインタではなくコピーです。 「prop」を変更しても、「obj1」は変更されません。警告true
var obj1 = {prop:true},
prop = obj1.prop;
prop = false;
alert(obj1.prop);
「obj2」は、「obj1」の「subObj」プロパティへの参照です。 「obj2」が変更されると、「obj1」が変更されます。 false
に警告します。
var obj1 = {subObj:{prop:true}},
obj2 = obj1.subObj;
obj2.prop = false;
alert(obj1.subObj.prop);
はい、変数が関数を参照しているという事実に関して特別なことはありません。エイリアシングは含まれていません。
var bar = 1;
var foo = bar;
bar = "something entirely different";
// foo is still 1
はい、これは正しい動作です。
//create variable bar and assign a function to it
var bar = function () { alert("A"); }
//assign value of bar to the newly created variable foo
var foo = bar;
//assign a new function to the variable bar
//since foo and bar are not pointers, value of foo doesn't change
bar = function () { alert("B"); };
//call the function stored in foo
foo();
これらは関数ポインターではありません(JSにはネイティブにポインターはありません)。 JSの関数は匿名にすることができ、ファーストクラスオブジェクトです。したがって
function () { alert("A"); }
実行時に「A」を警告する匿名関数を作成します。
var bar = function () { alert("A"); };
その機能をバーに割り当てます。
var foo = bar;
fooをbarに割り当てます。これは関数「A」です。
bar = function () { alert("B"); };
barを匿名関数「B」に再バインドします。これはfooや他の関数「A」には影響しません。
foo();
関数「A」であるfooに保存されている関数を呼び出します。
実際に機能点がある言語ではCはfoo
にも影響しません。再割り当てで「B」を取得するというアイデアがどこで得られるかわかりません。
void A(void) { printf("A\n"); }
void B(void) { printf("B\n"); }
typedef void(*fptr_t)(void);
fptr_t foo = A;
fptr_t bar = foo;
bar = B;
foo(); // should print "A"
これは、関数へのポインタではなく、名前のない関数に変数を割り当てています
はい、元の「A」関数へのポインタを作成しました。バーを再割り当てすると、再割り当てになりますが、古い関数への参照はそのまま残ります。
あなたの質問に答えるために、はい、あなたはそれに頼ることができます。
これは、事前定義された名前付き関数でも機能することを追加したいだけです:
function myfunc() { alert("A"); }
var bar = myfunc;
var foo = bar;
bar = function () { alert("B"); };
foo();
これは同じことを行い、関数名が配列名(ポインター)のように機能することを示します。
コード内の各FunctionDeclaration fについて、ソーステキストの順序で以下を実行します。
FnをFunctionDeclaration fの識別子とします。
第13節で説明されているように、foをFunctionDeclaration fをインスタンス化した結果とします。
FuncAlreadyDeclaredを、引数としてfnを渡すenvのHasBinding具象メソッドを呼び出した結果とします。
FuncAlreadyDeclaredがfalseの場合、envのCreateMutableBinding具象メソッドを呼び出して、引数としてfnとconfigurableBindingsを渡します。
参考文献