Little Red Book から文を借用します:
ECMAScript のすべての関数のパラメーターは値によって渡されます
値が単純型の場合は、それ自体です。参照型の場合、渡されるオブジェクトはそのオブジェクトを指すアドレスです。したがって、パラメータの受け渡しはすべて値の受け渡しであると考えることができますが、具体的にはどのように理解すればよいのでしょうか。例を見てみましょう:
var obj = { n: 1 }; function foo(data) { data = 2; console.log(data); //2 } foo(obj); console.log(obj.n) // 1
パラメータの転送を理解できると思います。参照型を渡すときは、ポインタを忘れずに渡してください。
最初にvar obj = {n: 1}
を実行します。これは、スタック アドレス 001 に{n:1}
へのポインターを格納していると見なされます。ポインター *pvar obj = {n: 1};
,可以看作在栈的001地址中存入了一个指向{n:1}
的指针*p
接下来为声明function foo
此时会创建函数执行上下文,产生一个变量对象,其中声明了形参data,由于函数没有执行,当前值为undefined。我们记data地址为022。关于更多变量对象的知识可以参考冴羽老师的这篇JavaScript深入之变量对象,本文不深入研究关于AO相关,你只需要知道在声明这个函数的时候里面的形参已经被创建出来了。
执行foo(obj)
其中会进行参数传递,其中将obj中存储的*p拷贝给处在022地址的data,那么此时它们就指向了同一个对象,如果某一个变量更改了n的值,另一个变量中n的值也会更改,因为其中保存的是指针。
进入函数内部,顺序执行data = 2;
此时002地址存储了基本类型值,则直接存储在栈中,从而与堆中的{n:1}失去了联系。从而打印console.log(data) // 2
,最后发现初始开辟的{n:1}对象没有过更改,故而console.log(obj.n) // 1
仍然打印1。
var obj = {n:1}; (function(obj){ console.log(obj.n); //1 obj.n=3; var obj = {n:2}; console.log(obj.n) //2 })(obj); console.log(obj.n) //3
整体来看这个例子中出现了同名覆盖的问题。不太了解代码如何执行的流程,可能会因为同名的关系而有些混乱,不过没关系。只要按照上一个例子的流程图中的执行过程,一定可以得出正确的结果。
声明变量obj,地址为011其中存入指向{n:1}的指针*p
声明函数,虽然同为obj变量名,但是形参obj为AO中的属性,不会与全局造成覆盖,其拥有新的地址记作022,在未执行前其值为undefined。
函数立即执行,此时将全局obj赋值给形参obj,我们忽略这个重复命名的问题,其实就是将011中的 指针*p拷贝了一份给了022。同时执行第一个console.log(obj.n)
结果即为1。
执行obj.n=3
,此时为函数的形参即022中的obj来改变了对象内n的值。
最关键的一步:var obj = {n:2};
由于对象命名的关系可能很多童鞋就会有点懵,但依然按照同样的方式来分析即可,由于使用了var那么就是新声明一个对象,从而会在栈中压入新的地址记作033,其中存入了新的指针指向了新的对象{n:2}。从而之后打印的console.log(obj.n)
结果则应是新开辟的对象中的n的值。
最后打印console.log(obj.n) //3
foo(obj)
を実行します。 objに格納されている*pをアドレス022のデータにコピーしたパラメータが渡され、このとき同じオブジェクトを指す変数がnの値を変更すると、もう一方の変数のnの値も変更されます。ポインタも格納されているため変更されます。
関数を入力し、
data = 2を順に実行します;
このとき、基本型の値はアドレス 002 に格納され、スタックに直接格納されるため、ヒープ内の {n:1} との接続が失われます。したがって、
console.log(data) // 2
を出力すると、最初に開いた {n:1} オブジェクトが変更されていないことが最終的にわかりました。そのため、
console.log(obj.n) / / 1 は依然として 1 を出力します。 2 番目の例rrreee 全体として、この例には同名カバレッジに問題があります。コードの実行の流れがよくわからないと、名前が同じなので少し混乱するかもしれませんが、大丈夫です。前の例のフローチャートの実行プロセスに従えば、正しい結果を得ることができます。 変数objを宣言し、アドレスは011で、 { n:1} へのポインタ pointer*p は、 obj 変数名は同じですが、仮パラメータ obj は AO の属性であり、グローバルで上書きされません。新しいアドレスは 022 として記録され、その値は実行前には未定義です。 関数はすぐに実行され、グローバルobjが割り当てられますobj を参照すると、この名前の重複の問題は無視されます。実際には、011 のポインタ *p を 022 にコピーします。同時に、最初の console.log(obj.n)
の実行結果は 1 になります。
obj.n=3
を実行> このとき、関数の仮引数、つまり022のobjがオブジェクト内のnの値を変更します。
最も重要なステップ:
var obj = {n:2};
オブジェクトの名前のせいで、多くの子供たちは少し混乱するかもしれませんが、var が使用されるため、同じ方法で分析できます。が宣言されているため、新しいアドレスがスタックにプッシュされ、033 として記録され、そこに新しいオブジェクト {n:2} を指す新しいポインタが格納されます。したがって、後で出力される
console.log(obj.n)
の結果は、新しく開かれたオブジェクトの n の値になるはずです。 最後に print
console.log(obj.n) //3
明らかに、グローバル オブジェクトはその値を 1 回 3 に変更しています。
まとめ
ここまで、上記の 2 つのコードに含まれる変数の「精神的な旅」をすべて説明してきました。作者は専門家ではないため、この図のスタック名と変数名の説明は正確ではない可能性があります。とても正確です。間違いがないか確認してください。遠慮せずに教えてください。重要な点は、私が表現したいことを理解できるということです。一般的に重要なのは、パラメータを渡す過程で値のコピーが存在すること、同時に代入オブジェクトが参照型の場合はポインタを渡すことです。この 2 つの点を理解した上で分析してください。前のフローチャートで説明したように、同様の問題が再び発生すると思いますが、より一貫したアプローチが必要です。
関連する推奨事項:
コンポーネント間のジャンプパラメータ転送を実装するための vue-router について
以上がJavaScript パラメータ受け渡し図のチュートリアルの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。