-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JavaScript专题之类型判断(下) #30
Comments
这样是不是也可以判断是否是空对象呢? function isEmptyObject(obj) {
return !!obj ? (Object.keys(obj).length === 0) : true;
} |
@F-happy 也可以呀,不过两者稍微有一点区别,文章中的方法用的是 for in ,而这种方法用的是 Object.keys 两者的主要区别在于 for in 还会遍历原型上的属性,这也就意味着: function Person(){}
Person.prototype.name = "111"
var person = new Person();
console.log(isEmptyObject(person)) 如果用文中的方法就会是 false,用这种方法结果就会是 true,无所谓对错,看设计者想设计成什么样哈。 除此之外, Object.keys 是一个 ES5 的方法哈~ |
@NewNewKing 非常感谢指出~ 确实是写错了 |
有一个地方有点疑惑, |
@foxpsd 出于兼容性的考虑,使用 toString 打印的结果在各个浏览器还不一样: |
@mqyqingfeng 原来如此···· |
@foxpsd 出自 jQuery 的源码 |
看来要花些时间去多看源码,楼主对于看源码有没有心历过程呀? |
@xiaobinwu 心历过程?先挑个简单的看,然后搜索看有没有人写过这个东西的源码解析或者精简版的实现,然后边看源码边看文章,不知道算不算…… |
@mqyqingfeng 判断isPlainObject那个方法的最后一句
是否可以写成
|
@sarazhang123 可以的,如果非要说两种方法有什么区别的话,可能是前者速度会更快些…… |
isElement里面为什么多加一个判断obj是否存在呢? 直接obj.nodeType === 1不可以么? |
@zhangruinian 举个例子: var isElement = function(obj) {
return !!(obj.nodeType === 1);
};
console.log(isElement()) // 报错
console.log(isElement(a)) // 报错
console.log(isElement(undefined)) // 报错 |
你好我想问问isWindow的判断原理是判断传入的对象是否有window属性,如果我创造一个对象, |
function isWindow( obj ) {
return obj != null && obj === obj.window;
} 应该是创造一个对象,将这个对象的 window 属性指向自己 如果要刻意创造这样一个对象,这也没有办法呀~ |
isElement里!!(obj && obj.nodeType === 1)为什么不能直接写成obj && obj.nodeType === 1 |
@magentaqin isElement 函数用来判断元素是否是 Element,结果只有两种,true 或者 false。 举个例子: var isElement = function(obj) {
return !!(obj && obj.nodeType === 1);
};
var a;
isElement(a) 如果 obj 不存在的话,直接写就变成了返回 undefined |
因为 || 和 && 的返回值实际上不是布尔值,而是返回比较中的两个值中的一个,用 !! 是做强制类型转换,将值转换为布尔值。 |
看来两遍只能说看懂了代码想表达什么,要我自己写的话肯定会懵逼。 |
嗯,也就是说保证返回值是布尔值。只是实际开发的时候if表达式求值后也是布尔值,所以也就没这样写了。
2017-12-12 15:26 GMT+08:00 zjp6049 <notifications@github.com>:
… 看来两遍只能说看懂了代码想表达什么,要我自己写的话肯定会懵逼。
还有~~为什么没有直接点下一篇的链接啊哈哈哈
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#30 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/Ac9pr7BROcoqIWw7MUfZi9cR43eKsWH8ks5s_iq3gaJpZM4ONymz>
.
|
数组最后一个元素要有值这个好像吐槽了好久的一个梗. |
@ClarenceC 这个梗不知道哎~😂 |
其实我觉得这段代码是有问题的: var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
var isArrayLike = function(collection) {
var length = getLength(collection);
return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};
function isArrayLike(o) {
if (o && // o is not null, undefined, etc
// o is an object
typeof o === "object" &&
// o.length is a finite number
isFinite(o.length) &&
// o.length is non-negative
o.length >= 0 &&
// o.length is an integer
o.length === Math.floor(o.length) &&
// o.length < 2^32
o.length < 4294967296) //数组的上限值
return true;
else
return false;
} |
意思是这种就不算类数组对象吗。 |
@tr2v 没有要求,看 API 设计者想设计成什么样 |
@tr2v 你要是写一个 API,将这种类型也算为类数组对象,也可以的,重点还是说在实际开发中对于类数组对象的处理是否符合业务需求,比如写业务中就是会出现这种对象,而我又需要跟数组一样处理,那它就是被允许的 |
// obj 必须有 length属性 |
首先要理解 所以假定 var length = !!obj // 此时 length === false
var length = obj // 此时 length === 0 |
判断是否为windowfunction isWindow( obj ) {
return obj != null && obj === obj.window;
}
let fakeWindow = {}
fakeWindow.window = fakeWindow
isWindow(fakeWindow) // true 为什么不用这种方法,是存在什么缺陷吗?function isWindow(obj) {
return !!(window && obj === window)
} @mqyqingfeng 请楼主解惑 |
针对
因为如果这里忽略这个问题,我看了后面的
用 |
推荐chrome的插件 Octotree 😄 |
window.a = 1; |
那最后一句是否可以写成
|
为什么前者Ctor是函数类型,本可以Ctor.toString,却非要调用call来调用? |
空对象判断,isEmptyObject(100)也会返回true,这个合理吗 |
我觉得应该是在node环境下,window没有定义的话,会报错的 |
Array.isArray函数个人感觉这么写更好些: const MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; //避免内存溢出
function isArrayLike(obj) {
if (isWindow(obj) || type(obj) === "function") {
return false;
}
const length =
!!obj &&
typeof obj.length === "number" &&
obj.length >= 0 &&
obj.length <= MAX_ARRAY_INDEX &&
obj.length;
if (isElement(obj) && length) {
return true;
}
return (
Array.isArray(obj) || length === 0 || (length > 0 && length - 1 in obj)
);
} |
!obj || toString.call(obj) !== "[object Object]" 中!obj可以不用判断吧,toString 就能判断吧 |
typeof Ctor === "function" && hasOwn.toString.call(Ctor) === hasOwn.toString.call(Object);可以直接判断构造函数和Object吗
|
Object.keys 拿不到原型链上的属性吧 |
同问,直接判等是不是有没有什么说法呢 |
/** |
前言
在上篇《JavaScript专题之类型判断(上)》中,我们抄袭 jQuery 写了一个 type 函数,可以检测出常见的数据类型,然而在开发中还有更加复杂的判断,比如 plainObject、空对象、Window 对象等,这一篇就让我们接着抄袭 jQuery 去看一下这些类型的判断。
plainObject
plainObject 来自于 jQuery,可以翻译成纯粹的对象,所谓"纯粹的对象",就是该对象是通过 "{}" 或 "new Object" 创建的,该对象含有零个或者多个键值对。
之所以要判断是不是 plainObject,是为了跟其他的 JavaScript对象如 null,数组,宿主对象(documents)等作区分,因为这些用 typeof 都会返回object。
jQuery提供了 isPlainObject 方法进行判断,先让我们看看使用的效果:
由此我们可以看到,除了 {} 和 new Object 创建的之外,jQuery 认为一个没有原型的对象也是一个纯粹的对象。
实际上随着 jQuery 版本的提升,isPlainObject 的实现也在变化,我们今天讲的是 3.0 版本下的 isPlainObject,我们直接看源码:
注意:我们判断 Ctor 构造函数是不是 Object 构造函数,用的是 hasOwn.toString.call(Ctor),这个方法可不是 Object.prototype.toString,不信我们在函数里加上下面这两句话:
发现返回的值并不一样,这是因为 hasOwn.toString 调用的其实是 Function.prototype.toString,毕竟 hasOwnProperty 可是一个函数!
而且 Function 对象覆盖了从 Object 继承来的 Object.prototype.toString 方法。函数的 toString 方法会返回一个表示函数源代码的字符串。具体来说,包括 function关键字,形参列表,大括号,以及函数体中的内容。
EmptyObject
jQuery提供了 isEmptyObject 方法来判断是否是空对象,代码简单,我们直接看源码:
其实所谓的 isEmptyObject 就是判断是否有属性,for 循环一旦执行,就说明有属性,有属性就会返回 false。
但是根据这个源码我们可以看出isEmptyObject实际上判断的并不仅仅是空对象。
举个栗子:
以上都会返回 true。
但是既然 jQuery 是这样写,可能是因为考虑到实际开发中 isEmptyObject 用来判断 {} 和 {a: 1} 是足够的吧。如果真的是只判断 {},完全可以结合上篇写的 type 函数筛选掉不适合的情况。
Window对象
Window 对象作为客户端 JavaScript 的全局对象,它有一个 window 属性指向自身,这点在《JavaScript深入之变量对象》中讲到过。我们可以利用这个特性判断是否是 Window 对象。
isArrayLike
isArrayLike,看名字可能会让我们觉得这是判断类数组对象的,其实不仅仅是这样,jQuery 实现的 isArrayLike,数组和类数组都会返回 true。
因为源码比较简单,我们直接看源码:
重点分析 return 这一行,使用了或语句,只要一个为 true,结果就返回 true。
所以如果 isArrayLike 返回true,至少要满足三个条件之一:
第一个就不说了,看第二个,为什么长度为 0 就可以直接判断为 true 呢?
那我们写个对象:
isArrayLike 函数就会返回 true,那这个合理吗?
回答合不合理之前,我们先看一个例子:
如果我们去掉length === 0 这个判断,就会打印 false,然而我们都知道 arguments 是一个类数组对象,这里是应该返回 true 的。
所以是不是为了放过空的 arguments 时也放过了一些存在争议的对象呢?
第三个条件:length 是数字,并且 length > 0 且最后一个元素存在。
为什么仅仅要求最后一个元素存在呢?
让我们先想下数组是不是可以这样写:
当我们写一个对应的类数组对象就是:
也就是说当我们在数组中用逗号直接跳过的时候,我们认为该元素是不存在的,类数组对象中也就不用写这个元素,但是最后一个元素是一定要写的,要不然 length 的长度就不会是最后一个元素的 key 值加 1。比如数组可以这样写
但是类数组对象就只能写成:
所以符合条件的类数组对象是一定存在最后一个元素的!
这就是满足 isArrayLike 的三个条件,其实除了 jQuery 之外,很多库都有对 isArrayLike 的实现,比如 underscore:
isElement
isElement 判断是不是 DOM 元素。
结语
这一篇我们介绍了 jQuery 的 isPlainObject、isEmptyObject、isWindow、isArrayLike、以及 underscore 的 isElement 实现。我们可以看到,即使是 jQuery 这样优秀的库,一些方法的实现也并不是非常完美和严密的,但是最后为什么这么做,其实也是一种权衡,权衡所失与所得,正如玉伯在《从 JavaScript 数组去重谈性能优化》中讲到:
所有这些点,都必须脚踏实地在具体应用场景下去分析、去选择,要让场景说话。
专题系列
JavaScript专题系列目录地址:https://github.com/mqyqingfeng/Blog。
JavaScript专题系列预计写二十篇左右,主要研究日常开发中一些功能点的实现,比如防抖、节流、去重、类型判断、拷贝、最值、扁平、柯里、递归、乱序、排序等,特点是研(chao)究(xi) underscore 和 jQuery 的实现方式。
如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎 star,对作者也是一种鼓励。
The text was updated successfully, but these errors were encountered: