Учитывая развитие JavaScript
с момента создания языков, почему нет встроенного метода, который проверяет, является ли объект простым объектом?
Или действительно ли существует метод?
Учитывая развитие JavaScript
с момента создания языков, почему нет встроенного метода, который проверяет, является ли объект простым объектом?
Или действительно ли существует метод?
Не существует явного прямого способа проверить, является ли значение объектом, т.е. относится к типу объекта, но есть некоторые надежные способы сделать это. Я написал список в другом ответе, наиболее кратким кажется
function isObject(value) {
return Object(value) === value;
}
Подобная функция была запрошена несколько раз на esdiscuss. Например,
Юрий Зайцев "kangax" задается вопросом о правильном способе проверить, является ли значение объектом.
Фактически, Object.isObject
был предложен как соломенный, и он появился в раннем проекте ES6.
TC39 bashing: Обсуждение Object.isObject
в проекте ES6.
Насколько примитивны Символы? Bignums? и т.д.: обсуждает x === Object(x)
Object.isObject
Соломен был в конечном счете отклонен и удален из проекта ES6.
Совсем недавно,
Object.isObject
Теперь существует это предложение {tип} Методы, которое включает Object.isObject
среди множества других других проверок.
Таким образом, есть еще надежда, и в итоге у нас может быть что-то вроде этого.
Вышеупомянутое предназначено для тестирования объектов в целом. Если вы не хотите, чтобы вы определили, что для вас означает "простой объект".
Например, вы можете проверить свойство constructor
. Но любой объект может его настроить.
Вы можете использовать Object.prototype.toString
, чтобы получить устаревший ES5 [[Класс]]. Но любой объект может настроить это через Symbol.toStringTag
.
Вы можете проверить значение, возвращаемое [[GetPrototypeOf]]. Но даже экзотические объекты могут позволить их прототип быть изменен на любой произвольный объект или нуль. И объекты Proxy даже имеют полный контроль над этим внутренним методом.
Поэтому, скорее всего, вы не сможете положиться на эти тесты. И добавить что-то к стандарту может быть сложно, потому что разные люди могут хотеть разные вещи.
Что бы я хотел, это какой-то способ проверить, является ли объект обычным. То есть, он имеет поведение по умолчанию для основных внутренних методов, которые должны поддерживаться всеми объектами.
Как только вы узнаете, что объект обычный, вы можете полагаться на такие вещи, как [[GetPrototypeOf]], чтобы настроить тест на ваши вкусы.
Вы можете проверить тип и экземпляр объекта таким образом:
var a = new Date();
console.log(typeof a);
console.log(a instanceof Date);
var b = "Hello";
console.log(typeof b);
console.log(b instanceof Date);
Полагаясь на [object Object]
строковое представление неточно. Это поведение может быть изменено для любых объектов с помощью:
let o = { toString: () => '...' };
('' + o) !== '[object Object]'
var a = [];
a.toString = () => '[object Object]';
('' + a) === '[object Object]';
Самый надежный способ проверить, является ли значение простым объектом,
let o = {}
Object.getPrototypeOf(o) === Object.prototype
И учитывая, что свойство constructor
не было подделано, самый простой способ проверить, является ли значение простым объектом,
let o = {}
o.constructor === Object
Это охватывает все POJO, построенные из Object
, и не охватывает Object.create(null, { ... })
или любые дочерние классы (включая встроенные элементы типа RegExp
или Array
):
Object.create(null).constructor !== Object
[].constructor !== Object
(new class {}).constructor !== Object
Одна из возможных причин, по которым нет специального метода проверки на предметность объекта, заключается в том, что ограничение использования только объектов {}
нецелесообразно. Это имеет мало смысла в контексте JS. Это предотвращает использование экземпляров класса или относительно "простых" объектов (Object.create({}, ...)
).
Для этого потребуется взломать, чтобы нужные объекты, не имеющие равных объектов, прошли проверку:
Object.assign({}, (new class {})).constructor === Object
В большинстве случаев проверка объекта "все, что не запрещено, разрешено", принцип окупается (с особой осторожностью относительно печально известной null
несогласованности).
Применяя приведенное выше к этому случаю, безопасное и сжатое условие для фильтрации объектов без массива -
o && typeof o === 'object' && !Array.isArray(o)
И условие для фильтрации объектов, которые не являются встроенными (функции Array
, RegExp
и т.д.),
o && (o.constructor === Object || !/\[native code\]/.test(o.constructor))
Всякая JavaScript - это объект, поэтому нет необходимости иметь isObject api