Object.create(null) 和 new Object() 创建的对象有什么区别?
Object.create(null) 和 new Object()(或者字面量 {})在 JavaScript 中都用于创建对象,但它们之间有着本质的区别,核心差异在于原型链(Prototype Chain)。
简单来说:
new Object()创建的是一个带有标准原型链的普通对象。Object.create(null)创建的是一个绝对纯净的空对象,没有任何原型和内置方法。
以下是详细对比:
1. new Object() (或 {})
当你使用 new Object() 或字面量 {} 创建对象时,这个对象默认会继承 Object.prototype。
- 原型链:
obj.__proto__ === Object.prototype - 自带属性和方法:因为它继承了
Object.prototype,所以它天生自带许多内置方法,例如toString()、valueOf()、hasOwnProperty()等。
示例:
javascript
let obj1 = new Object(); // 等同于 let obj1 = {};
console.log(obj1.toString); // [Function: toString]
console.log(obj1.hasOwnProperty); // [Function: hasOwnProperty]
console.log(obj1.constructor); // [Function: Object]
2. Object.create(null)
Object.create(proto) 方法会使用指定的 proto 对象作为新创建对象的原型。当你传入 null 时,意味着新对象没有原型。
- 原型链:完全没有原型(没有
__proto__属性,或者说原型指向null)。 - 自带属性和方法:什么都没有。它是一个真正的“空字典”(裸对象),没有任何内置方法。
示例:
javascript
let obj2 = Object.create(null);
console.log(obj2.toString); // undefined
console.log(obj2.hasOwnProperty); // undefined
console.log(obj2.constructor); // undefined
console.log(obj2.__proto__); // undefined
3. 为什么需要 Object.create(null)?(应用场景)
既然什么方法都没有,那为什么要用它呢?主要有以下几个原因:
A. 作为纯粹的字典/哈希映射(Map)
在使用普通对象 {} 存储键值对时,如果键名是用户输入的,可能会与原型链上的属性发生命名冲突。
javascript
// 使用普通对象
let counts = {};
let word = "constructor";
// 假设你想记录 "constructor" 这个词出现的次数
if (counts[word]) {
counts[word]++;
} else {
counts[word] = 1; // 这里会出 bug!
}
// 因为 counts["constructor"] 默认是一个函数,不是 undefined,所以逻辑会出错。
// 使用 Object.create(null)
let pureCounts = Object.create(null);
let word2 = "constructor";
if (pureCounts[word2]) { // undefined,正常进入 else
pureCounts[word2]++;
} else {
pureCounts[word2] = 1; // 完美运行
}
注意:在现代 JavaScript 中,如果需要键值对映射,更推荐使用 ES6 的 Map 数据结构,但了解 Object.create(null) 依然很重要。
B. 提升性能(微乎其微但存在)
对于 Object.create(null) 创建的对象,在使用 for...in 循环时,不需要遍历原型链,在检查属性时也不需要去原型链上查找,因此在极端的性能场景下(如大型数据字典),它的运行效率会略高一点。
C. 防止原型污染安全问题
在处理外部传入的不可信数据(如解析 JSON)时,使用 Object.create(null) 可以避免黑客通过 __proto__ 属性进行原型链污染攻击。
4. 总结对比表
| 特性 | new Object() 或 {} |
Object.create(null) |
|---|---|---|
| 原型 (Prototype) | 指向 Object.prototype |
没有原型 (null) |
| 内置方法 | 有 (toString, hasOwnProperty 等) |
无 (完全纯净) |
| 对象类型校验 | typeof obj === 'object' |
typeof obj === 'object' |
hasOwnProperty |
可以直接调用 obj.hasOwnProperty('x') |
会报错!需用 Object.hasOwn(obj, 'x') 或 Object.prototype.hasOwnProperty.call(obj, 'x') |
| 适用场景 | 普通的对象操作,需要面向对象特性 | 纯粹的键值对存储(字典),防属性冲突,防原型污染 |