javascript 为什么 lodash 的 .isObject, .isPlainObject 的行为与“typeof x === 'object'”不同?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34111902/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why do lodash's .isObject, .isPlainObject behave differently than "typeof x === 'object'"?
提问by brandonscript
Consider the following:
考虑以下:
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]
]
*/
Clearly we can see that there is a disconnect between .isObject()
:
很明显,我们可以看到以下之间存在脱节.isObject()
:
它检查 value 是否是 Object 的语言类型。(例如数组、函数、对象、正则表达式、new Number(0) 和 new String(' ')
.isPlainObject()
:
.isPlainObject()
:
其中if value 是一个普通对象,即由 Object 构造函数创建的对象或 Prototype 为 null 的对象
And our good ol' trusty friend typeof x === 'object'
.
还有我们可信赖的好朋友typeof x === 'object'
。
I have three questions:
我有三个问题:
- Was there a conscious design decision to make
.isObject
and.isPlainObject
behave differently than the native .js type checking? - If my first question is true, what was the design decision and what are the benefits of doing it this way?
- Is there any native lodash(or underscore.js)
is*
function that behaves exactly the same astypeof x === 'object'
?
- 是否有一个有意识的设计决策来做出
.isObject
与.isPlainObject
原生 .js 类型检查不同的行为? - 如果我的第一个问题是真的,那么设计决策是什么,这样做有什么好处?
- 是否有任何本机lodash(或underscore.js)
is*
函数的行为与typeof x === 'object'
?
Obviously I can just continue to use typeof
, but syntactically it's a bit weird to use one or the other in some places, for example the usage of .isObject
will return false positives when checking for typeof x === 'object' && typeof x !== 'function'
. I don't really see any benefit of .isObject
returning true for functions when .isFunction
already exists.
显然我可以继续使用typeof
,但在语法上在某些地方使用一个或另一个有点奇怪,例如.isObject
在检查typeof x === 'object' && typeof x !== 'function'
. 我真的没有看到.isObject
为.isFunction
已经存在的函数返回 true 的任何好处。
采纳答案by djechlin
typeof
has nothing to do with whether something is an object. Functions, strings, and {}
have different typeof
and they are all objects. Functions are of course first-class objects, just like strings are first-class objects, therefore isObject
must return true for strings and objects.
typeof
与某物是否为对象无关。函数、字符串和{}
有不同的typeof
,它们都是对象。函数当然是一等对象,就像字符串是一等对象一样,因此isObject
对于字符串和对象必须返回true。
For the record the documentation covers this:
作为记录,文档涵盖了以下内容:
Checks if value is the language type of Object. (e.g. arrays, functions, objects, regexes, new Number(0), and new String(''))
检查 value 是否为 Object 的语言类型。(例如数组、函数、对象、正则表达式、new Number(0) 和 new String(''))
Wow! that really is a lot to test for without having a handy isObject
method. To be fair most return typeof
as object
, but the point of higher level methods, especially in libraries like lodash, is so the programmer can forget about that nonsense.
哇!如果没有一个方便的isObject
方法,这真的是很多要测试的。公平地说,大多数返回typeof
as object
,但更高级的方法的重点,尤其是在像 lodash 这样的库中,程序员可以忘记那些废话。
If you care about the typeof
an argument, then use typeof
. If you care about objects that are not functions, you have a couple options: you can use typeof
andcheck strings specially, or you can use isObject && !isFunction
. I would prefer the latter. The latter does happen to say exactly what you are trying to convey so it really is the correct thing to code. If you think when you say "object" that you implicitly don't mean functions, then you do not think functions are first-class objects, or rather you would like your code to more closely resemble a language in which they're not. But then you can't blame lodash for being a library that extensively uses the fact that functions are first-class objects to make a language in which functions are first-class objects more expressive.
如果您关心typeof
an 参数,请使用typeof
. 如果您关心不是函数的对象,您有几个选择:您可以专门使用typeof
和检查字符串,或者您可以使用isObject && !isFunction
. 我更喜欢后者。后者确实恰好说明了您想要传达的内容,因此它确实是编码的正确内容。如果您认为当您说“对象”时隐含地不是指函数,那么您并不认为函数是一流的对象,或者您希望您的代码更接近于一种语言,而它们不是。但是你不能责怪 lodash 是一个广泛使用函数是一流对象这一事实的库,使函数是一流对象的语言更具表现力。
I believe that was the bulk of your question. I believe the use case for isPlainObject
is to answer the question "is this just data?" or "is this code?" so objects created as pseudo-classes (new
of something) don't count.
我相信这是你的大部分问题。我相信用例isPlainObject
是回答“这只是数据吗?”的问题。或“这是代码吗?” 所以创建为伪类(new
某物)的对象不计算在内。
回答by Ethan Lynn
Sometimes code speaks louder than words. Here's the source from lodash:
有时代码胜于雄辩。这是来自 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);
}
According to the lodash docs:
根据 lodash 文档:
isObject
对象
Checks if value is the language typeof Object. (e.g. arrays, functions, objects, regexes, new Number(0), and new String(''))
检查 value 是否为 Object的语言类型。(例如数组、函数、对象、正则表达式、new Number(0) 和 new String(''))
isPlainObject
是普通对象
Checks if value is a plain object, that is, an object created by the Object constructor or one with a [[Prototype]] of null.
检查 value 是否为普通对象,即由 Object 构造函数创建的对象或 [[Prototype]] 为 null 的对象。
What is an object?
什么是对象?
Perhaps the existence of an isObject
function is inherently a bit confusing when in JavaScript so many things act like objects. The key idea is that some values in JavaScript are considered primitives and others considered full-blown objects. Strings, numbers, and booleans are treated differently at an internal level than objects created with the object literal or constructor functions (this doesn't end up have much practical significance because primitives will automatically cast themselves to objects when necessary).
也许isObject
函数的存在本质上有点令人困惑,因为在 JavaScript 中,很多东西都像对象一样。关键思想是 JavaScript 中的某些值被认为是原始值,而其他值被认为是成熟的对象。字符串、数字和布尔值在内部级别的处理方式与使用对象字面量或构造函数创建的对象不同(这最终没有太大的实际意义,因为基元会在必要时自动将自己强制转换为对象)。
The fact that typeof null === 'object'
probably originates from the fact that objects are reference types and null is often returned from functions in lieu of an object. (A quirk which likely hearkens back to the concept of pointers and the NULLPTR in C and C++. The type void *
has many values but the NULLPTR is still considered a valid value for the pointer type.)
这一事实typeof null === 'object'
可能源于这样一个事实,即对象是引用类型,而 null 通常从函数返回,而不是从对象中返回。(一个怪癖可能会让人回想起 C 和 C++ 中指针和 NULLPTR 的概念。该类型void *
有很多值,但 NULLPTR 仍然被认为是指针类型的有效值。)
回答by Daniel Kobe
- The lodash docsdescribes Lodash as "a JavaScript utility library delivering consistency, modularity, performance, & extras."
isObject
andisPlainObject
would be an extra. They are utility functions. I'm sure they were aware that they are different then typeof which is why they may be useful to some people. They probably thought the performance, consistency, and syntax of the nativetypeof
didn't warrant the making of.typeOf
that does the same thing. - As mentioned above, the benefits are that it functions a little differently than typeof which may be handy to some people. Also lodash focuses on better performance as well, although I'm not sure if there performance of such a simple function could be significantly improved. It is said to improve the performance of loopsthough. You can test the performance difference using JSPerfand let us know! As far as why they decided to have
.isObject
return true for functions is because functions in JS are objects. It is kind of deceiving when nativetypeof
returns function and not object. It is further convoluted by the fact thattypeof []
doesnt return array and instead returns object so why should it return function and not object on a function. - Neither lodash or underscore appear to have a function that is the same as
typeof
. Underscore has_.isObject
which is the same as the lodash.isObject
. You could use lodash's.isFunction
and.isObject
to create your own typeof function that returns the same thing nativetypeof
would.
- lodash文档将 Lodash 描述为“一个提供一致性、模块化、性能和附加功能的 JavaScript 实用程序库”。
isObject
并且isPlainObject
将是额外的。它们是效用函数。我敢肯定他们知道它们与 typeof 不同,这就是为什么它们可能对某些人有用。他们可能认为原生的性能、一致性和语法typeof
并不能保证.typeOf
它做同样的事情。 - 如上所述,好处是它的功能与 typeof 有点不同,后者可能对某些人来说很方便。lodash 也专注于更好的性能,尽管我不确定这样一个简单函数的性能是否可以显着提高。据说它可以提高循环的性能。您可以使用JSPerf测试性能差异并告诉我们!至于为什么他们决定
.isObject
为函数返回 true 是因为 JS 中的函数是对象。当本机typeof
返回函数而不是对象时,这是一种欺骗。typeof []
不返回数组而是返回对象的事实进一步令人费解,那么为什么它应该返回函数而不是函数上的对象。 - lodash 或下划线似乎都没有与
typeof
. 下划线_.isObject
与 lodash 相同.isObject
。您可以使用 lodash's.isFunction
and.isObject
创建自己的 typeof 函数,该函数返回与本机相同的内容typeof
。