🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

3回答

553閲覧

JavaScriptのmap()がもとのオブジェクトにまで影響してしまうのは何故ですか?

hanyoaka

総合スコア15

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

1グッド

2クリップ

投稿2019/10/27 16:01

JavaScript

1let responseJson = { 2data: { 3children:[ 4{data:{url:"example.com"}}, 5{data:{url:"example.com"}}, 6{data:{url:"example.com"}}, 7{data:{url:"example.com"}}, 8{data:{url:"example.com"}}, 9] 10} 11}; 12 13console.log(responseJson); 14 15let threads = responseJson.data.children.slice(0, 2); 16 17threads.map(i => i.key = i.data.url);

このようなコードでresponseJsonを出力すると、以下のような結果が出力されます。(抜粋)

console

1data: {…} 2children: (5) […] 30: Object { data: {…}, key: "example.com" } 41: Object { data: {…}, key: "example.com" } 52: Object { data: {…} } 63: Object { data: {…} } 74: Object { data: {…} } 8length: 5

なぜresponseJsonに影響するのでしょうか?また、responseJsonを保持したい場合どのような工夫ができますか?

miyabi_pudding👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

js

1let threads = responseJson.data.children.slice(0, 2);

は元のresponseJson.data.childrenの(先頭2つの)要素への参照をコピーした新しい配列を返しています。
つまり、responseJson.data.childrenの(先頭2つの)要素とthreadsの各要素は同じオブジェクトを参照しています。

  • responseJson.data.children[0]threads[0]は同じオブジェクトを参照している。
  • responseJson.data.children[1]threads[1]は同じオブジェクトを参照している。

そのため、threads[0]を操作した場合、responseJson.data.children[0]を操作したのと同じことになります。


また、なにを意図しているのか不明ですが、(普通、Array.prototype.map()は新しい配列を作るために使います。)

js

1threads.map(i => i.key = i.data.url);

js

1threads.map(function(i) { 2 i.key = i.data.url; // <- オブジェクトを変更している。 3 return i.key; 4});

と同じ意味なので、threads[0]threads[1]が変更されます。


また、responseJsonを保持したい場合どのような工夫ができますか?

値をコピーしたオブジェクトを作るとか。

JavaScript

1threads.map(i => {data:{url:i.data.url}, key:i.data.url});

投稿2019/10/27 17:00

編集2019/10/27 21:34
draq

総合スコア2577

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

本質問は、JavaScriptにおける、値の扱いの仕様、
値の参照の置き換えが関係していきます。

非公式でないので、正確性に欠ける可能性がありますが、
読んでいる限りは、合っていると思ったので、
参考記事を記載します。

JavaScriptに参照渡し/値渡しなど存在しない - Qiita

まず、プリミティブな値(数値や文字列など)が基本とすると理解できる、かと思いますので、その解説から。

javascript

1let a = 10; // 値10が生成され、aは、10という値への参照となる。 2console.log(a) // 10

基本、変数は、メモリに格納された値の参照であり、変数自体には値が入っていないということです。

では、変数に変数を代入した時はどうなるかというと、

javascript

1let a = 10; 2let b = a; // 変数bは、値10への参照になる。aもbも10という値を"参照"している状態 3console.log(a) // 10 4console.log(b) // 10

となります。
ですが、プリミティブな値の場合、bを変更しても、a自体はなんら変化がありません。
それはなぜかというと、

javascript

1let a = 10; 2let b = a; // 変数bは、値10への参照になる。aもbも10という値を参照している状態 3b = 100; // 値100が新たに生成され、bはその値への参照となる。aとは独立している(aは値10への参照を失わない) 4console.log(a); // 10 5console.log(b); // 100

となり、ようは、参照の置き換えが発生します。

では、本質問のようなことがなぜ起こるのか。
配列やオブジェクトではそもそも参照している段階が違うと言いますか、
プリミティブなものとは、参照している値が違うからです。
※今回の質問は配列ですが、オブジェクトの方が説明がしやすいので、オブジェクトで解説していきます。

javascript

1const a = {key: 0, value: 15}; // aは{}の参照となる。そして、各プロパティは、各値の参照となる

という状態になり、a自体は、{}というオブジェクト自体の参照となります。
そして、各プロパティは、各値の参照となります。
よって、このオブジェクト参照の変数を、他の変数に代入するとどうなるか。

javascript

1const a = {key: 0, value: 15}; // aは{}の参照となる。そして、各プロパティは、各値の参照となる 2const b = a; // bは{key,value}というオブジェクト自体の参照となる 3b.value = 35; // {key,value}というオブジェクトの、valueの値の参照が置き換わる。そのため、a、b自体の参照は置き換わらない 4// よって、下記のような結果となる 5console.log(a.value); // 35 6console.log(b.value); // 35

つまり、変数に、オブジェクト変数を代入すると、
その代入先は、代入元のオブジェクト自体の参照となります。
そして、そのオブジェクトのプロパティに値を代入し直すと、
そのプロパティ自体の値の参照が置き換わるが、
オブジェクト自体への参照が置き換わるわけではないため、
a、b自体はなんら変わるわけではないわけです。
a、bは同じオブジェクトを参照しているため、bの方でプロパティの値参照を変えようと、aの方で変えようと、
同じオブジェクトを参照しているため、プロパティは共通の値となるのです。

例えば、一つのコップをAさんBさんが同時に手にもっているとします。
コップには水が入っています。
Bさんが、コップの水を捨て、お茶に置き換えれば、コップの中身は変わっても
コップ自体は変わらないのと同じです。
(二人の人間が手に持ちながら、中身を入れ直す絵面は、想像すると微妙ですが)

これは、配列においても同じことがいえます。
(というかJavaScriptにおいては配列もオブジェクト)

javascript

1const a = ['まさひこ', 'たかひこ']; // aは[0, 1]の参照となる。そして、要素(インデックス)は、各値の参照となる 2const b = a; // bは[0, 1]という配列自体の参照となる 3b[0] = 'ひこざぶろう'; // [0, 1]という配列の、0インデックスの値の参照が置き換わる。そのため、a、b自体の参照は置き換わらない 4// よって、下記のような結果となる 5console.log(a[0]); // ひこざぶろう 6console.log(b[0]); // ひこざぶろう

よって、今回の配列のような参照元の配列の値の参照が置き換わるので、今回の質問のような結果となります。

前回答状態では、誤解と、間違った回答となっていたため、
大変に失礼しました。

また、間違っている部分があれば、ご指摘いただければ幸いです。

投稿2019/10/27 17:01

編集2019/10/28 01:43
miyabi_takatsuk

総合スコア9555

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hayataka2049

2019/10/27 22:32

渡してないのに◯◯渡しという言葉で説明することに違和感を覚えます。
Zuishin

2019/10/27 23:40 編集

C# にも値型と参照型はあります。つまりこの回答で言う C# で言う値渡しと参照渡しのようなものを参照渡しを使わずにすることができます。このコメントの意味がわかりますでしょうか? 用語が適切に使われていないために、このコメントのように回答がややこしくなっています。 リンク先にも書いてある通り、JavaScript には参照渡しの概念は無いので、わざわざ誤解を招く用語を使う必要はありません。「似ているからいいじゃないか」と主張する人がよくいますが、それはその人が参照渡しを理解できず参照型と勝手に混同しただけで、全く似ていません。 たとえば国民主権について「戦時中でいう天皇主権のようなもの」と説明する人がいたら嫌でしょう? 違う意味で使われているものをわざわざ持ち出さなくても説明できるはずです。 参照型と参照渡しが似ているのは主に名前というだけなので、同一視する意味はありません。
miyabi_takatsuk

2019/10/27 23:52

hayataka2049さん > ご指摘ありがとうございます。 Zuishinさん > ご指摘ありがとうございます。 回答を修正していきます。
guest

0

MDNのArray.prototype.map() (構文)を最初に示しますね。

  • コールバックの処理結果は代入式の左辺にある変数(new_array)で結果を受け取ります。
  • コールバック関数は、新しい配列要素となる値の返却が必要

draq さんの回答に重複しますが、ループの中で元のオブジェクトの値を書き換えるだけの処理になっています。

javascript

1// threads.map(i => i.key = i.data.url); は以下のループに等しい 2for( let idx=0; idx<threads.length; ++idx ) { 3 let i = threads[idx]; 4 (void 0).push(i.key = i.data.url); 5 // threads[idx].key = threads[idx].data.url; 実行しているが、 6 // new_array に該当する新しいArray用変数がない 7}

単にurlを抽出するだけなら

javascript

1let rslt = threads.map( function(i){ 2 return i.data.url 3}); 4console.log(rslt) // ["example.com", "example.com"]

投稿2019/10/28 01:14

編集2019/10/28 01:22
AkitoshiManabe

総合スコア5434

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問