Lodash源码阅读-isEmpty

功能概述

能判断各种各样的数据类型是不是"空的"。不管你给它数组、对象、Map、Set,还是字符串,它都能准确告诉你是不是空的。而且实现方式很巧妙,针对不同类型的数据采用不同的判断策略。

源码实现

js 复制代码
function isEmpty(value) {
  if (value == null) {
    return true;
  }
  if (
    isArrayLike(value) &&
    (isArray(value) ||
      typeof value == "string" ||
      typeof value.splice == "function" ||
      isBuffer(value) ||
      isTypedArray(value) ||
      isArguments(value))
  ) {
    return !value.length;
  }
  var tag = getTag(value);
  if (tag == mapTag || tag == setTag) {
    return !value.size;
  }
  if (isPrototype(value)) {
    return !baseKeys(value).length;
  }
  for (var key in value) {
    if (hasOwnProperty.call(value, key)) {
      return false;
    }
  }
  return true;
}

实现原理解析

整体思路概述

这个函数的实现思路非常清晰,就像走一个决策树:

  1. 先处理最简单的 null/undefined 情况
  2. 然后判断是不是数组类型的(包括数组、字符串、类数组等)
  3. 接着看看是不是 Map/Set 类型
  4. 再检查是不是原型对象
  5. 最后处理普通对象的情况

每一步都针对特定类型采用最合适的判空方式,下面我们来详细看看每种情况。

1. null/undefined 判断

js 复制代码
if (value == null) {
  return true;
}

这是最基础的判断,用双等号(==)来同时处理 null 和 undefined:

js 复制代码
console.log(isEmpty(null)); // true
console.log(isEmpty(undefined)); // true

// 但其他假值不一定是空的
console.log(isEmpty(0)); // false
console.log(isEmpty(false)); // false

2. 数组类型判断

js 复制代码
if (
  isArrayLike(value) &&
  (isArray(value) ||
    typeof value == "string" ||
    typeof value.splice == "function" ||
    isBuffer(value) ||
    isTypedArray(value) ||
    isArguments(value))
) {
  return !value.length;
}

这段代码处理所有有 length 属性的类型,包括:

js 复制代码
// 数组
console.log(isEmpty([])); // true
console.log(isEmpty([1, 2])); // false

// 字符串
console.log(isEmpty("")); // true
console.log(isEmpty("hello")); // false

// 类数组对象
function foo() {
  console.log(isEmpty(arguments)); // true
}
foo();

// 类型化数组
console.log(isEmpty(new Int8Array())); // true
console.log(isEmpty(new Int8Array(2))); // false

3. Map/Set 类型判断

js 复制代码
var tag = getTag(value);
if (tag == mapTag || tag == setTag) {
  return !value.size;
}

对于 Map 和 Set,我们看它们的 size 属性:

js 复制代码
// Map
const map = new Map();
console.log(isEmpty(map)); // true
map.set("key", "value");
console.log(isEmpty(map)); // false

// Set
const set = new Set();
console.log(isEmpty(set)); // true
set.add(1);
console.log(isEmpty(set)); // false

4. 原型对象判断

js 复制代码
if (isPrototype(value)) {
  return !baseKeys(value).length;
}

处理原型对象的情况:

js 复制代码
// 创建一个构造函数
function Person() {}
Person.prototype.name = "John";

// 检查原型对象
console.log(isEmpty(Person.prototype)); // false

// 空的原型对象
function Empty() {}
console.log(isEmpty(Empty.prototype)); // true

5. 普通对象判断

js 复制代码
for (var key in value) {
  if (hasOwnProperty.call(value, key)) {
    return false;
  }
}
return true;

最后处理普通对象,看看有没有自己的可枚举属性:

js 复制代码
// 空对象
console.log(isEmpty({})); // true

// 有属性的对象
console.log(isEmpty({ name: "John" })); // false

// 只有不可枚举属性的对象
const obj = Object.defineProperty({}, "name", {
  value: "John",
  enumerable: false,
});
console.log(isEmpty(obj)); // true

总结

通过一系列的条件判断,优雅地处理了各种不同类型的空值判断。不同类型用不同的判空标准:length、size、自有属性等。而且代码结构清晰,判断逻辑层层递进。

相关推荐
GreenTea12 小时前
GrokBot 核心成员 Lauren Tan:每月交付 2000 个 PR 的人,是怎么用 AI 的
前端·后端·架构
mCell13 小时前
用 Knip 清理 AI Coding 留下的冗余代码
前端·ai编程·前端工程化
笃行35014 小时前
使用Rokid AIUI做了一个童年推箱子游戏
前端
excel15 小时前
前端加密的作用与使用场景
前端
计算机魔术师16 小时前
纽约时报版权诉讼披露:微软高管内部称训练 AI 是人类历史上最大规模劳动窃取
前端
去伪存真17 小时前
大模型的参数量为什么那么大?
前端·人工智能
IT_陈寒17 小时前
Java空指针这次真把我坑惨了
前端·人工智能·后端
高级程序源18 小时前
django大学生创新创业项目管理系统94923-计算机课程设计、毕业设计
javascript·vue.js·spring boot·后端·python·django·课程设计
八荒启·交互动画18 小时前
# Web特效020—让 Web 特效真正动起来:时间循环应该怎么接
前端·webgl·网页特效·八荒启-交互动画·八荒启
动恰客流统计18 小时前
线下零售数字化浪潮下,客流统计的3个核心发展趋势
大数据·前端·人工智能