LoginSignup
2
1

More than 5 years have passed since last update.

map, filterの写像でつまづいた(starwars解説)

Last updated at Posted at 2018-04-24

Star Warsで解説

starwars.js
const episode1 = [
  { name: 'Anakin', jedi: true },
  { name: 'Luku', jedi: true }
]
const episode3 = episode1.map(char => char)

// Dirk side
episode3[0].jedi = false

console.log(episode1)
// [ { name: 'Anakin', jedi: false },{ name: 'Luku', jedi: false } ]
console.log(episode3)
// [ { name: 'Anakin', jedi: false },{ name: 'Luku', jedi: true } ]

アナキンはエピソード3でダークサイドに墜ちるのでjedi = falseに変更。
...あれ、episode1でシスに落ちとるがな、ストーリー上ありえないので修正

答えから言うとmap, filterは中のオブジェクトまでは写像しない!

starwars.js
const episode1 = [
  { name: 'Anakin', jedi: true },
  { name: 'Luku',
  jedi: false }
]
const episode3 = episode1.map(char => Object.assign({}, char))

// Dirk side
episode3[0].jedi = false

console.log(episode1)
// [ { name: 'Anakin', jedi: true },{ name: 'Luku', jedi: false } ]
console.log(episode3)
// [ { name: 'Anakin', jedi: false },{ name: 'Luku', jedi: false } ]

Object.assign()でオブジェクト自体も新しいものを作ってあげると解決!
無事ストーリーが進みそう。

filterでもはまった

jediだけを抽出し配列を作る。前回の反省にならってObject.assign()を使う。

starwars.js
const episode1 = [
  { name: 'Anakin', jedi: true },
  { name: 'Luku', jedi: true },
  { name: 'Amidala', jedi: false }
]
const episode3 = episode1.filter(char => {
  if (char.jedi) {
    return Object.assign({}, char)
  }
})

// Dirk side
episode3[0].jedi = false

console.log(episode1)
// [ { name: 'Anakin', jedi: false }, { name: 'Luku', jedi: true }, { name: 'Amidala', jedi: false } ]
console.log(episode3)
// [ { name: 'Anakin', jedi: false }, { name: 'Luku', jedi: true } ]

アナキンがシスになってる...

ジェダイ図書館で調べたところ、
filterは値が偽の場合値を返さない
真の場合値をそのまま返す
つまりObject.assignは実行されていない。

これはおったまげ、ジャージャーが非常事態にパルパティーンに武力行使権を与えるのも納得。

解決法

starwars.js
const episode1 = [
  { name: 'Anakin', jedi: true },
  { name: 'Luku', jedi: true },
  { name: 'Amidala', jedi: false }
]
const episode3 = episode1.filter(char => {
  if (char.jedi) {
    return char
  }
}).map(char => Object.assign({}, char))

// Dirk side
episode3[0].jedi = false

console.log(episode1)
// [ { name: 'Anakin', jedi: true }, { name: 'Luku', jedi: true }, { name: 'Amidala', jedi: false } ]
console.log(episode3)
// [ { name: 'Anakin', jedi: false }, { name: 'Luku', jedi: true } ]

なるほど、filterにmapを連結して新しい配列を返す。
ジェダイ・マスターへの道は遠い...

2
1
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
2
1