LoginSignup
0
0

More than 3 years have passed since last update.

BFE.dev解答記録 #88. JavaScriptでnegative indexをサポートする

Posted at

https://bfe.dev/ja はFrontEnd版のLeetCode、GAFAの面接を受けるなら練習した方がいいかなと。
以下は自分の練習記録です。

スクリーンショット 2020-10-09 15.57.52.jpg

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が求められるのはわかりました。

  1. 全ての変更は元のarrayにする
  2. 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はサポートしていない、それ以外のデータはちゃんと返している。

Alt Text

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ではない!!

Alt Text

[...arr]は動かない。。

[...arr] は実はSymbol.Iteratorを実行している、上記のproxyではdata持っていないから、元の配列のinteratorを実行する必要があるので、Function.prototype.bind() はいいかも、このように。

get(target, prop) {
  if (prop === Symbol.iterator) {
    return target[Symbol.iterator].bind(target)
  }
  ...
}

通った!

Alt Text

上記のコードはこちらで見れます。https://bigfrontend.dev/ja/problem/support-negative-Array-index/discuss/22

もし興味あれば、 BFE.devでやってみましょう

0
0
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
0
0