为什么Object.keys()方法没有被添加到Object.prototype中?

10

我对 JavaScript 为什么以某种方式工作感到困惑。

如果我有一个对象被设置为变量obj,并且如果我想列出对象中的所有键,则会这样说

Object.keys(obj)

为什么不是下面这样呢?

obj.keys()

如果我正在使用数组,那么应该使用arr.pop()。 那么为什么在 obj.keys() 中不使用相同的语法呢?为什么它必须是 Object.keys(obj)


为什么要使用Object.prototype.hasOwnProperty.call(myObj, prop)而不是myObj.hasOwnProperty(prop)? - adiga
1
可能是为什么Object.keys不是Object.prototype.keys?的重复问题。 - Slai
2个回答

16

你可以在Object.prototype上定义一个keys方法使其符合你的预期,但这不是一个好主意。

Object.prototype.keys = function() {
  return Object.keys(this);
};

const obj = {
  prop: 'val'
};
const keys = obj.keys();
console.log(keys);

使用对象键的问题在于,对象通常可以具有任何类型的键。该对象甚至可能具有名为keys的键。例如:

const obj = {
  name: 'building 1',
  keys: 'foo'
}

在这里,如果你执行obj.keys(),你会得到一个TypeError,因为keys属性是指对象直接拥有的属性,而不是Object.prototype方法。

Object.prototype.keys = function() {
  return Object.keys(this);
};

const obj = {
  name: 'building 1',
  keys: 'foo'
};


const keys = obj.keys();
console.log(keys);

因此,获取对象所有键的方法被放在了Object上作为静态方法,而不是原型方法Object.prototype上,以避免可能的名称冲突。另一方面,普遍期望数组具有特定的几个方法(如push),而且没有其他内容。数组不是通用对象 - 你几乎总是期望一个数组只有数组方法,而且数组几乎从不会添加任意键(如果您看到有这样的代码,那么它可能值得重构)。因此,对于数组,不存在像通用对象那样的数组方法导致名称冲突的实际可能性。因此,有Array.prototype.push没有问题,但Object.prototype.keys很容易引起问题。

这应该被标记为正确答案。 - Kevin Farrugia

3

除了假设的 keys() 方法可能被隐藏外,还有可能该值根本不是Object实例。

考虑以下示例:

// properly define your suggested method
Object.defineProperty(Object.prototype, 'keys', {
  configurable: true,
  writable: true,
  value: function keys () { return Object.keys(this); }
})

const obj = { foo: 'bar', hello: 'world' };

console.log(obj instanceof Object);

// okay
console.log(obj.keys());

const value = Object.create(
  null,
  Object.getOwnPropertyDescriptors(obj)
);

console.log(value instanceof Object);

// existing approach still works
console.log(Object.keys(value));

// suggested approach fails
console.log(value.keys());


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接