10
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Linkbal(リンクバル)Advent Calendar 2019

Day 1

JavaScriptのビルトインオブジェクトを拡張する

Last updated at Posted at 2019-11-30

例えば、配列を拡張してrubyのようにfirstで1件目のエントリーを取得できるようにするにはどうすればよいか、
といったことを紹介します。

const arr = [1, 10, 100, 200]
arr.first // -> 1

拡張する方法を紹介する記事ですので、拡張している内容は特に重要ではありません。

注意

グローバルなものを変更してしまう内容を紹介しています。

一見便利に思えても、名前が衝突する可能性があったりしますので、実用するべきかどうかは慎重に検討してください。

(僕は個人の実装物でしかやりません)

そして、実装する内容も、本当に汎用的に使えるものに絞ったほうがよいです。

Mathオブジェクトに関数を拡張

この場合、単に好きなキー名に関数をアサインしてしまって大丈夫です。

Math.sum = (...numbers) => {
  return numbers.reduce((prev, current) => prev + current)
}

Math.sum(1, 10, 100) // -> 111

↑与えられた可変長引数の数値を全て合計して返す関数です。可変長引数やreduceの解説は省略。

Math.average = (...numbers) => {
  return Math.sum(...numbers) / numbers.length
}

Math.average(1, 10, 100) // -> 37

↑与えられた可変長引数の数値の平均を返す関数。さっきのsumを再利用。

Math.randomInt = (min, max) => {
  return Math.floor(Math.random() * (max + 1 - min)) + min
}

Math.randomInt(1, 100) // -> 55

↑第一引数〜第二引数の範囲で、ランダムに整数を返す関数。

Arrayのprototypeにgetter/setterを定義

prototypeを拡張する際は、definePropertyを使ってください。

Object.defineProperty(Array.prototype, 'first', {
  get () {
    return this[0]
  },
  set (value) {
    this[0] = value
  }
})

const arr = [1, 10, 100, 200]
arr.first // -> 1
arr.first = 5
arr.first // -> 5

配列の1件目にアクセスできるプロパティを実装してみました。

Arrayのprototypeに関数を拡張

同じくdefinePropertyを使い、valueに定義します。

Object.defineProperty(Array.prototype, 'random', {
  value () {
    return this[Math.randomInt(0, this.length - 1)]
  }
})

const arr = [1, 10, 100, 200]
arr.random() // -> 10
arr.random() // -> 200

↑配列内から一つのエントリーをランダムに取得します。さっきのrandomIntを再利用。

Object.defineProperty(Array.prototype, 'clear', {
  value () {
    return this.length = 0
  }
})

const arr = [1, 10, 100, 200]
arr.clear()
arr // -> []

↑配列を空にする関数です。

(配列はarr.length = 0で空にできますが、仕様を知っていないと何をしているか意味がわかりません。arr = []なら分かりやすいけど、別のオブジェクトになってしまうのでやっていることが全然変わってきます。なので明確な名前をつけて関数化しました。)

プリミティブ型のラッパーオブジェクトも拡張

手順は同じです。

Object.defineProperty(Number.prototype, 'half', {
  get () {
    return this / 2
  }
})
const num = 1280
console.log(num) // -> 1280
console.log(num.half) // -> 640
console.log(num.half.half) // -> 320
console.log(num.half.half.half) // -> 160

数値を半分にします。

補足

defineProperty

さきほどのdefinePropertyの第三引数で渡した記述子には、get, set, value以外にもありますので、詳しくは以下をご覧ください。

Objectのprototype

もちろんMathArray以外でも同じ方法で拡張できますが、Objectのprototypeは変更するとあらゆるものに影響してしまうのでやめたほうが良いです。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?