小技巧:如何精确判断一个变量是空对象?

1,744 阅读2分钟

每天一个填坑小细节之判断空对象

在现代浏览器中使用Object.keys()判断

const empty = {};

Object.keys(empty).length === 0 && empty.constructor === Object;

为何加了一个额外的constructor判断?

你可能很好奇,为何加了一个constructor检测?

且听我给你一一分析

我们都知道在js中有9种内置的构造函数

new Object();

new String();
new Number();
new Boolean();
new Array();
new RegExp();
new Function();
new Date();

我们可以用new Object()来创建一个对象

但是最好不要这么用

const obj = new Object();

Object.keys(obj).length === 0; // true

这样,使用Object.keys去判断, 当对象为空的时候返回true ✅.

但是,但我们用其他构造函数创建实例会怎么样?

function badEmptyCheck(value) {
  return Object.keys(value).length === 0;
}

badEmptyCheck(new String());    // true 😱
badEmptyCheck(new Number());    // true 😱
badEmptyCheck(new Boolean());   // true 😱
badEmptyCheck(new Array());     // true 😱
badEmptyCheck(new RegExp());    // true 😱
badEmptyCheck(new Function());  // true 😱
badEmptyCheck(new Date());      // true 😱

奇怪的事情发生了

少了constructor判断以后,都为真

使用constructor检测来避免其他构造函数的创建的空对象

function goodEmptyCheck(value) {
  Object.keys(value).length === 0
    && value.constructor === Object; // 👈 constructor check
}

goodEmptyCheck(new String());   // false ✅
goodEmptyCheck(new Number());   // false ✅
goodEmptyCheck(new Boolean());  // false ✅
goodEmptyCheck(new Array());    // false ✅
goodEmptyCheck(new RegExp());   // false ✅
goodEmptyCheck(new Function()); // false ✅
goodEmptyCheck(new Date());     // false ✅

这样一来,避免了其他情况的影响

其他特殊值的判断,null, undefined

当碰到null, undefined时,会抛出错误

// TypeError: Cannot covert undefined or null ot object
goodEmptyCheck(undefined);
goodEmptyCheck(null);

为了解决这个问题,可以加一个存在性判断, 解决错误抛出

function goodEmptyCheck(value) {
  value && Object.keys(value).length === 0
    && value.constructor === Object; // 👈 constructor check
}

旧浏览器中使用 Object.prototype.toString.call()判断

旧浏览器中不支持ES新方法

我们使用Object.prototype.toString.call()配合JSON.stringify(value) === '{}'来判断

function isObjectEmpty(value) {
  return (
    Object.prototype.toString.call(value) === '[object Object]' &&
    JSON.stringify(value) === '{}'
  );
}

碰到空对象时会正确输出

isObjectEmpty({});           // true ✅
isObjectEmpty(new Object()); // true ✅

不需要使用constructor检测

这种判断方式,避免了其他构造函数的影响

isObjectEmpty(new String());   // false ✅
isObjectEmpty(new Number());   // false ✅
isObjectEmpty(new Boolean());  // false ✅
isObjectEmpty(new Array());    // false ✅
isObjectEmpty(new RegExp());   // false ✅
isObjectEmpty(new Function()); // false ✅
isObjectEmpty(new Date());     // false ✅

nullundefined也可以正确处理

当然,即使是 nullundefined,也不需要额外处理

isObjectEmpty(null);      // false
isObjectEmpty(undefined); // false

其他方法:借助第三方库

Lodash

_.isEmpty({});
// true

Underscore

_.isEmpty({});
// true

jQuery

jQuery.isEmptyObject({});
// true