Как эффективно проверить, является ли переменная Array или Object (в NodeJS & V8)? - PullRequest
40 голосов
/ 12 января 2012

Есть ли способ эффективно проверить, является ли переменная 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 ]

78 голосов
/ 17 мая 2013

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

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
22 голосов
/ 12 января 2012

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

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

20 голосов
/ 12 января 2012

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

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

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

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

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

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

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

14 голосов
/ 04 апреля 2012

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]';
  };
10 голосов
/ 12 января 2012

Я использую 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
9 голосов
/ 29 сентября 2013

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

var util = require('util');

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

var obj = {};
typeof obj === "Object" // true
3 голосов
/ 11 июля 2017

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

function myIsArray (arr) {
    return (arr.constructor === Array);
}
3 голосов
/ 23 августа 2016

Лучший способ использовать мой проект. Использовать 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 голосов
/ 04 апреля 2017

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

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

РЕДАКТИРОВАТЬ

Улучшение для предотвращения «неопределенных» и «нулевых» значений:

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());
}
1 голос
/ 27 апреля 2015

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

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