每个 JavaScript 对象都有一个名为 的内部“槽”,其值为 或 .您可以将槽视为对象上的一个属性,该属性位于 JavaScript 引擎内部,隐藏在您编写的代码中。周围的方括号是经过深思熟虑的,是表示内部插槽的 ECMAScript 规范约定。[[Prototype]]
null
object
[[Prototype]]
对象所指向的值,俗称“该对象的原型”。[[Prototype]]
如果通过点 () 或方括号 () 表示法访问某个属性,并且该对象不直接具有此类属性(即自己的属性,可通过 检查),则运行时会在 所引用的对象上查找具有该名称的属性。如果 也没有这样的属性,则依次检查它,依此类推。通过这种方式,原始对象的原型链被移动,直到找到匹配项,或者达到其终点。原型链的顶部是价值。obj.propName
obj['propName']
obj.hasOwnProperty('propName')
[[Prototype]]
[[Prototype]]
[[Prototype]]
null
现代 JavaScript 实现允许通过以下方式对 进行读取和/或写入访问:[[Prototype]]
- 运算符(在从构造函数返回的默认对象上配置原型链),
new
- 关键字(使用类语法时配置原型链),
extends
-
Object.create
将提供的参数设置为结果对象的参数,[[Prototype]]
-
Object.getPrototypeOf
和(在对象创建后获取/设置),以及Object.setPrototypeOf
[[Prototype]]
- 命名的标准化访问器(即 getter/setter)属性(类似于 4)。
__proto__
Object.getPrototypeOf
并且优先于 ,部分原因是 当对象具有 的原型时,的行为是不寻常的。Object.setPrototypeOf
__proto__
o.__proto__
null
对象最初是在对象创建期间设置的。[[Prototype]]
如果通过 创建新对象,则默认情况下,该对象将设置为 所引用的对象。new Func()
[[Prototype]]
Func.prototype
因此,请注意,所有类和可以与 new
运算符一起使用的所有函数,除了它们自己的 [[Prototype]]
内部槽外,还具有名为 .
prototype 的属性。“原型”这个词的这种双重使用是该语言新手无休止的混乱的根源。
与构造函数一起使用允许我们在JavaScript中模拟经典继承;尽管正如我们所看到的,JavaScript的继承系统是原型的,而不是基于类的。new
在将类语法引入 JavaScript 之前,构造函数是模拟类的唯一方法。我们可以将构造函数的属性引用的对象的属性视为共享成员;即。每个实例的成员相同。在基于类的系统中,方法对于每个实例都以相同的方式实现,因此方法在概念上被添加到属性中;但是,对象的字段是特定于实例的,因此会在构造过程中添加到对象本身。.prototype
.prototype
如果没有类语法,开发人员必须手动配置原型链,以实现与经典继承类似的功能。这导致了实现这一目标的不同方法的优势。
这是一种方法:
function Child() {}
function Parent() {}
Parent.prototype.inheritedMethod = function () { return 'this is inherited' }
function inherit(child, parent) {
child.prototype = Object.create(parent.prototype)
child.prototype.constructor = child
return child;
}
Child = inherit(Child, Parent)
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'
...这是另一种方法:
function Child() {}
function Parent() {}
Parent.prototype.inheritedMethod = function () { return 'this is inherited' }
function inherit(child, parent) {
function tmp() {}
tmp.prototype = parent.prototype
const proto = new tmp()
proto.constructor = child
child.prototype = proto
return child
}
Child = inherit(Child, Parent)
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'
ES2015 中引入的类语法简化了事情,它提供了配置原型链的“一种真正方法”,以便在 JavaScript 中模拟经典继承。extends
因此,与上面的代码类似,如果您使用类语法来创建一个新对象,如下所示:
class Parent { inheritedMethod() { return 'this is inherited' } }
class Child extends Parent {}
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'
...生成的对象将设置为 的实例,其实例又为 。[[Prototype]]
Parent
[[Prototype]]
Parent.prototype
最后,如果通过 创建新对象,则生成的对象将设置为 。Object.create(foo)
[[Prototype]]
foo