質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.50%
JavaScript

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

Q&A

6回答

1569閲覧

配列コピーの基本的なことを確認させてください。

退会済みユーザー

退会済みユーザー

総合スコア0

JavaScript

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

0グッド

0クリップ

投稿2016/01/25 04:12

javascriptの勉強をしております。

配列をコピーする際にコピーの仕方による挙動の違いに少し混乱してしまったので、確認させて下さいませ!

javascript

1var listA = []; 2var listB = [1,2,3]; 3 4listA = listB.concat(); 5 6console.log(listA); // => [1, 2, 3] 7console.log(listB); // => [1, 2, 3] 8 9listB.shift() 10console.log(listA); // => [2, 3] 11console.log(listB); // => [1,2, 3] 12 13console.log(listA[1] === listB[0]) // => true

javascript

1var listA = []; 2var listB = [1,2,3]; 3 4listA = listB; 5console.log(listA); // => [1, 2, 3] 6console.log(listB); // => [1, 2, 3] 7 8listB.shift() 9console.log(listA); // => [2, 3] 10console.log(listB); // => [2, 3] 11 12console.log(listA[0] === listB[0]) // => true

1つ目の方はlistBに入った配列の箱への参照自体をlistAにコピーしたという認識で合ってますでしょうか?

逆に2つ目の方はlistBに入った配列が持つ各値への参照をlistAにコピーしたという認識でよろしいでしょうか?

非常に基礎的な質問で恐縮ですが、ご回答頂けると助かります。

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

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

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

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

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

guest

回答6

0

捉え方がまったく違います。

1つ目の方は、listBの配列を要素ごとにコピー(シャローコピー)して、listAにセットしています。そのため、listAlistBは配列として別個に操作できます。なお、配列の中身が整数なので目立たないですが、配列の中身まではコピーされず、同じオブジェクトを共有することになりまう。

2つ目の方は、listBlistA同じ配列オブジェクトを共有する形となっています。そのため、片方を書き換えればもう片方も書き換わります。

どちらの例でも、listAの宣言時に定義した配列はただ捨てられます(宣言だけにして配列を代入しなかったとしても、まったく同じ動作をします)。代入時のオブジェクトに置き換わってしまう感じです。

投稿2016/01/25 04:37

maisumakun

総合スコア145121

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

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

0

こんにちは。

1番目のものは、
concat()で配列の中身をコピーしたもので、
listAとlistBの中身は別々のものとして作成されます。

console.log(listA===listB);
と厳密比較演算子で比較すると
false
と返ってきます。

しかし、2番目のものは、オブジェクト指向でいうところの参照渡しなので、
同じメモリの場所を見ている状態になります。

なので、listBをshift()するとlistAにも影響しますので、
console.log(listA===listB);
と厳密比較演算子で比較すると
true
と返ってきます。

参考:
concat()
比較演算子

投稿2016/01/25 04:56

kaputaros

総合スコア1844

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

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

0

javascript

1a=[]; 2elm1 = [1,2]; elm2 = [3,4]; elm3 = [5,6]; 3b = [elm1,elm2,elm3]; 4a = b.concat(); console.log(a===b); //false 5elm1[0] = 0; console.log(a[0][0]); //0

こんな感じにするとわかりやすいと思います。
bは[[1,2],[3,4],[5,6]]ですが、実際には[elm1のアドレス,elm2のアドレス,elm3のアドレス]のような配列のアドレスが入っています。

**a=b.concat(); **
これは[elm1のアドレス,elm2のアドレス,elm3のアドレス]これを複製して
出来上がった配列のアドレスをaに代入します。
a,bは別々の配列ですが、a[0],b[0]には同じelm1のアドレスが入っています。

a=b;
これはbと同じ配列へのアドレスをaに代入します。

投稿2016/01/25 14:56

編集2016/01/25 15:00
hirohiro

総合スコア2068

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

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

0

基本的な質問はかえって回答が難しいのでやりがいを感じます。

2番目は、たぶんあっています。(Javascriptの変数は変数名そのもので管理するので、厳密な形では違いがあるような気がするのですが、うまく説明する知識がありません。)

1つ目の方はlistBに入った配列の箱への参照自体をlistAにコピーしたという認識で合ってますでしょうか?

正直、意味がよくわかりませんでしたのでコードで説明します。
1番目はlistA = listB.concat();と等価になるlistA = concatArray(listB);という配列コピー関数を定義したとするとこのようになります。

javascript

1var concatArray = function(list){ 2 var newList = []; 3 for(var i in list){ 4 newList.push(list[i]); 5 } 6}

配列の中身を逐一コピーしているので、listAとlistBは別の配列になります。


シンボルが変数とちょっと違うというコードがかけたので、余談として楽しんでいただければ・・・
(蛇足ともいう)

javascript

1var addA = function(b) {return a + b;} 2addA(2); // シンボルaが定義されていないので、エラー 3var a = 1; // addAが定義され時にない値を定義 4addA(3); // 4が返る 5a = "a" 6add("b") // "ab"が返る

これは、CやJavaではありえないことで、javascriptが実行時にaというシンボル(名前)を探すという動作をしているためです。

投稿2016/01/25 11:44

編集2016/01/25 12:19
iwamoto_takaaki

総合スコア2883

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

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

0

エスパー回答ですが、あなたはPHPから来ましたね?
まずはコレを見て下さい。

PHP

1echo (['1'] === ['1']? 'true': 'false'); 2// true

JavaScript

1console.log(['1'] === ['1']? 'true': 'false'); 2// false

めっちゃ不思議ですね。

解説

PHPは中身が同じものであればtrueになります。

JavaScriptはインスタンスを生成する度に一意のIDを付与して、
メモリ空間に生まれた全く同じインスタンスに限りtrueとなるのです。
JavaScriptの配列は、Arrayオブジェクトから生成されたインスタンスなので生成する度に違うIDが割り当てられます。

以上の事から、JavaScriptでは[1] === [1]の結果はfalseになります。
もっと細かい内容は他の回答者様を御覧ください。

投稿2016/01/25 07:57

miyabi-sun

総合スコア21158

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

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

0

こんにちは。

一つ目の

listA = listB.concat()

は、listBの配列+αをlistAに設定しています。
※提示頂いた例だと、concatの引数に何も渡していないので、listBと全く同じ内容が生成されて、listAに設定されていますね。

たとえば、

listA = listB.concat([4,5,6]);

とすると、
listAの中身は1,2,3,4,5,6 で、
listBの中身は1,2,3 になります。

したがって、concatを使うとことで、listAとlistBは参照関係ではなく、
全く別のオブジェクトして定義されていることになりますね。
※配列内の要素も別オブジェクトです。

そのあと、listB.shift()でlistBの要素[0]を削除していおり、
直後に ===(厳密等価演算子)で判定していますね。

===(厳密等価演算子)は、オブジェクトの型も考慮して演算してくれます。
listAとlistBの中身はすべて数値型で定義されているようなので、
数字が合っていれば、trueが帰ってきます。
※==(等価演算子)の場合、 1=="1" でもtureになっちゃいます。
※これは、暗黙的に "1" == "1" に変換されてしまうためです。

二つ目の例で、

listA = listB;

ですが、これはlistAにlistBの参照を渡していることになります。
したがって、listAの実態はlistBのことですので、
密接な関係にあるといえますね。
※listAまたはlistBの中身を変えると、お互いに影響しあいます。

■さいごに、、、

1つ目の方はlistBに入った配列の箱への参照自体をlistAにコピーしたという認識で合ってますでしょうか?

答え:
いえ、少し違います。concatは新たにオブジェクトを生成して、
その結果をlistAに入れているため、listAとlistBは全く別物です。
中の各要素も、listAとlistBは別ものとして定義されます。

逆に2つ目の方はlistBに入った配列が持つ各値への参照をlistAにコピーしたという認識でよろしいでしょうか?

"各値"というより、"listBオブジェクトへの参照"が、listAに代入されているという意味のほうが正しいです。
コピーという言葉を使うと、少し混乱するかもしれません。
※listAは、listBへの"ショートカットアイコン"みたいなイメージだと伝わりますかね?

ご参考になれば幸いです。

投稿2016/01/25 04:57

hentai_nabe

総合スコア94

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問