如何有效地检查变量是否是数组或对象(在NodeJS& V8中)?

时间:2012-01-12 11:12:43

标签: javascript node.js v8 instanceof typeof

有没有办法有效地检查变量是Object还是Array,在NodeJS& V8?

我正在为MongoDB和NodeJS编写一个模型,并且要遍历对象树,我需要知道对象是简单的(Number,String,...)还是复合(Hash,Array)。

V8似乎有快速内置Array.isArray,但如何检查对象是否是对象?我的意思是复杂的对象,如哈希{}或类的实例,而不是new String()

通常可以这样做:

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

或者这个:

object === Object(object)

但似乎这种操作并不便宜,也许有一些效率更高?如果它不是通用的并且不适用于所有引擎,那就没关系,我只需要在V8上工作。

13 个答案:

答案 0 :(得分:76)

只需检查对象或数组而无需额外的函数调用(速度)。

<强> 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

答案 1 :(得分:22)

所有对象都是ECMAScript中至少一个类的实例 - Object。您只能使用Object#toString区分内置类和普通对象的实例。它们都具有相同的复杂程度,例如,它们是使用{}还是new运算符创建的。

Object.prototype.toString.call(object)是区分正常对象和其他内置类实例的最佳选择,因为object === Object(object)在此处不起作用。但是,我看不出你为什么需要做你正在做的事情的原因,所以如果你分享用例,我可以提供更多的帮助。

答案 2 :(得分:19)

如果它只是检测你是否正在处理Object,我能想到

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

但是,对于非对象原始值,这可能会失败。实际上,调用.toString()来检索[[cclass]]属性并没有错。您甚至可以创建一个很好的语法,如

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

然后像

一样使用它
if( type( obj ) === '[object Object]' ) { }

这可能不是最快的操作,但我不认为那里的性能泄漏太大。

答案 3 :(得分:14)

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]';
  };

答案 4 :(得分:10)

我使用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

答案 5 :(得分:9)

您好我知道这个主题已经过时但是有一种更好的方法来区分Node.js中的Array和任何其他对象看看docs

var util = require('util');

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

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

答案 6 :(得分:3)

我可以使用我的项目的最佳方式。以棘手的方式使用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)

答案 7 :(得分:2)

刚刚找到了一个快速简单的解决方案来发现变量的类型。

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

修改

改善以防止&#39; undefined&#39;和&#39; null&#39;值:

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());
}

答案 8 :(得分:2)

如果您知道某个参数肯定是一个数组或一个对象,那么检查一个数组可能比检查具有类似内容的对象更容易。

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

答案 9 :(得分:1)

在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]";
}

答案 10 :(得分:1)

我用这个函数来解决:

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

答案 11 :(得分:0)

我知道它已经有一段时间了,但我想我会更新答案,因为有更新(更快更简单)的方法来解决这个问题。 由于ECMAscript 5.1哟可以使用isArray()类中的Array方法。

哟可以在MDN here中看到它的文档。

我认为您现在不应该遇到兼容性问题,但为了以防万一,如果您将此代码添加到代码中,那么Array.isArray()是多层填充应始终是安全的:

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

答案 12 :(得分:0)

仅供记录,lodash也有isObject(value)