Object.create(null)

JavaScript

Object.create 可以用提供的对象做新对象的 __proto__。这导致了一个很有趣的现象,如果使用 Object.create(null) 来创建新对象,那么这个新对象上就没有任何 __proto__。因为 JavaScript 的对象经常被用来做字典使用,Object.create(null) 可以让这个功能使用更加的纯粹。

const dict = Object.create(null);
console.log(Object.getPrototypeOf(dict));
// output: null
console.log(typeof dict.hasOwnProperty);
// output: "undefined"
const obj = { };
console.log(Object.getPrototypeOf(obj));
// output:
// {
//   constructor,
//   hasOwnProperty,
//   isPrototypeOf,
//   propertyIsEnumerable,
//   toLocaleString,
//   toString,
//   valueOf,
//   ...
// }

同样,因为没有 prototype,理论上来说,后续如果有人对 Object.prototype 做操作,也不会影响到使用。

const dict = Object.create(null);
// ...
Object.prototype.addSomething = () => { };
console.log(typeof dict.addSomething);
// output: undefined
for (const key in dict) console.log(key);
// no output

console.log(typeof ({}).addSomething);
// output: function
for (const key in {}) console.log(key);
// output: 'addSomething'

所以,如果判断对象有某个字段,那么一定是他自身有这个字段,而不会是因为原型链上的定义。也就是说,不需要用:

if (Object.prototype.hasOwnProperty.call(dict, 'addSomething') { }) {
  // ...
}

而只需要写:

if (dict.addSomething) {
  // ...
}

当然,这也会有一些弊端,比如默认 Object.prototype 的东西就没了,如果需要 toString 之类的函数,得自己写。