每日前端面试题-如何判断空对象,如何区分数据类型

一、如何判断空对象

①最常用 的是 Object.keys(obj).length === 0。它检查对象自身的、可枚举的属性名个数,性能好,能满足绝大多数业务场景。

②如果需要考虑不可枚举属性 (例如通过 Object.defineProperty 创建的属性),可以使用 Object.getOwnPropertyNames(obj).length === 0

③如果需要考虑最全面的情况(包括 Symbol 类型的属性键),则要使用 Reflect.ownKeys(obj).length === 0

④JSON.stringify(obj) === '{}' 方法虽然简单,但会忽略函数、undefined 等属性值,存在局限性,一般不推荐在严格的逻辑判断中使用。

1、JSON.stringify()

将对象转换为 JSON 字符串,然后判断其是否等于 '{}'

javascript 复制代码
const obj = {};
const isEmpty = JSON.stringify(obj) === '{}';
console.log(isEmpty); // true

const obj2 = { name: 'Tom' };
console.log(JSON.stringify(obj2) === '{}'); // false

缺点:

①性能问题:将整个对象序列化为字符串是一个相当耗时的行为

②如果属性值是函数,undefined,Symbol,JSON.stringigy()会忽略它们

javascript 复制代码
const obj = { a: undefined, b: function() {}, c: Symbol() };
console.log(JSON.stringify(obj) === '{}'); // true (但实际它有属性,所以判断不准确)
2、Object.keys() (最常用,兼顾性能和准确度)

Object.keys(obj) 返回对象自身可枚举属性名组成的数组。判断数组长度是否为 0 即可。

javascript 复制代码
const obj = {};
const isEmpty = Object.keys(obj).length === 0;
console.log(isEmpty); // true

const obj2 = { name: 'Tom' };
console.log(Object.keys(obj2).length === 0); // false

const obj3 = { a: undefined };
console.log(Object.keys(obj3).length === 0); // false (因为它确实有一个属性 'a')
3、Object.getOwnPropertyNames()可以发现不可枚举属性

返回所有属性名构成的数组,包含不可枚举属性,但是不包含Symbol类型的属性

javascript 复制代码
const obj = {};
Object.defineProperty(obj, 'hidden', {
  value: 'secret',
  enumerable: false // 设置为不可枚举
});

console.log(Object.keys(obj).length === 0); // true (keys 无法发现不可枚举属性)
console.log(Object.getOwnPropertyNames(obj).length === 0); // false (发现了不可枚举属性)
4、Reflect.ownKeys()(最彻底最全面的,返回所有属性名构成的数组)
javascript 复制代码
const obj = {};
const sym = Symbol('key');
obj[sym] = 'symbol value';

Object.defineProperty(obj, 'hidden', {
  value: 'secret',
  enumerable: false
});

console.log(Reflect.ownKeys(obj).length === 0); // false (包含了 Symbol 和不可枚举属性)
5、for...in(通常不推荐,但需要了解)

for...in 循环会遍历对象的可枚举属性 ,包括继承自原型链的属性。因此用它判断时,通常需要配合 hasOwnProperty 来过滤。

javascript 复制代码
function isEmpty(obj) {
            for(let key in obj) {
                if(obj.hasOwnProperty(key)) {
                    return false
                }
                return true
            }
        }
        const obj = {}
        console.log(isEmpty(obj))


        // 但是如果原型链上有可枚举属性
        const protoObj = {inherited: 'value'}
        // 以protoObj为原型创建新的对象
        const childObj = Object.create(protoObj)
        // true,(因为 childObj 自身没有属性,虽然原型链上有,但 hasOwnProperty 过滤掉了)
        console.log(isEmpty(childObj))

二、如何区分数据类型

javascript的数据类型分为两大类:

基本类型:string, number, boolean, undefined, null

引用类型:object, function, array, date

1、typeof操作符

typeof 适合判断 stringnumberbooleanundefinedsymbolbigintfunction。对于 null 和大部分对象类型,它只能返回 "object",无法进一步区分

javascript 复制代码
console.log(typeof 'hello');     // "string"
console.log(typeof 42);          // "number"
console.log(typeof true);        // "boolean"
console.log(typeof undefined);   // "undefined"
console.log(typeof Symbol());    // "symbol"
console.log(typeof 123n);        // "bigint"
console.log(typeof function(){});// "function" (函数是对象的一种,但 typeof 特殊处理)

// ---------- 著名的坑 ----------
console.log(typeof null);        // "object" (这是一个存在了20多年的bug)
console.log(typeof [1, 2, 3]);   // "object"
console.log(typeof {});          // "object"
console.log(typeof new Date());  // "object"
2、instanceof 操作符 (用于检查对象的具体类型)
javascript 复制代码
console.log([] instanceof Array);       // true
console.log([] instanceof Object);      // true (因为数组的原型链上也有 Object.prototype)
console.log({} instanceof Object);      // true
console.log(new Date() instanceof Date);// true
console.log(/regex/ instanceof RegExp); // true

// 基本类型用 instanceof 通常为 false
console.log('hello' instanceof String); // false (除非是 new String('hello') 创建的对象)
3、Object.prototype.toString.call() (终极方案,最准确)

这是最强大、最准确的类型判断方法。它可以返回任何数据类型的内部 [[Class]] 属性。

javascript 复制代码
const toString = Object.prototype.toString;

console.log(toString.call('hello'));      // "[object String]"
console.log(toString.call(42));           // "[object Number]"
console.log(toString.call(true));         // "[object Boolean]"
console.log(toString.call(undefined));    // "[object Undefined]"
console.log(toString.call(null));         // "[object Null]"
console.log(toString.call(Symbol()));     // "[object Symbol]"
console.log(toString.call(123n));         // "[object BigInt]"
console.log(toString.call([]));           // "[object Array]"
console.log(toString.call({}));           // "[object Object]"
console.log(toString.call(function(){})); // "[object Function]"
console.log(toString.call(new Date()));   // "[object Date]"
console.log(toString.call(/regex/));      // "[object RegExp]"
console.log(toString.call(new Error()));  // "[object Error]"
console.log(toString.call(document));     // "[object HTMLDocument]"
console.log(toString.call(globalThis));   // "[object global]" 或 "[object Window]"
相关推荐
小码哥_常13 小时前
安卓开发秘籍:解锁10大性能优化秘诀
前端
try2find14 小时前
打印ascii码报错问题
java·linux·前端
郑州光合科技余经理15 小时前
同城O2O海外版二次开发实战:从支付网关到配送算法
开发语言·前端·后端·算法·架构·uni-app·php
冰暮流星15 小时前
javascript事件案例-全选框案例
服务器·前端·javascript
Csvn16 小时前
前端性能优化实战指南
前端
Moment16 小时前
2026 年,AI 全栈时代到了,前端简历别再只写前端技术了 🫠🫠🫠
前端·后端·面试
糯米团子74916 小时前
Web Worker
开发语言·前端·javascript
freewlt16 小时前
React Server Components 深度解析
前端·react.js·前端框架
wordbaby17 小时前
一次跨端 Loading 卡死复盘:把请求计数从 Axios 拦截器迁到 try/catch/finally
前端·axios
我命由我1234517 小时前
JavaScript 开发 - 获取函数名称、获取函数参数数量、获取函数参数名称
开发语言·前端·javascript·css·html·html5·js