【TC39 Proposals】Math Extensions

# 注意書き

2019 年 10 月 9 日に開催の [#tc39_study](https://web-study.connpass.com/event/147538/) 用に作成した資料です。
執筆時点で TC39 の Proposals に上がっている機能を紹介します。
将来的に JavaScript（ECMAScript）に取り入れられるかもしれませんし、取り入れられないかもしれませんし、紹介内容から仕様が大きく変更になるかもしれません。
TC39 の承認プロセスについては、https://tc39.es/process-document/ をご覧ください。

---

# Math Extensions

`Math` に 4 つの関数と 2 つの定数を追加する Proposal です。
コンピュータグラフィックス方面で時々使うような処理が追加されます。
本記事の執筆時点で Stage 1 です。

---

# `Math.clamp(x, lower, upper)`

`x` が `lower` を下回ったときは `lower` を、`upper` を上回った時は `upper` を、どちらでもないときは `x` を返すような関数です。
値が設定された下限と上限を超えないように変換するときに有用です。
`Math.min` と `Math.max` を使えば同等の処理ができます。

## 使い方

```javascript
console.log(Math.clamp(0, -100, 100))
// -> 0

console.log(Math.clamp(-200, -100, 100))
// -> -100

console.log(Math.clamp(200, -100, 100))
// -> 100

console.log(Math.clamp(NaN, -100, 100))
// -> NaN

console.log(Math.clamp(0, NaN, 100))
// -> NaN

console.log(Math.clamp(0, -100, NaN))
// -> NaN
```

## 同等の処理

```javascript
const clamp = (x, lower, upper) => {
  return Math.min(Math.max(x, lower), upper)
}
console.log(clamp(0, -100, 100))
console.log(clamp(-200, -100, 100))
console.log(clamp(200, -100, 100))
console.log(clamp(NaN, -100, 100))
console.log(clamp(0, NaN, 100))
console.log(clamp(0, -100, NaN))
```

---

# `Math.scale(x, inLow, inHigh, outLow, outHigh)`

`x` を線形変換した値を返します。
2つの数直線があり、片方に `x` と `inLow`、`inHigh` が、もう片方に `y` と `outLow` 、 `outHight` があり、`inLow` と `outLow`、`inHigh` と `outHigh` がそれぞれ対応しているとき、`x` に対応する `y` を計算するイメージです。

![scale.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4249/3c2a0e5a-7ad0-c655-611b-97758f06701d.png)

以下の関係が成り立ちます。

```math
\frac{x - \text{inLow}}{\text{inHigh} - \text{inLow}} = \frac{y - \text{outLow}}{\text{outHigh} - \text{outLow}}
```

## 使い方

```javascript
console.log(Math.scale(50, 0, 100, -10, 10))
// -> 0

console.log(Math.scale(200, 0, 100, -10, 10))
// -> 30

console.log(Math.scale(80, 0, 100, 10, -10))
// -> -6

console.log(Math.scale(NaN, 0, 100, -10, 10))
// -> NaN

console.log(Math.scale(50, NaN, 100, -10, 10))
// -> NaN

console.log(Math.scale(50, 0, NaN, -10, 10))
// -> NaN

console.log(Math.scale(50, 0, 100, NaN, 10))
// -> NaN

console.log(Math.scale(50, 0, 100, -10, NaN))
// -> NaN

console.log(Math.scale(Infinity, 0, 100, -10, 10))
// -> Infinity

console.log(Math.scale(-Infinity, 0, 100, -10, 10))
// -> -Infinity

console.log(Math.scale(50, -Infinity, 100, -10, 10))
// -> NaN

console.log(Math.scale(50, 0, Infinity, -10, 10))
// -> -10

console.log(Math.scale(50, 0, 100, -Infinity, 10))
// -> NaN

console.log(Math.scale(50, 0, 100, -10, Infinity))
// -> Infinity
```

---

# `Math.radians(degrees)`

`degrees` をラジアンに変換した値を返します。

## 使い方

```javascript
console.log(Math.degrees(-1))
// -> -57.29577951308232

console.log(Math.degrees(0))
// -> 0

console.log(Math.degrees(1))
// -> 57.29577951308232

console.log(Math.degrees(Math.PI))
// -> 180

console.log(Math.degrees(2 * Math.PI))
// -> 360

console.log(Math.degrees(3 * Math.PI))
// -> 540

console.log(Math.degrees(NaN))
// -> NaN

console.log(Math.degrees(+Infinity))
// -> Infinity

console.log(Math.degrees(-Infinity))
// -> -Infinity
```

---

# `Math.degrees(radians)`

`radians` を度数に変換した値を返します。

## 使い方

```javascript
console.log(Math.radians(-120))
// -> -2.0943951023931953

console.log(Math.radians(0))
// -> 0

console.log(Math.radians(120))
// -> 2.0943951023931953

console.log(Math.radians(240))
// -> 4.1887902047863905

console.log(Math.radians(360))
// -> 6.283185307179586

console.log(Math.radians(480))
// -> 8.377580409572781

console.log(Math.radians(NaN))
// -> NaN

console.log(Math.radians(+Infinity))
// -> Infinity

console.log(Math.radians(-Infinity))
// -> -Infinity
```

---

# `Math.RAD_PER_DEG`

1° あたりのラジアンを表す定数です。

```math
\frac{180}{\pi} = 57.29577951308232
```

---

# `Math.DEG_PER_RAD`

1 ラジアンあたりの度数を表す定数です。

```math
\frac{\pi}{180} = 0.0174532925199432
```

---

# Polyfill

`core-js/proposals/math-extensions` を読み込んでください。

CommonJS

```javascript
require('core-js/proposals/math-extensions')
```

ES Modules

```javascript
import 'core-js/proposals/math-extensions'
```

---

# 所感

JavaScriptでお絵描きしてたらたまに必要になる。
個人的に特に`scale` は、これのためだけにd3-scaleを入れたりするので標準で入ってくれると嬉しい。

---

# 参考情報

* https://github.com/rwaldron/proposal-math-extensions
* https://github.com/likr-sandbox/tc39-study/tree/master/proposal-math-extensions