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