JavaScript 未分類の覚書き

未分類の覚書きです。`Map`や配列関係のものは別に投稿しています。

# オブジェクトリテラルで配列の長さを指定して作成する

`Array.from`は1番目の引数にオブジェクトリテラル`{length: 要素数}`を指定できます。2番目の引数`mapFn`と組み合わせることで一時的な配列を作成せずに指定長の配列を作成できます。

```js
Array.from({length: 100})
// (100) [undefined, undefined, ..., undefined]

Array.from({length: 100}, (_, i) => i)
// (100) [0, 1, ..., 98, 99]

Array.from({length: 100}, (_, i) => 2 + i * 2)
// (100) [2, 4, ..., 198, 200]
```
動作確認環境：Google Chrome 84.0.4147.105（Windows、64 ビット）

# 関数が`new`演算子で呼び出されたか判断する

`function`内部で`new.target`を呼び出すとnew演算子で呼び出されたか判断できます。

```js
function f1()
{
    console.log(`this: ${this}, new.target: ${new.target}`);
}
// new演算子なしで呼び出すとthis == グローバルオブジェクト、new.target == undefined
f1();
// this: [object Window], new.target: undefined

// new演算子ありで呼び出すとthis == 新しいインスタンス、new.target == コンストラクタや関数への参照
new f1();
// this: [object Object], new.target: function f1()
// {
//     console.log(`this: ${this}, new.target: ${new.target}`);
// }
```
動作確認環境：Google Chrome 84.0.4147.105（Windows、64 ビット）

- [new.target - MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/new.target)

# 関数は`new`演算子の有無で`this`の値と省略時の戻り値が異なる

```js
function f1()
{
    this.a = 1;
    this.b = 2;
}
// 新しいインスタンスを作成してそのフィールドa、bに値を代入する。
t = new f1();
// thisに代入したのでグローバル変数a、bは存在しません。
console.log(`global: a=${a}, b=${b}`); // Uncaught ReferenceError: a is not defined
// newで呼び出した関数はreturnの省略時にthisを返します。
console.log(`f1: a=${t.a}, b=${t.b}`); // f1: a=1, b=2
delete a;
delete b;

// 関数f1を呼び出してグローバル変数a、bに値を代入する。
t = f1();
// newが指定されていないのでthisはグローバル変数を指します。
// したがってグローバル変数a、bが作成されます。
console.log(`global: a=${a}, b=${b}`); // global: a=1, b=2
// newなしで呼び出した関数はreturnの省略時にundefinedを返します。
console.log(`f1: a=${t.a}, b=${t.b}`); // Uncaught TypeError: t is undefined
```

# `Array`関数は`Array`コンストラクタ（`new Array`）として振る舞う

`Array`関数は`new Array`と同様の機能を提供します。これは`Array`関数の特別な振る舞いであり、通常は`new`演算子の有無で動作が変わることに注意してください。

# `Array`型の`@@iterator`メソッドの別名

```js
const array1 = [0, 1, 2];
array1[Symbol.iterator] === array1.values; // true
```

仕様です。[Array.prototype\[@@iterator\]() - JavaScript | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/@@iterator)。

# イテラブル、イテレーター、イテレーターリザルトの判定

```js
// オブジェクトがイテレータのプロトコルを実装するか判断します。
const implementsIterable = (obj) => obj && obj[Symbol.iterator] instanceof Function && obj[Symbol.iterator].length == 0;
//  オブジェクトがイテラブルのプロトコルを実装するか判断します。
const implementsIterator = (obj) => obj?.next instanceof Function && obj.next.length == 0;
// オブジェクトがイテレーターリザルトのプロトコルを実装するか判断します。
const implementsIteratorResult = (obj) => obj && "value" in obj && typeof obj.done === "boolean";

const array1  = [0, 1, 2];
const iter1   = array1[Symbol.iterator]();
const result1 = iter1.next();

console.log(implementsIterable(array1));  // true
console.log(implementsIterable(iter1));   // true
console.log(implementsIterable(result1)); // false

console.log(implementsIterator(array1));  // false
console.log(implementsIterator(iter1));   // true
console.log(implementsIterator(result1)); // false

console.log(implementsIteratorResult(array1));  // false
console.log(implementsIteratorResult(iter1));   // false
console.log(implementsIteratorResult(result1)); // true
```

参考
- [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/in](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/in)
- [https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Iteration_protocols](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Iteration_protocols)