LoginSignup
8
5

More than 3 years have passed since last update.

JavaScript の Object 参照について

Last updated at Posted at 2018-02-14

やりたかったこと

一つの連想配列(オブジェクト)を利用して、複数のオブジェクトを持った配列を作成。
特定のプロパティの値に対して連番を振りたかった。

コード


const makeObjArr = (obj, num) => {
    const results = [];
    for (let i = 1; i <= num; i++) {
        results.push(obj);
    }
    return results;
};

const incrementObj = (arr, targetKey) => {
    return arr.map((item, idx) => {
        item[targetKey] = item[targetKey] + String(idx + 1);
        return item;
    });
};

const a = {hoge: "hoge"};
const b = makeObjArr(a, 3);
console.log(incrementObj(b, "hoge"));

理想

{hoge: "hoge"} => [{hoge: "hoge1"}, {hoge: "hoge2"}, {hoge: "hoge3"}]

現実

{hoge: "hoge"} => [{hoge: "hoge123"}, {hoge: "hoge123"}, {hoge: "hoge123"}]

Q.なぜこうなった?

A. JavaScriptのObjectは参照渡しだから。
JSではプリミティブデータ型(Boolean, Null, Undefined, Number, String, Symbol)は値渡し。
Objectは参照渡しとなっています。(JavaScript に call by reference は存在しないため、誤解を生まないように打ち消し)
A. JavaScript の Object が保持するプロパティは書き換え可能だから。

例を挙げてみると

String


/* String */
var a = "a";
var b = a;
b = "b";
console.log(a);
console.log(b);
console.log(a === b);
a
b
false

Number


/* Number */
var a = 1;
var b = a;
b = 2;
console.log(a);
console.log(b);
console.log(a === b);
1
2
false

Symbol


/* Symbol */
var a = Symbol("a");
var b = a;
b = Symbol("b");
console.log(a);
console.log(b);
console.log(a === b);
Symbol(a)
Symbol(b)
false

コードを書いていて想定通りの動きになっているはず。
変数aの値は書き換えられず、変数bの値だけが書き換わっている状態。

ところがObjectだと・・・


/* Object */
var a = {value: "a"};
var b = a;
b["value"] = "b";
console.log(a);
console.log(b);
console.log(a === b);
{ value: 'b' }
{ value: 'b' }
true

見事にaのvalueプロパティの値が書き換えられている・・・。


/* {}とnew ObjectはObjectの生成/初期化を意味する */
var a = {};
var b = new Object;
var c = a;
console.log(a);
console.log(b);
console.log(a === b);
console.log(a === c);
c = {};
console.log(a === c);
{}
{}
false
true
false

で、どうすれば理想が現実になるの?

Object.assign()メソッドを使用する。


const makeObjArr = (obj, num) => {
    const results = [];
    for (let i = 1; i <= num; i++) {
        results.push(Object.assign({}, obj));
    }
    return results;
};

const incrementObj = (arr, targetKey) => {
    return arr.map((item, idx) => {
        item[targetKey] = item[targetKey] + String(idx + 1);
        return item;
    });
};

const a = {hoge: "hoge"};
const b = makeObjArr(a, 3);
console.log(incrementObj(b, "hoge"));
[ { hoge: 'hoge1' }, { hoge: 'hoge2' }, { hoge: 'hoge3' } ]

Object.assign()
一つ以上の ソース オブジェクトから、直接所有で (own) 列挙可能な (enumerable) すべてのプロパティの値を、ターゲット オブジェクトへコピーします。戻り値はターゲット オブジェクトです。

素敵。
ただし、IEでは動作しない可能性があるので、そこは注意が必要。
Babelとか使ってなくて、IE対応があるから使えない・・・って場合だったらfor文で頑張って下さい。

8
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5