Подтвердить что ты не робот

Почему lodash.isObject,.isPlainObject ведут себя иначе, чем "typeof x === 'object?"?

Рассмотрим следующее:

var o1 = {}
var O = function () {
  return this
}
var o2 = new O()
var o3 = function() {}
var o4 = [o1, o1]

var output = [
    [_.isObject(o1), _.isObject(o2), _.isObject(o3), _.isObject(o4)], 
    [_.isPlainObject(o1), _.isPlainObject(o2), _.isPlainObject(o3), _.isPlainObject(o4)],
    [typeof o1 === 'object', typeof o2 === 'object', typeof o3 === 'object', typeof o4 === 'object'],
    [o1 instanceof Array, o2 instanceof Array, o3 instanceof Array, o4 instanceof Array]
]

/* outputs:

[
    [true,true,true,true],
    [true,false,false,false],
    [true,true,false,true],
    [false,false,false,true]
]

*/

Очевидно, мы видим, что существует разрыв между .isObject():

Какой проверяет, является ли значение типом языка объекта. (например, массивы, функции, объекты, регулярные выражения, новое число (0) и новая строка ('')

.isPlainObject():

Какой если значение является простым объектом, то есть объектом, созданным конструктором Object, или с прототипом null

И наш добрый друг typeof x === 'object'.

У меня есть три вопроса:

  • Было ли сознательное дизайнерское решение сделать .isObject и .isPlainObject поведение иначе, чем проверка типа .js?
  • Если мой первый вопрос верен, каково было конструктивное решение и каковы преимущества его выполнения таким образом?
  • Есть ли какой-либо родной lodash ( или ) is* функция, которая ведет себя точно так же, как typeof x === 'object'?

Очевидно, я могу просто продолжать использовать typeof, но синтаксически немного странно использовать тот или иной в некоторых местах, например, использование .isObject будет возвращать ложные срабатывания при проверке на typeof x === 'object' && typeof x !== 'function'. Я действительно не вижу преимуществ .isObject, возвращающих true для функций, когда .isFunction уже существует.

4b9b3361

Ответ 1

typeof не имеет никакого отношения к тому, что-то является объектом. Функции, строки и {} имеют разные typeof, и все они являются объектами. Функции, конечно же, являются первоклассными объектами, точно так же, как строки являются первоклассными объектами, поэтому isObject должен возвращать true для строк и объектов.

Для записи документация охватывает следующее:

Проверяет, является ли значение типом языка объекта. (например, массивы, функции, объекты, регулярные выражения, новое число (0) и новая строка (''))

Ничего себе! это действительно много, чтобы протестировать, не имея удобного метода isObject. Чтобы быть справедливым, вернем typeof как object, но точка методов более высокого уровня, особенно в таких библиотеках, как lodash, так программист может забыть об этой ерунде.

Если вам нужен аргумент typeof, используйте typeof. Если вас интересуют объекты, которые не являются функциями, у вас есть пара вариантов: вы можете использовать typeof и проверять строки специально, или вы можете использовать isObject && !isFunction. Я бы предпочел последний. Последнее действительно говорит точно, что вы пытаетесь передать, поэтому на самом деле это правильная вещь для кодирования. Если вы думаете, что когда вы говорите "объект", что вы неявно не имеете в виду функции, то вы не считаете, что функции являются первоклассными объектами, или, скорее, вы хотели бы, чтобы ваш код более напоминал язык, на котором они нет. Но тогда вы не можете обвинять lodash за то, что являетесь библиотекой, которая широко использует тот факт, что функции являются первоклассными объектами для создания языка, функции которого являются первоклассными объектами более выразительными.

Я считаю, что это была основная часть вашего вопроса. Я считаю, что прецедент для isPlainObject заключается в ответе на вопрос: "Это только данные?" или "это этот код?" поэтому объекты, созданные как псевдоклассы (new чего-либо), не учитываются.

Ответ 2

Иногда код говорит громче слов. Здесь источник от lodash:

function isObject(value) {
  var type = typeof value;
  return !!value && (type == 'object' || type == 'function');
}
function isPlainObject(value) {
  var Ctor;
  if (!(isObjectLike(value) && objToString.call(value) == objectTag && !isHostObject(value) && !isArguments(value)) ||
      (!hasOwnProperty.call(value, 'constructor') && (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) {
    return false;
  }
  var result;
  if (lodash.support.ownLast) {
    baseForIn(value, function(subValue, key, object) {
      result = hasOwnProperty.call(object, key);
      return false;
    });
    return result !== false;
  }
  baseForIn(value, function(subValue, key) {
    result = key;
  });
  return result === undefined || hasOwnProperty.call(value, result);
}

В соответствии с документами lodash:

IsObject

Проверяет, является ли значение типом языка объекта. (например, массивы, функции, объекты, регулярные выражения, новое число (0) и новая строка (''))

isPlainObject

Проверяет, является ли значение равным объектом, то есть объектом, созданным конструктором Object, или объектом с [[Prototype]] нулевого значения.

Что такое объект?

Возможно, существование функции isObject по своей сути немного запутанно, когда в JavaScript так много вещей действует как объекты. Основная идея заключается в том, что некоторые значения в JavaScript считаются примитивами, а другие - полномасштабными. Строки, числа и логические типы обрабатываются по-разному на внутреннем уровне, чем объекты, созданные с помощью объектных литералов или конструкторских функций (это не имеет большого практического значения, потому что при необходимости при необходимости автоматически приступают к объектам).

Тот факт, что typeof null === 'object', вероятно, исходит из того факта, что объекты являются ссылочными типами, а null часто возвращается из функций вместо объекта. (Причуда, которая, вероятно, вернется к понятию указателей и NULLPTR в C и С++. Тип void * имеет много значений, но NULLPTR по-прежнему считается допустимым значением для типа указателя.)

Ответ 3

  • lodash docs описывает Lodash как "библиотеку утилиты JavaScript, обеспечивающую согласованность, модульность, производительность и дополнительные функции". isObject и isPlainObject будут лишними. Это служебные функции. Я уверен, что они знали, что они разные, чем тип, поэтому они могут быть полезны для некоторых людей. Вероятно, они считали, что производительность, согласованность и синтаксис родного typeof не гарантируют, что создание .typeOf делает то же самое.
  • Как упоминалось выше, преимущества заключаются в том, что он функционирует несколько иначе, чем тип, который может быть полезен некоторым людям. Кроме того, lodash также фокусируется на лучшей производительности, хотя я не уверен, что производительность такой простой функции может быть значительно улучшена. Говорят, что улучшает производительность циклов. Вы можете протестировать разницу в производительности, используя JSPerf и сообщите нам об этом! Что касается того, почему они решили вернуть .isObject true для функций, это потому, что функции в JS являются объектами. Это своего рода обман, когда native typeof возвращает функцию, а не объект. Это еще более запутан тем, что typeof [] не возвращает массив и вместо этого возвращает объект, поэтому зачем ему возвращать функцию, а не объект в функцию.
  • Ни lodash, ни подчеркивание не имеют функции, которая совпадает с typeof. Подчеркивание имеет _.isObject, что совпадает с lodash .isObject. Вы можете использовать lodash .isFunction и .isObject для создания собственной функции typeof, которая возвращает ту же самую нативную typeof.