为什么lodash的.isObject,.isPlainObject的行为与“typeof x ==='object'”不同?

时间:2015-12-05 22:54:39

标签: javascript lodash

请考虑以下事项:

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()

之间存在脱节
  

哪个checks if value is the language type of Object. (e.g. arrays, functions, objects, regexes, new Number(0), and new String(' ')

.isPlainObject()

  

哪个if value is a plain object, that is, an object created by the Object constructor or one with a Prototype of null

我们的好朋友typeof x === 'object'

我有三个问题:

  1. 是否有意识的设计决定使.isObject.isPlainObject的行为与本机.js类型检查的行为不同?
  2. 如果我的第一个问题是真的,那么设计决定是什么?这样做有什么好处?
  3. 是否存在与is*完全相同的原生(或typeof x === 'object'函数?
  4. 显然我可以继续使用typeof,但从语法上讲,在某些地方使用其中一个有点奇怪,例如.isObject的使用在检查{时会返回误报{1}}。当typeof x === 'object' && typeof x !== 'function'已经存在时,我并没有真正看到.isObject对函数返回true的任何好处。

3 个答案:

答案 0 :(得分:8)

typeof与某事物是否是一个无关。函数,字符串和{}具有不同的typeof,它们都是对象。函数当然是第一类对象,就像字符串是第一类对象一样,因此isObject必须为字符串和对象返回true。

对于记录,文档涵盖了这个:

  

检查value是否是Object的语言类型。 (例如数组,函数,对象,正则表达式,新数字(0)和新字符串(''))

哇!如果没有方便的isObject方法,那么真的需要进行大量测试。最公平的是将typeof作为object返回,但更高级别的方法,尤其是像lodash这样的库,是程序员可以忘记那些废话。

如果您关心typeof参数,请使用typeof。如果您关心不是函数的对象,您有几个选项:您可以使用typeof 特别检查字符串,或者您可以使用isObject && !isFunction。我更喜欢后者。后者确实恰好说出了你想传达的内容,所以编码是正确的。如果你认为当你说"对象"你隐含地不是指函数,那么你不认为函数是一流的对象,或者你希望你的代码更接近于它们不是的语言。但是,你不能责怪lodash是一个广泛使用函数是第一类对象的事实的库,这个函数是一种语言,其中函数是第一类对象更具表现力。

我认为这是你的大部分问题。我相信isPlainObject的用例是回答问题"这只是数据吗?"或"是这个代码?"所以创建为伪类(new的东西)的对象不算数。

答案 1 :(得分:7)

有时代码比言语更响亮。这是来自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 docs:

则IsObject

检查值是否为Object的language type。 (例如数组,函数,对象,正则表达式,新数字(0)和新字符串(''))

isPlainObject

检查value是否是普通对象,即Object构造函数创建的对象或[[Prototype]]为null的对象。

什么是对象?

在JavaScript中存在isObject函数本身就有点令人困惑,所以很多东西都像对象一样。关键思想是JavaScript中的某些值被视为原始值,而其他值则被视为完整的对象。字符串,数字和布尔值在内部级别的处理方式与使用对象文字或构造函数创建的对象的处理方式不同(这并不具有很大的实际意义,因为基元会在必要时自动将其自身转换为对象)。

typeof null === 'object'可能源于对象是引用类型并且通常从函数返回以代替对象这一事实。void * (一个怪癖可能会回到指针的概念和C和C ++中的NULLPTR。类型who_first <- function(n) { players <- seq_len(n) found_winner <- FALSE die_poss <- c(rep(c(0, 1), each = 3)) while (!found_winner) { cat("Rolling for players", paste(players, collapse = ", "), "\n") results <- replicate(length(players), sum(sample(die_poss, 4, replace=T))) cat("Players rolled", paste(results, collapse = ", "), "points\n") if (sum(max(results) == results) == 1) { found_winner <- TRUE winner <- players[which.max(results)] cat("Winner is player", winner, "\n") } else { players <- players[max(results) == results] } } invisible(winner) } 有很多值,但NULLPTR仍然被认为是指针类型的有效值。)

答案 2 :(得分:3)

  1. lodash docs将Lodash描述为“提供一致性,模块化,性能和附加功能的JavaScript实用程序库”。 isObjectisPlainObject将是额外的。它们是实用功能。我确信他们知道他们的类型不同,这就是为什么他们可能对某些人有用。他们可能认为原生typeof的性能,一致性和语法并不能保证.typeOf能够做同样的事情。
  2. 如上所述,其好处是它的功能与某些人可能很方便的类型略有不同。此外,lodash也关注更好的性能,虽然我不确定是否可以显着改善这种简单功能的性能。据说improve the performance of loops。您可以使用JSPerf测试性能差异,并告诉我们!至于为什么他们决定让.isObject为函数返回true是因为JS中的函数是对象。当本地typeof返回函数而不是对象时,它就是一种欺骗。由于typeof []不返回数组而是返回对象这一事实进一步令人费解,为什么它应该返回函数而不是函数上的对象。
  3. lodash或下划线似乎都没有与typeof相同的功能。下划线的_.isObject与lodash .isObject相同。您可以使用lodash的.isFunction.isObject来创建自己的typeof函数,该函数返回与typeof本机相同的内容。