web-dev-qa-db-ja.com

変数が配列であるかオブジェクトであるかを効率的に確認する方法(NodeJSおよびV8)

NodeJS&V8で、変数がオブジェクトか配列かを効率的にチェックする方法はありますか?

MongoDBとNodeJSのモデルを作成しています。オブジェクトツリーをトラバースするには、オブジェクトが単純(Number、String、...)か、複合(Hash、Array)かを知る必要があります。

V8には高速な_Array.isArray_が組み込まれているようですが、オブジェクトがオブジェクトであるかどうかを確認する方法はありますか? _new String()のようなものではなく、ハッシュ_{}_またはクラスのインスタンスのような複雑なオブジェクトを意味しますか?

通常、これは次のように実行できます。

_Object.prototype.toString.call(object) == "[object Object]"
_

またはこれ:

_object === Object(object)
_

しかし、この操作は安くはないようです。おそらくもっと効率的な方法があるのでしょうか?普遍的でなく、すべてのエンジンで機能しない場合でも問題ありません。V8でのみ機能する必要があります。

40

すべてのオブジェクトは、ECMAScriptの少なくとも1つのクラス(Object)のインスタンスです。 _Object#toString_を使用してのみ、組み込みクラスのインスタンスと通常のオブジェクトを区別できます。これらは、_{}_またはnew演算子を使用して作成されたかどうかなど、すべて同じレベルの複雑さを持っています。

Object.prototype.toString.call(object)はここでは機能しないため、通常のオブジェクトと他の組み込みクラスのインスタンスを区別するには、object === Object(object)が最善の策です。しかし、私があなたがしていることをする必要がある理由がわからないので、おそらくユースケースを共有するなら、私はもう少し助けを提供できます。

22
Andy E

追加の関数呼び出し(速度)なしでオブジェクトまたは配列に対して単純にチェックするため。

isArray()

isArray = function(a) {
    return (!!a) && (a.constructor === Array);
};
console.log(isArray(        )); // false
console.log(isArray(    null)); // false
console.log(isArray(    true)); // false
console.log(isArray(       1)); // false
console.log(isArray(   'str')); // false
console.log(isArray(      {})); // false
console.log(isArray(new Date)); // false
console.log(isArray(      [])); // true

isObject()

isObject = function(a) {
    return (!!a) && (a.constructor === Object);
};
console.log(isObject(        )); // false
console.log(isObject(    null)); // false
console.log(isObject(    true)); // false
console.log(isObject(       1)); // false
console.log(isObject(   'str')); // false
console.log(isObject(      [])); // false
console.log(isObject(new Date)); // false
console.log(isObject(      {})); // true
79
zupa

Objectを扱っているかどうかを検出するだけなら、

_Object.getPrototypeOf( obj ) === Object.prototype
_

ただし、これはおそらく、オブジェクト以外のプリミティブ値では失敗します。実際、[[cclass]]プロパティを取得するために.toString()を呼び出しても問題はありません。次のような素敵な構文を作成することもできます

_var type = Function.prototype.call.bind( Object.prototype.toString );
_

そして、それを次のように使用します

_if( type( obj ) === '[object Object]' ) { }
_

最速の操作ではないかもしれませんが、パフォーマンスリークが大きすぎるとは思いません。

20
jAndy

underscore.jsは次を使用しています

toString = Object.prototype.toString;

_.isArray = nativeIsArray || function(obj) {
    return toString.call(obj) == '[object Array]';
  };

_.isObject = function(obj) {
    return obj === Object(obj);
  };

_.isFunction = function(obj) {
    return toString.call(obj) == '[object Function]';
  };
14
Lordking

typeofを使用して、見ている変数がオブジェクトかどうかを判断します。もしそうなら、私はinstanceofを使ってそれがどんな種類かを決定します

var type = typeof elem;
if (type == "number") {
    // do stuff
}
else if (type == "string") {
    // do stuff
}
else if (type == "object") { // either array or object
    if (elem instanceof Buffer) {
    // other stuff
10
DanielS

こんにちは、私はこのトピックが古いことを知っていますが、Node.jsの配列を他のオブジェクトと区別するはるかに良い方法があります docs を見てください。

var util = require('util');

util.isArray([]); // true
util.isArray({}); // false

var obj = {};
typeof obj === "Object" // true
9
DeMeNteD

変数の型を発見するための迅速で簡単な解決策を見つけました。

ES6

export const isType = (type, val) => val.constructor.name.toLowerCase() === type.toLowerCase();

ES5

function isType(type, val) {
  return val.constructor.name.toLowerCase() === type.toLowerCase();
}

例:

isType('array', [])
true
isType('array', {})
false
isType('string', '')
true
isType('string', 1)
false
isType('number', '')
false
isType('number', 1)
true
isType('boolean', 1)
false
isType('boolean', true)
true

[〜#〜] edit [〜#〜]

「未定義」および「null」値を防止するための改善:

ES6

export const isType = (type, val) => !!(val.constructor && val.constructor.name.toLowerCase() === type.toLowerCase());

ES5

function isType(type, val) {
  return !!(val.constructor && val.constructor.name.toLowerCase() === type.toLowerCase());
}
4
jlcv

パラメーターが確実に配列またはオブジェクトのいずれかになることがわかっている場合、このようなオブジェクトをチェックするよりも配列をチェックする方が簡単です。

function myIsArray (arr) {
    return (arr.constructor === Array);
}
3
weaVaer

私のプロジェクトを使用できる最良の方法。トリッキーな方法でhasOwnPropertyを使用してください。

var arr = []; (or) arr = new Array();
var obj = {}; (or) arr = new Object();

arr.constructor.prototype.hasOwnProperty('Push') //true (This is an Array)

obj.constructor.prototype.hasOwnProperty('Push') // false (This is an Object)
2
VIJAY P

そこにあるjQueryを見るjQuery.isArray(...)

    isArray = Array.isArray || function( obj ) {
    return jQuery.type(obj) === "array";
}

これにより、_jQuery.type

    type = function( obj ) {
    return obj == null ?
        String( obj ) :
        class2type[ toString.call(obj) ] || "object";
}

もう一度確認する必要があります:class2type

class2type = {};

// Populate the class2type map
jQuery.each("Boolean Number String Function Array Date RegExp Object".split(" "), function(i, name) {
    class2type[ "[object " + name + "]" ] = name.toLowerCase();
});

ネイティブJSの場合:

var a, t = "Boolean Number String Function Array Date RegExp Object".split(" ");
for( a in t ) {
    class2type[ "[object " + t[a] + "]" ] = t[a].toLowerCase();
}

これは次のようになります。

var isArray = Array.isArray || function( obj ) {
    return toString.call(obj) === "[object Array]";
}
1
andlrc

この関数を使用して解決しました:

function isArray(myArray) {
    return myArray.constructor.toString().indexOf("Array") > -1;
}
0
Bernard Doci

このような簡単な機能を見つけました。

function getClass(object) {
    return Object.prototype.toString.call(object).slice(8, -1);
}

および使用法:

if ( getClass( obj ) === 'String' ) {
    console.log( 'This is string' );
}
if ( getClass( obj ) === 'Array' ) {
    console.log( 'This is array' );
}
if ( getClass( obj ) === 'Object' ) {
    console.log( 'This is Object' );
}
0
l13s7 ae

レコードについては、lodashにも isObject(value) があります

0
Sash

時間が経つことはわかっていますが、この問題を解決する新しい(より高速でシンプルな)方法があるため、答えを更新すると思いました。 ECMAscript 5.1 yoでは、Arrayクラスで利用可能なisArray()メソッドを使用できます。

YoのドキュメントはMDNで見ることができます こちら

現在、互換性の問題はないはずですが、念のため、これをコードに追加する場合は、Array.isArray()がポリフィルされていることが常に安全である必要があります。

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