plainObject

plainObject:纯粹的对象,具体来说就是该对象是通过 “{}” 或 “new Object()” 来创建的,该对象有零个或一个以上的键值对。

之所以要判断出来主要是因为区别于 null、数组、宿主对象(document)等。

先来看 jq 的效果。

  1. function Person(name) {
  2. this.name = name;
  3. }
  4. console.log($.isPlainObject({})); // true
  5. console.log($.isPlainObject(new Object())); // true
  6. console.log($.isPlainObject(Object.create(null))); // true
  7. console.log($.isPlainObject(Object.assign({ a: 1 }, { b: 2 }))); // true
  8. console.log($.isPlainObject(new Person("yayu"))); // false
  9. console.log($.isPlainObject(Object.create({}))); // false

除了 {} 和 new Object 创建的之外,jq 认为一个没有原型的对象也是一个纯粹的对象。

实现一下。

  1. const toString = Object.toString.toString;
  2. const hasOwn = Object.prototype.hasOwnProperty;
  3. function isPlainObject(obj) {
  4. const proto, Ctor;
  5. // 排除掉明显不是obj的以及一些宿主对象如Window
  6. // toString.call(window) // [object, Window]
  7. if (!obj || toString.call(obj) !== "[object Object]") {
  8. return false;
  9. }
  10. /**
  11. * getPrototypeOf es5 方法,获取 obj 的原型
  12. * 以 new Object 创建的对象为例的话
  13. * obj.__proto__ === Object.prototype
  14. */
  15. proto = Object.getPrototypeOf(obj);
  16. // 没有原型的对象是纯粹的,Object.create(null) 就在这里返回 true
  17. if (!proto) {
  18. return true;
  19. }
  20. /**
  21. * 以下判断通过 new Object 方式创建的对象
  22. * 判断 proto 是否有 constructor 属性,如果有就让 Ctor 的值为 proto.constructor
  23. * 如果是 Object 函数创建的对象,Ctor 在这里就等于 Object 构造函数
  24. */
  25. Ctor = hasOwn.call(proto, "constructor") && proto.constructor;
  26. // 在这里判断 Ctor 构造函数是不是 Object 构造函数,用于区分自定义构造函数和 Object 构造函数
  27. // 注意这里的 toString 是 Function.prototype.toString()
  28. // 返回的是一个函数的字符串的形式
  29. return typeof Ctor === "function" && hasOwn.toString.call(Ctor) === hasOwn.toString.call(Object);
  30. }

EmptyObject

很简单,利用 for in 循环判断有没有属性。

  1. function isEmptyObject(obj) {
  2. var name;
  3. for (name in obj) {
  4. return false;
  5. }
  6. return true;
  7. }

Window 对象

也很简单,利用 Window 对象有一个 Window 属性指向自身。

  1. function isWindow( obj ) {
  2. return obj != null && obj === obj.window;
  3. }

isElement

很简单,直接看代码。

  1. isElement = function(obj) {
  2. return !!(obj && obj.nodeType === 1);
  3. };

isArrayLike

规定数组和类数组都返回 true。

也很简单,直接看代码。

  1. function isArrayLike(obj) {
  2. // obj 必须有 length属性
  3. var length = !!obj && "length" in obj && obj.length;
  4. var typeRes = type(obj);
  5. // 排除掉函数和 Window 对象
  6. if (typeRes === "function" || isWindow(obj)) {
  7. return false;
  8. }
  9. return typeRes === "array" || length === 0 ||
  10. typeof length === "number" && length > 0 && (length - 1) in obj;
  11. }

根据上面的代码的最后一个 return 我们知道要返回 true 至少满足任一以下条件:

  • 是数组
  • 长度为 0
  • length 属性是大于 0 的数字类型,并且 obj[length - 1] 必须存在。

第一个条件不用说了,直接看第二个。

先来写个例子

  1. function a() {
  2. console.log(isArrayLike(arguments));
  3. }
  4. a(); // true

我们都知道 arguments 对象是类数组对象,所以长度为 0 是为了兼容 arguments。

第三个条件,必须最后一个元素存在。

因为如果最后一个元素不存在的话,length 的值就不对了(不是最后一个元素的 key 值加 1)。

参考:
[1] Javascript 专题之类型判断(下)