ゼロからはじめるプログラミング講座の第三十二回です。今回は配列と連想配列のコピーについて解説します。少しややこしいのでしっかり確認していってください。
配列、連想配列をコピーしてみよう。
配列と連想配列をコピーする前に普通の変数を複製してみましょう。
var a = "a"
var b = a
console.log(a)
console.log(b)
a
なんの問題もなく変数aを変数bに代入できましたね。
では次は代入したものの中身を書き換えてみます
var a = "a"
var b = a
b = "b" // bを書き換え
console.log(a)
console.log(b)
b
これも何の問題もありませんね。今まで通りに中身が書き換わっています。
では次は配列をコピーして中身を書き換えてみたいと思います。
var a = ["a","b"]
var b = a
console.log(a) // Array [ "a", "b" ]
console.log(b) // Array [ "a", "b" ]
b = "a"
console.log(a) // 変わらず
console.log(b) // "a"
Array [ “a“, “b” ]
Array [ “a“, “b” ]
a
で?別に普通の動作じゃないか?
はい、ここまでは今までの知識通りの動作です。では次はコピーした配列に値を追加してみるので確認してください。
var a = ["a","b"]
var b = a
console.log(a) // Array [ "a", "b" ]
console.log(b) // Array [ "a", "b" ]
b[2] = "c"
b.push("d")
console.log(a) // Array [ "a", "b", "c", "d" ]
console.log(b) // Array [ "a", "b", "c", "d" ]
Array [ “a“, “b” ]
Array [ “a“, “b“, “c“, “d” ]
Array [ “a“, “b“, “c“, “d” ]
なんと新規追加をしていない配列aにも配列bに追加したものが入ってしまっています。
これは非常にめんどうなことになっていますがもちろん期待通りの複製方法もあります。
まず何故このようにコピー元の配列aにも追加が起こってしまったかを解説します。
それは変数bに渡されたものは配列aへの参照だったからです。
何故参照が渡されたかというと配列はオブジェクト型だからです。
オブジェクト型とプリミティブ型について知ろう。
プリミティブ型とは
オブジェクト型と対になるものです。
そもそもオブジェクト型が何かも説明していませんね。まずオブジェクト型とは値の集合体のことです。そして対になるプリミティブ型は値が1つのものです。
具体的にどんなものがあるかをあげます。
プリミティブ型:
- string型:”文字列”のこと
- number型:数値のこと -1 0 1 2…
- boolean型:真偽値のこと true false
- null型,undefined型,symbol型:これらは覚えなくてよい
オブジェクト型:プリミティブ型以外のもの
データの型を知る方法を一応紹介しておきます。興味のある方は調べてください。
var a = ["a","b"]
var b = "a"
var c = 10
console.log(typeof a) // Object
console.log(typeof b) // String
console.log(typeof c) // Number
typeofを使うことで型を調べることができます。
プリミティブ型のコピーは値が渡されます。
オブジェクト型のコピーは参照が渡されます。
このように配列のコピーはオブジェクト型なので参照が渡されて配列の中身を追加するとコピー元の配列も変わってしまうのです。
配列を値渡しでコピーしてみよう。
参照渡しではコピー元の配列も操作してしまうので配列でも値渡しをしましょう。
function copy(arr){
var out = new Array()
for(var i=0, r=arr.length; i<r; i++){
out[i] = arr[i]
}
return out
}
var a = ["a","b","c"]
var b = copy(a)
b.push("d")
console.log(a)
console.log(b)
Array [ “a“, “b“, “c“, “d” ]
まずは配列をコピーするようの関数を作ります。練習も兼ねて関数にしています。
値を入れる空の配列を作るにはnew Array()で作ります。連想配列の場合はnew Object()でしたね。もちろんどちらもオブジェクト型です。
引数で受け取った配列をforループで回して1つずつ値をoutに入れていきます。
ループが終わった後はreturnで配列outを返します。
値渡しでコピーした配列はコピー元とは別の実体を持っているので誤ってコピー元を操作してしまうことはありません。
練習問題を解いてみよう。
- 区画名a-cに対応する値1-3を持つ連想配列aを作りなさい。
- 連想配列をコピーして返す関数copy()を作りなさい。
- 関数copy()を利用して連想配列aをコピーした連想配列bを作りなさい。
- 連想配列bにd:4を追加しなさい。
- コンソールでaを表示しなさい。コンソールでbを表示しなさい。
正解するとこうなります。
Object { a: 1, b: 2, c: 3, d: 4 }
解答例はこうです。(マウスオーバーで表示)
function copy(arr){
var out = new Object()
for(key in arr){
out[key] = arr[key]
}
return out
}
var a = {a:1, b:2, c:3}
var b = copy(a)
b.d = 4 // b["d"] = 4;でもいい
console.log(a)
console.log(b)
正解しましたか?連想配列のループはfor inループを使いましょう。
配列、連想配列のコピーは関数を用意したり少し面倒ですが実はJavaScriptがあらかじめ用意してくれたメソッドもあります。それは今度紹介します。
お疲れ様でした。次回は雑談回です、いよいよ基礎編が終わり実践編へ移る準備です。
次も頑張って記事を作るのでチャレンジしてください!
JavaScript #1/#2/#3/#4/#5/#6/#7/#8/#9/#10/#11/#12/#13/#14/#15/#16/#17/#18/#19/#20
_(__つ/ ̄ ̄ ̄/
\/ /
 ̄ ̄ ̄
(´・ω・`)
_( つ ミ バタンッ
\ ̄ ̄ ̄\ミ
 ̄ ̄ ̄ ̄