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

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

ただいまの
回答率

90.51%

  • JavaScript

    20427questions

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

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

受付中

回答 6

投稿

  • 評価
  • クリップ 0
  • VIEW 666
退会済みユーザー

退会済みユーザー

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

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

var listA = [];
var listB = [1,2,3];

listA = listB.concat();

console.log(listA); // => [1, 2, 3]
console.log(listB); // => [1, 2, 3]

listB.shift()
console.log(listA); // => [2, 3]
console.log(listB); // => [1,2, 3]

console.log(listA[1] === listB[0]) // => true
var listA = [];
var listB = [1,2,3];

listA = listB;
console.log(listA); // => [1, 2, 3]
console.log(listB); // => [1, 2, 3]

listB.shift()
console.log(listA); // => [2, 3]
console.log(listB); // => [2, 3]

console.log(listA[0] === listB[0]) // => true

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

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

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

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 6

+3

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

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

こんにちは。

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

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

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

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

参考:
concat()
比較演算子

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

こんにちは。

一つ目の

  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への"ショートカットアイコン"みたいなイメージだと伝わりますかね?

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

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

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

めっちゃ不思議ですね。

 解説

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

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

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

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

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

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

var concatArray = function(list){
   var newList = [];
   for(var i in list){
     newList.push(list[i]);
   }
}


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


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

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

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

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

a=[];
elm1 = [1,2]; elm2 = [3,4]; elm3 = [5,6];
b = [elm1,elm2,elm3];
a = b.concat();  console.log(a===b); //false
elm1[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に代入します。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

同じタグがついた質問を見る

  • JavaScript

    20427questions

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