English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

jsの参照とコピー(値の伝達とアドレスの伝達)について簡単に説明

JavaScriptの参照とコピーについて詳しく説明する人はあまりいませんが、この概念を理解することで多くのことを理解することができます

非常に基本的なことをまず説明し、JavaScriptでデータ型がどのように渡されるかを見てみましょう

参照:オブジェクト、配列、関数

コピー:数字、ボルン

文字列は特別な説明が必要です。その特殊性から、参照を渡すかコピー値を渡すかを決定することができません(文字列の値は変更できないため、この問題に悩むのは意味がありませんが)しかし比較の際には明らかに値比較に属します(後で比較のことについて詳しく説明します)

使用中の具体的な表現について説明します

最も一般的な使用は割り当て

var a = 1;
var b = a;  //これはaのコピー値を割り当てる
b ++;
alert(a);  //"1"bの変更はaに影響しない
/****************************************/
var a = [1};
var b = a;   //これはaの参照を割り当てる 
b[0] ++;
alert(a); //"2"bの変更はaにも影響するが、もちろんb = [2];この変更はaには役立ちません。

関数の引数

値の伝搬:関数に渡されるのは数値のコピーであり、関数内での変更は外部から見えません。

var a = 1;
var b = 2;
function change(a,b) {
 var c = a;
 a = b;   //新しい参照を上書きします。
 b = c;
 alert(a);  //"2"     
 alert(b);  //"1"
};
change(a,b);
alert(a);  //"1"     
alert(b);  //"2"

参照の伝搬:値の参照の伝搬:関数に渡されるのは数値の参照であり、関数内での属性の変更は外部から見えますが、新しい参照を上書きすることは外部から見えません。例えば、

var a = [1, 2, 3};
var b = [5, 6};
function change(a,b) {
 a[0] = 4;  //属性の変更は外部から見えます。 
 var c = a;
 a = b;   //新しい参照を上書きします。
 b = c;
 alert(a);  //"5,6"     
 alert(b);  //"4,2,3"
};
change(a,b);
alert(a);  //"4,2,3"
alert(b);   //"5,6"

結果から見て、aとbは交換されていません。なぜなら、外部から見えない新しい参照を上書きしているからです。これは自然なことです。なぜなら、関数は参照を取得しているだけで、参照を変更する権限はありません。

これは少し違います。

var a = [1, 2, 3};
var b = [5, 6};
function change() {
 var c = a;
 a[0] = 4;
 a = b;
 b = c;
};
change();
alert(a);  //"5,6"
alert(b);  //"4,2,3"

ここで成功した交換が行われました。 

また、JavaScriptのブロックレベルのスコープについて言及します。これは他の言語では未定義エラーと報告されることでしょう。なぜなら、JavaScriptにはブロックレベルのスコープがありませんので、change内でa、bを見つけられない場合、自動的に上位のスコープに移動します。したがって、ここでのa、bはグローバル変数の参照です。

そして上のa、bはchange関数の変数であり、関数を呼び出す際にa、bの参照をこれらの変数に割り当てましたが、グローバルのa、bを変更することはできません。名前を変えることでより理解しやすくなります。

少し脱線しました。

参照とコピーについて戻ってみます。比較演算子での注意点について少し説明します。

値の比較は数値を比較し、参照の比較は参照を比較します。参照が異なる場合、数値が同じでも不等です。

1 == 1;  //true
1 === 1;  //true
[0] == [0]; //false
[0][0] == [0][0];  //true
[0][0] === [0][0];  //true
[0].toString() == [0].toString();  //true 

クロージャでは...

クロージャはJavaScriptの中で最も複雑なものの一つです。私の部署の面接の古典的な問題で、いつもよく出されます。

ここではクロージャのことについて説明しません。まずは値の伝搬と参照に関することだけ説明します。いつか明確な条項、簡潔な言葉、生き生きとした例を使ってそのものを完全に説明できるようになったら、このJavaScriptでは言わずと知れたその存在について詳細に説明します。

クロージャでは、内部関数が外部関数のローカル変数を使用する際には参照の方法ではなくコピーの方法を使用します。

実はこれもクロージャを理解する非常に重要な部分であり、非常に典型的なクロージャ現象を説明することができます。クロージャを説明する際によく使われる例です。

/*関数を構築し、配列のノードにイベントハンドラを設定します。ノードをクリックすると、そのノードのインデックスがalertされます。*/
var add_handlers = function (nodes) {
  var i;
  for (i = 0, l = nodes.length; i < l; i ++) {
    nodes[i].onclick = function (e) {
      alert(i);  // もちろん、この結果は常にノードの総数がalertされるというものでしょう。。。。
    };
  };
};

なぜ、常にノードの総数がalertされるのか、予想されるインデックス番号ではなく、コピーと参照を使って説明すれば非常に簡単です。

内部関数が外部変数を使用する際には、参照の方法を使用するのではなく、コピーを使用するため、各ノードにonclickイベントを設定する際に、iの参照をalertに渡していることを意味します。ノードをクリックしてonclickイベントがトリガーされたとき、iの値は既にノードの総数に変わっています。。。

var add_handlers = function (nodes) {
  var i;
  for (i = 0, l = nodes.length; i < l; i ++) {
    nodes[i].onclick = function (i) {
      return function(){
      alert(i);  
      };
 }(i);
  };
};

この修正が正しい理由は、現在渡されたのはiの値のコピーであり、実際には普通の関数と同じです。クロージャが加わったから迷子になったら困ります。本源に戻って考えれば、すぐにわかります。本源は先ほど述べたアドレスの伝達です。

付け加えると、クロージャという奇妙な名前に惑わされないでください。実際には、私たちが日常的に使う関数の原理と同じです。クロージャの「より長いライフサイクル」「プライベートな変数の保護」といった特性を除いて、普通の関数(または別の視点から、グローバル関数を特別なクロージャと見なすこともできます)として考えれば、簡単に理解できます。

大切なのは、すべての虚飾を捨てて、最も本質的なものに戻ることがです。。。話が脱線してしまいました。。。

以上の簡単な記事「jsにおける参照とコピー(値の伝達とアドレスの伝達)について」は編集者が皆さんに共有したすべての内容です。皆様に参考になれば幸いですし、ぜひ「叫び教程」を多くのご支援をお願いします。

おすすめ