https://bfe.dev/ja はFrontEnd版のLeetCode、GAFAの面接を受けるなら練習した方がいいかなと。
以下は自分の練習記録です。
BFE.dev#88. JavaScriptでnegative indexをサポートする をみてみよう
説明をみよう
const originalArr = [1,2,3]
const arr = wrap(originalArr)
arr[0] // 1
arr[1] // 2
arr[2] // 3
arr[3] // undefined
arr[-1] // 3
arr[-2] // 2
arr[-3] // 1
arr[-4] // undefined
新しいobjetを返して、プロパティにいい感じのindexとvalueを設定するのは可能です。例えば {0:1, 1:2, 2:3, -1:3, -2:2, -3:1}
。
だけど下記のように元々の配列とシンクするのは不可能のようだ。
arr[-1] = 5
arr // [2,3,5]
originalArr // [2,3,5]
getter/setterを使えばsyncできそう、このように
Object.defineProperty(arr, '-1', {
get() {
return originalArr[2]
},
set(value) {
originalArr[2] = value
}
})
だけの-1
の他、-2
... -originalArr.length
もあるので、全部いちいち変更するのは無理を感じる。
Proxy は救世主
問題の説明からでは、ある意味のProxy
が求められるのはわかりました。
- 全ての変更は元のarrayにする
- negative indexのみ、戻り値をいじる
なず基本のproxyを書く
function wrap(arr) {
return new Proxy(arr, {
get(target, prop) {
return target[prop]
},
set(target, prop, value) {
target[prop] = value
return true
}
})
}
このproxyはただproxyするだけなので、negative indexはサポートしていない、それ以外のデータはちゃんと返している。
indexをいじる
propはnumberではないことを注意してください、まずnumberに変換しとこう。
get(target, prop) {
let index = parseInt(prop, 10)
// negative index
if (index < 0) {
index += target.length;
return target[index]
}
return target[prop]
},
set(target, prop, value) {
let index = parseInt(prop, 10)
// negative index
if (index < 0) {
index += target.length;
// negative index overflowed, too small
if (index < 0) {
throw new Error('not ok')
}
target[index] = value
return true
}
target[prop] = value
// don't forget to return true to indicate success
return true
}
iterableではない!!
[...arr]
は動かない。。
[...arr]
は実はSymbol.Iterator
を実行している、上記のproxyではdata持っていないから、元の配列のinteratorを実行する必要があるので、Function.prototype.bind()
はいいかも、このように。
get(target, prop) {
if (prop === Symbol.iterator) {
return target[Symbol.iterator].bind(target)
}
...
}
通った!
上記のコードはこちらで見れます。https://bigfrontend.dev/ja/problem/support-negative-Array-index/discuss/22
もし興味あれば、 BFE.devでやってみましょう