TL:DR
__proto__ 是一个遗留功能,通常应避免使用MDN
什么是__proto__
简单地说,__proto__ 只是一个 propertyKey。这就是您应该看到的所有内容,因为虽然大多数内置对象之间存在共同行为,但它绝不是必须(甚至应该)以任何特定方式表现的东西。
将其视为常规的 getter/setter 对
我们可以轻松地使任何键的行为方式与__proto__ 相同:
const provingAPoint = {
get thisIsANormalKey () { return Reflect.getPrototypeOf(this) },
set thisIsANormalKey (proto) { Reflect.setPrototypeOf(this, proto) }
}
这基本上就是__proto__ 的全部内容。
始终期望对象与默认的 __proto__ 行为不同
如果您从某个 API 接收对象,则不应期望 __proto__ 的行为与默认对象中的行为相同。看上面的例子,很明显它不是一个可靠的东西。例如,我们可以这样做:
Reflect.defineProperty(provingAPoint, '__proto__', {
get: () => { throw new Error('you are not getting my prototype like this') },
set: () => { throw new Error('you will not set my prototype like this') }
})
现在如果有人试图访问这个属性,他们会得到一个错误。它现在也是只读的,不能更改或删除。
改用正确的方法
全局对象Object 和Reflect 都具有静态方法getPrototypeOf 和setPrototypeOf(关于Reflect 的细节不再赘述,它们的区别)。如果您要操作原型链,请使用这些
__proto__ 在当今 Java/EcmaScript 中的单一有效用法
令人惊讶的是,有一种有效的用途并不为人所知。创建对象字面量时,如果在其上定义 __proto__ 属性,如果其值为对象或 null,则生成的对象将使用该值作为原型
// this can save you some of the annoyances of `Object.create(null, {...descriptors})`
const objectWithNullPrototype = {
__proto__: null,
propA: 'valueA',
prop0: 'value0'
}
Object.getPrototypeOf(objectWithNullPrototype) // => `null`
// and again, don't extect any consistent behaviour of `__proto__` because:
objectWithNullPrototype.__proto__ // => `undefined`
关于prototype
函数上的prototype 属性定义了构造对象时继承的内容
总之
一个构造函数prototype属性等于它构造的对象的原型。例如:
Object.getPrototypeOf(new Array(12)) === Array.prototype // => true
// NOTE: don't do this, use literals or `Object.create`
Object.getPrototypeOf(new Object()) === Object.prototype // => true
Object.getPrototypeOf(new Map()) === Map.prototype // => true
Java/EcmaScript 是一种基于原型的语言
如果您对这意味着什么有任何疑问,我强烈建议您 google 并阅读一些有关它的文章,因为对含义的误解(或不知道)是错误和混淆的常见来源。