【JavaScript】値の代入方法と仕組み
更新日:2023/10/16
プログラミングをする上で重要なのが代入です。
重要ですが多言語のプログラミング経験者なら、気にせずスルーできます。
しかし意外と知らないことがあるかもしれないので、確認してみましょう。
変数への代入
JavaScriptでは、値の代入は代入演算子(=)を使用します。
let value = 1;
value = 100; // 値の代入
constで宣言した変数には、代入できません。
代入すると、タイプエラーになります。
const value = 1;
value = 100; // TypeError: Assignment to constant variable.
JavaScriptは動的型付け言語なので、異なる型の値を代入できます。
let value = 1; // 数値型で初期化
value = "abcde"; // 文字列型を代入
どちらかと言うと『動的型付け言語』ではなくて、『型なんか気にしないよ言語』です。
プロパティへの代入
オブジェクトのプロパティへの代入も、代入演算子(=)を使用します。
その際、異なる型を代入できます。
const obj = { value:100 };
obj.value = 100; // 数値型を代入
obj.value = "abcde"; //文字列型を代入
存在しないプロパティに代入操作を行うと、プロパティが作成されます。
const obj = {};
obj.value = 100; // valueプロパティが作成され、数値型が代入される
obj.value = "abcde"; // 文字列型を代入
obj["value"] = 1000; // 配列形式でもプロパティアクセスできる
プロパティ名を誤記しても、エラーになりません。
const obj = { value:100 };
obj.volue = 200; // valueに代入
console.log( obj.value );
>> 100
僕は「なぜ、値が変わらない???」と数時間悩みました。
オブジェクトの代入
オブジェクトを値に持つ変数を他の変数に代入すると、二つの変数は同じオブジェクトを共有します。
const obj1 = { value1: 100 };
const obj2 = obj1;
// obj1のプロパティを変更
obj1.value1 = "abc";
console.log( obj2 );
>> { value1: 'abc' } // obj2も変更されている
// obj2にプロパティを追加
obj2.value2 = 200;
console.log( obj1 );
>> { value1: 'abc', value2: 200 } // obj1にもプロパティが追加されている
// 二つの変数が同じオブジェクト(の実体)を参照しているか確認
console.log( Object.is(obj1,obj2) ); // obj1 === obj2 でもOK
>> true
同じオブジェクトを共有しているので、一方の変数のプロパティ操作は、もう一方の変数に影響します。
なおJavaScriptの配列は、配列の機能を持ったオブジェクトです。
関数は、関数の機能を持ったオブジェクトです。
そのため、配列や関数を値に持つ変数を他の変数に代入すると、二つの変数は同じ配列または関数を共有します。
const array1 = [1,2,3];
const array2 = array1;
// 二つの変数が同じ配列(の実体)を参照しているか確認
console.log( Object.is(array1 ,array2 ) ); // array1 === array2 でもOK
>> true
const func1 = function(){};
const func2 = func1;
// 二つの変数が同じ関数(の実体)を参照しているか確認
console.log( Object.is(func1 ,func2 ) ); // func1 === func2 でもOK
>> true
==との違い
==および===は、二つの値を比較して true または false を返す比較演算子です。
通常はif文等で使用しますが、それ以外でもエラーではありません。
代入操作を行う場面で、=を二つ記述するような間違いも考えられます。
let value = 100;
value == 5; // 代入操作?
console.log( value );
>> 100
上記のコードは代入できていないので、値が変更されません。
意図的に記述しないと思いますが、それだけに見逃しやすく、発見が困難な不具合コードになります。
僕は、1時間悩みました。
代入の仕組み
一般的にプログラミングには、値渡しや参照渡しなどの概念があります。
代入の仕組みを知っておくと、JavaScriptが値渡しかそれとも参照渡しか、といった疑問の答えを知ることができます。
次のコードは、変数valueに数値1を代入しています。
let value = 1;
変数はコードの記述位置ではなくて、実行時(関数なら関数コード実行時)に用意されています。
値は計算時(リテラルはコード評価時)に用意されます。
そして、変数に『データと変数を関連付けるために必要な値(bound value)』がセットされて、変数とデータが関連付け(binding)されます。
bound valueがどのような値かはJavaScriptの仕様で定義されていません。
ブラウザ等に組み込む技術者側に一任されています。
次に、異なる値を変数にセットします。
value = 2;
内部では数値2へのbound valueが、セットされます。
他の変数を代入するケースもあります。
const value2 = 3;
value = value2;
二つの変数は、同じデータに関連付けられます。
値を代入したというよりも、関連付けをコピーしたイメージですね。
(1) value2のbound valueを参照して、実データ3を取得する。
(2) valueに、実データ3へのbound valueをセットする。
JavaScriptの数値や文字列などのプリミティブ値はデータとして扱われます。
オブジェクトもデータとして扱われ、代入操作ではプリミティブ値と区別されません。
そのためオブジェクトの代入も、関連付けをコピーしたイメージになります。
これにより、二つの変数が一つのオブジェクトを共有している形になります。
他のプログラミング言語は、変数が値を直接持っていて、代入すると上書きされるものがあります。
これは値渡しと呼ばれています。
値渡しはメモリの使用量を最小限に抑えるために、変数が型を持っています。
型を持つことで、各型に必要なバイト数だけメモリを確保します。
結果として、同じ型同士でのみ代入可能という制限があります。
JavaScriptは、イメージ的には関連付けという型のやりとりです。
同じ型のやりとりになるので、型を気にせず代入操作ができます。
変数が他の変数と関連付けられていて、値を変更すると関連先の値が変更されるプログラミング言語もあります。
この仕組みを参照渡しと呼ばれていて、関連付け値は参照値と呼んでいます。
JavaScriptは値渡しのように、値をコピーしません。
また参照渡しのように、相手側の値を変更することもありません。
この二つのパターンとは異なるのですが、方式についての名前は特にありません。
強いて言うなら、関連付け渡しかもしれません。
更新日:2023/10/16
関連記事
スポンサーリンク
記事の内容について
こんにちはけーちゃんです。
説明するのって難しいですね。
「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。
裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。
掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。
ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php
このサイトは、リンクフリーです。大歓迎です。