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

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

Я пишу модель для MongoDB и NodeJS, и для перемещения по дереву объектов мне нужно знать, является ли объект простым (Number, String,...) или составным (Hash, Array).

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

Обычно это может быть сделано следующим образом:

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

или это:

object === Object(object)

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

Ответы

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

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

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

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

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

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

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

Ответ 4

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

Ответ 5

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

Ответ 6

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

var util = require('util');

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

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

Ответ 7

Лучший способ использовать мой проект. Используйте hasOwnProperty в Tricky Way!.

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)

Ответ 8

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

Ответ 9

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

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

Ответ 10

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

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

ИЗМЕНИТЬ

Усовершенствование для предотвращения "undefined" и "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());
}

Ответ 11

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

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

Ответ 12

я нашел простую функцию, подобную этой.

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

Ответ 13

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

Yo может видеть документацию в MDN здесь.

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

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