简体   繁体   English

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

[英]How to efficiently check if variable is Array or Object (in NodeJS & V8)?

Is there any way to efficiently check if the variable is Object or Array, in NodeJS & V8?在 NodeJS 和 V8 中,有什么方法可以有效地检查变量是对象还是数组?

I'm writing a Model for MongoDB and NodeJS, and to traverse the object tree I need to know if the object is simple (Number, String, ...) or composite (Hash, Array).我正在为 MongoDB 和 NodeJS 编写模型,为了遍历对象树,我需要知道对象是简单的(数字、字符串……)还是复合的(哈希、数组)。

It seems that V8 has fast built-in Array.isArray , but how to check if object is an Object?好像 V8 内置了快速的Array.isArray ,但是如何检查 object 是否是 Object 呢? I mean complex object like hash {} or instance of class, not something like new String() ?我的意思是像 hash {}这样的复杂对象或类的实例,而不是像new String()这样的东西?

Usually it may be done as this:通常可以这样做:

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

or this:或这个:

object === Object(object)

But it seems that this operations aren't cheap, maybe there's some more efficient?不过这个操作好像不便宜,说不定还有更高效的呢? It's ok if it's not universal and doesn't works on all engines, I need it only to work on V8.如果它不是通用的并且不适用于所有引擎,那没关系,我只需要它在 V8 上工作。

For simply checking against Object or Array without additional function call (speed).用于简单地检查对象或数组而无需额外的函数调用(速度)。

isArray() 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()

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

All objects are instances of at least one class – Object – in ECMAScript.所有的对象都是至少一个类的实例- Object -在ECMAScript中。 You can only differentiate between instances of built-in classes and normal objects using Object#toString .您只能使用Object#toString区分内置类和普通对象的实例。 They all have the same level of complexity, for instance, whether they are created using {} or the new operator.它们都具有相同的复杂程度,例如,无论它们是使用{}还是new运算符创建的。

Object.prototype.toString.call(object) is your best bet to differentiate between normal objects and instances of other built-in classes, as object === Object(object) doesn't work here. Object.prototype.toString.call(object)是区分普通对象和其他内置类实例的最佳选择,因为object === Object(object)在这里不起作用。 However, I can't see a reason why you would need to do what you're doing, so perhaps if you share the use case I can offer a little more help.但是,我看不出为什么您需要做您正在做的事情,所以也许如果您分享用例,我可以提供更多帮助。

If its just about detecting whether or not you're dealing with an Object , I could think of如果只是检测您是否正在处理Object ,我可以想到

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

However, this would probably fail for non-object primitive values.但是,对于非对象原始值,这可能会失败。 Actually there is nothing wrong with invoking .toString() to retreive the [[cclass]] property.实际上,调用.toString()来检索 [[cclass]] 属性并没有错。 You can even create a nice syntax like你甚至可以创建一个很好的语法,比如

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

and then use it like然后像这样使用它

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

It might not be the fastest operation but I don't think the performance leak there is too big.这可能不是最快的操作,但我不认为那里的性能泄漏太大。

underscore.js is using the following 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]';
  };

Hi I know this topic is old but there is a much better way to differentiate an Array in Node.js from any other Object have a look at the docs .嗨,我知道这个话题很旧,但是有更好的方法可以将 Node.js 中的数组与任何其他对象区分开来,请查看文档

var util = require('util');

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

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

I use typeof to determine if the variable I'm looking at is an object.我使用typeof来确定我正在查看的变量是否是一个对象。 If it is then I use instanceof to determine what kind it is如果是,那么我使用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

Just found a quick and simple solution to discover type of a variable.刚刚找到了一个快速简单的解决方案来发现变量的类型。

ES6 ES6

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

ES5 ES5

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

Examples:例子:

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编辑

Improvment to prevent 'undefined' and 'null' values:改进以防止“未定义”和“空”值:

ES6 ES6

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

ES5 ES5

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

If you know that a parameter will definitely be either an array or an object, it may be easier to check for an array compared to checking for an object with something like this.如果您知道参数肯定是数组或对象,那么检查数组可能比检查具有类似内容的对象更容易。

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

The Best Way I Can Use My Project.Use hasOwnProperty in Tricky Way!.我可以使用我的项目的最佳方式。以棘手的方式使用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)

I know it's been a while, but I thought i would update the answer since there are new (faster and simpler) ways to solve this problem.我知道已经有一段时间了,但我想我会更新答案,因为有新的(更快、更简单)的方法来解决这个问题。 Since ECMAscript 5.1 yo can use the isArray() method avaiable in the Array class.ECMAscript 5.1 开始,您可以使用Array类中可用的isArray()方法。

Yo can see it's documentation in MDN here .您可以在此处查看 MDN 中的文档。

I think you shouldn't have a compatibility problem nowadays, but just in case, if you add this to your code you should be always safe that Array.isArray() is polyfilled:我认为你现在不应该有兼容性问题,但以防万一,如果你将它添加到你的代码中,你应该始终确保Array.isArray()是多Array.isArray()

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

looking at jQuery they in there jQuery.isArray(...) they do:看看 jQuery 他们在那里jQuery.isArray(...)他们做:

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

this leads us to: jQuery.type :这导致我们: jQuery.type

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

and again we have to look in: class2type再次我们必须查看: 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();
});

and in native JS:在原生 JS 中:

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

this ends up with:这最终是:

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

I've used this function to solve:我用这个函数解决了:

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

Just for the record, lodash also has isObject(value) 只是为了记录, lodash也有isObject(值)

Making - Object.isObject()制作 - Object.isObject()

Object.prototype.isObject = function (param) {
   if(!param){return}
   return param.constructor === Object ?  true : false;
}

Calling - Object.isObject()调用 - Object.isObject()

Object.isObject({})                       // returns true
Object.isObject([])                       // returns false
Object.isObject("I am string")            // returns false

If you're sure that the variable you're checking will be either an object or an array, you could use the length property as well.如果您确定要检查的变量是对象或数组,则也可以使用length属性。

variable.length on an array will return an integer between 1 and n whereas variable.length on an object will return undefined . variable.length上的variable.length将返回 1 和n之间的整数,而对象上的variable.length将返回undefined

If you have other data types in the mix then you can add separate checks for those.如果混合中有其他数据类型,则可以为它们添加单独的检查。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM