Как эффективно проверить, является ли переменная массивом или объектом (в NodeJS & V8)?

есть ли способ эффективно проверить, является ли переменная объектом или массивом в NodeJS & V8?

Я пишу модель для MongoDB и NodeJS, и чтобы пересечь дерево объектов, мне нужно знать, прост ли объект (номер, строка,...) или композитный (хэш, массив).

кажется, что V8 имеет быстрый встроенный Array.isArray, но как проверить, является ли объект объектом? Я имею в виду сложный объект, такой как hash {} или экземпляр класса, а не что-то вроде new String()?

как правило, это может быть сделано, как это:

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

или такой:

object === Object(object)

но кажется, что эти операции не дешевы, может быть, есть некоторые более эффективные? Это нормально, если он не универсален и не работает на всех двигателях, мне нужно только работать на V8.

14 ответов


все объекты являются экземплярами хотя бы одного класса – Object – в ECMAScript. Вы можете различать только экземпляры встроенных классов и обычных объектов с помощью Object#toString. Все они имеют одинаковый уровень сложности, например, создаются ли они с помощью {} или new оператора.

Object.prototype.toString.call(object) лучше всего различать обычные объекты и экземпляры других встроенных классов, как object === Object(object) здесь не работает. Однако я не вижу причины. почему вам нужно делать то, что вы делаете, поэтому, возможно, если вы поделитесь прецедентом, я могу предложить немного больше помощи.


для просто проверки против объекта или массива без дополнительного вызова функции (скорости).

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

если это просто об обнаружении того, имеете ли вы дело с Object, я мог бы подумать о

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

однако это, вероятно, не удастся для примитивных значений без объектов. На самом деле нет ничего плохого в вызове .toString() для восстановления свойства [[cclass]]. Вы даже можете создать хороший синтаксис, такой как

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

и затем использовать его как

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

Это может быть не самая быстрая операция, но я не думаю, что утечка есть тоже большой.


подчеркивания.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]';
  };

Я использую 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

Привет я знаю, что эта тема старая, но есть гораздо лучший способ отличить массив в узел.js из любого другого объекта посмотрите на docs.

var util = require('util');

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

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

Лучший Способ Использовать Мой Проект.Использовать 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)

глядя на 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]";
}

я использовал эту функцию для решения:

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

просто нашел быстрое и простое решение для обнаружения типа переменной.

ЕС6

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

редактировать

Improvment для предотвращения значений "undefined" и "null":

ЕС6

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

Если вы знаете, что параметр определенно будет либо массивом, либо объектом, может быть проще проверить массив по сравнению с проверкой объекта с чем-то вроде этого.

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

Я нашел такую простую функцию.

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

Я знаю, что прошло некоторое время, но я думал, что обновлю ответ, так как есть новые (более быстрые и простые) способы решения этой проблемы. С ECMAscript 5.1 вы можете использовать isArray() метод доступен в Array класса.

Yo может видеть, что это документация в MDN здесь.

Я думаю, что у вас не должно быть проблемы совместимости в настоящее время, но на всякий случай, если вы добавите это в свой код, вы всегда должны быть в безопасности, что Array.isArray() is polyfilled:

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

просто для протокола, lodash также isObject(значение)