1
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 3 years have passed since last update.

Javascriptの Array.isArray()を理解する。

Last updated at Posted at 2021-04-20

書いた後で気づいたのですが、こちらの方が書いた記事のほうが
完成度が何倍も高いので是非こちらをご一読ください。

javascriptの型などの判定いろいろ

背景

Typescriptを学び始めて、引数の型を判別する関数を書いていたある日、
ふとある疑問が浮かびました。

**Array.isArray(args)**ってメソッドは何のためにあるんだ:question::question:

Array.isArray() - Javascript MDN

instanceofとかtypepfで判別するのはだめなの???

typeof - Javascript MDN

instanceof - Javascript MDN

もしかしたら同じような疑問を持つ方が今後いらっしゃるかもしれない
&何かの助けになればと思い、記事として残しておきます。

typeofの性質

typeof

console.log(typeof 42);
// expected output: "number"

console.log(typeof 'blubber');
// expected output: "string"

typeofの後に続く変数(MDNではoperandと記載)の型を判定してくれます。
このtypeofを用いた判定、一見便利そうに見えて実は
プリミティブ型(StringとかNumberとか)
Function
Object
Symbol

のいずれか(一応undefinedも)のみを返します。

偉大な先人様のわかりやすい記事↓
プリミティブ型とオブジェクト型

console.log(typeof ['a', 'b', 'c'] === 'object');
// true 

console.log(typeof "test" === 'object');
// false typeof "test" → String (プリミティブ型)

//nullはtrue, typeof NaNはnumber, typeof undefinedはundefinedを返す
console.log(typeof null === 'object');
// true
console.log(typeof NaN)
//number
console.log(typeof undefined)
//undefined
console.log(['a', 'b', 'c'] instanceof Array);
//true

console.log(['a', 'b', 'c'] instanceof Object);
// javascriptにおいてすべてのオブジェクトはObjectを継承しているのでtrue

ArrayはObject型なのでtypeofを使っても'object'として判定されてしまいますね。

そこで、別の手段として
Object.prototype.toString.call()やArg.constructorを使って型を判定することができます。

console.log(Object.prototype.toString.call('test'));
// [object String]
console.log(Object.prototype.toString.call(1));
// [object Number]
console.log({}.toString.call([1, 2, 3]));
// [object Array]

//引数が関数かどうかを判定
const isFunc = (value: unknown):boolean => {
  return value && {}.toString.call(value) === "[object Function]"
}

console.log([1, 2, 3].constructor === Array);
//true
console.log("test".constructor === String);
// true

これで判定できるんだったらArray.isArray()無くてもいいのか.....?という結論になりかけたんですが、こちらに答えが書いてありました(英語サイトです。)
要約すると(拙訳すいません。御指摘ください。)

  • Object.prototype.toString.call(args) === "[object Array]"で判定するのはいい方法だけど、Object.prototype.toStringとかFunction.prototype.callの挙動が変更になったとき影響を受ける恐れがあるよ(そんなことあるんかいな...)
    (but that relies on Object.prototype.toString and Function.prototype.call not being changed (probably a good assumption but still fragile).)

  • instanceof Arrayとか、A.constructor === Arrayは、複数windowをまたぐときにとか、スコープが違う時には動作が保証されないよ。
    (What about arrays in different windows? The shared-mutation hazard of having arrays in two coordinating windows be instances of the same Array constructor, sharing the same Array.prototype, is enormous when either page augments Array.prototype (not to mention the security problems when one page is malicious!), so Array and Array.prototype in each window must be different. Therefore, by the semantics of instanceof, o instanceof Array works correctly only if o is an array created by that page's original Array constructor (or, equivalently, by use of an array literal in that page))
    (o.constructor === Array is one, with the same problem as an instanceof check.)

その点、Array.isArray()はiframesで動作するので複数windowをまたいでも正常に動作するようなので安心ですね。

結論

JavascriptにおいてArray型の判別はArray.isArray()が便利

ただし、Array.isArray()はES5の構文なので、polyfillを考えないといけない場合はおとなしくObject.prototype.toString.call()での判別でいいと思います。

以下MDNにあったpolyfill例

if (!Array.isArray) {
  Array.isArray = function(arg) {
    return Object.prototype.toString.call(arg) === '[object Array]';
  };
}

この他にもnew String等を使った場合の型など、javascriptの型システムは結構落とし穴がなにかと多い印象です....
稚拙な記事でしたが、どなたかの学びのきっかけになれば幸いです。

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