原型是构造函数上的属性,该函数设置将成为构造对象的proto属性。
每个对象都可以有另一个对象作为其原型。然后,前一个对象继承了其所有原型的属性。对象通过内部属性指定其原型[[Prototype]]。通过[[Prototype]]属性连接的对象链称为原型链:
Prototype为了了解基于原型的继承(或原型)的继承方式,让我们看一个示例(使用用于指定[[Prototype]]属性的发明语法):
var proto = {
describe: function () {
return 'name: '+this.name;
}
};
var obj = {
[[Prototype]]: proto,
name: 'obj'
};
> obj.describe
[Function]
> obj.describe()
'name: obj'
__proto__
是一个存取器属性的的Object.prototype
对象。它公开了内部原型链接[[Prototype]])
function Foo(name) {
this.name = name;
}
var b = new Foo('b');
var a = new Foo('a');
b.say = function() {
console.log('Hi from ' + this.whoAmI());
}
console.log(a.__proto__ === Foo.prototype); // true
console.log(a.__proto__ === b.__proto__); // true
prototype
JavaScript引擎将say()
方法添加到b对象,而不是Foo.prototype
对象。
如您在图中所看到的,a.proto暴露了[[Prototype]]指向Foo.prototype对象的。同样,b.proto也指向与a.proto
示例1:通过构造函数创建对象
除了通过指定的模式创建对象外,构造函数还可以做另一件事-它会自动为新创建的对象设置prototype
。该prototype
存储在ConstructorFunction.prototype
属性中。
例如在之前示例中, 我们可以用构造函数重写带有对象b.
function Foo(y) {
this.y = y;
}
Foo.prototype.x = 10;
Foo.prototype.calculate = function (z) {
return this.x + this.y + z;
};
var b = new Foo(20);
b.calculate(30); // 60
console.log(
b.__proto__ === Foo.prototype, // true
b.__proto__.calculate === Foo.prototype.calculate // true
b.__proto__.calculate === b.calculate, // true
Foo === b.constructor, // true
Foo === Foo.prototype.constructor, // true
);
如上所示,b是从Foo()继承的方法。“ Foo.prototype”自动创建一个特殊属性“ constructor”,该属性是对构造函数本身的引用。
实例“ b”可以通过委托找到它,并用于检查其构造函数。
示例2:JavaScript经典继承图
这是一个关于通过构造函数创建对象的示例,但是我们将重点放在这些对象和实例系列期间的原型链问题。原型对象也只是简单的对象,可能有自己的原型。如果某个原型对其原型具有非空引用,依此类推,则称为原型链
原型链png现在,从图中可以看出为什么当我们从Animal继承Dog时,我们会这样做:
function Dog() {} // the usual constructor function
Dog.prototype = new Animal();
Dog.prototype.constructor = Dog;
当new()一个实例时会发生什么:
需要注意的是,原型在Foo.prototype是不是形成一个原型链。Foo.prototype 指向原型链中的某些位置,但是Foo的原型属性不是构成原型链。什么构成了一个原型链是proto朝上链,且对象指向proto,如去富.__ proto__,马上要到富.原.__ proto__,依此类推,直到空为止。
proto和原型的关系
JavaScript的工作方式如下:我是一个构造函数,我只是一个函数,并且我拥有一个原型引用,并且每当调用foo = new Foo()时,我都会让foo .__ proto__指向我的原型对象。因此,Foo.prototype和obj .__ proto__是两个不同的概念。Foo.prototype指示创建Foo的对象时,这是新对象的原型链应指向的位置,即foo .__ proto__应指向Foo.prototype指向的位置。
如果需要添加功能怎么办?
如果woofie对象没有move方法,它将像任何原型继承场景一样,沿着原型链上升,首先到达woofie .__ proto__指向的对象,这与Dog.prototype引用的对象相同至。如果方法move不是该对象的属性(意味着Dog类没有方法move),请在原型链中上一层,即woofie .__ proto . proto__,或与Animal.prototype相同。
Animal.prototype.move = function() { ... };
__proto__
即使foo.constructor === Foo,构造方法属性也不是foo自己的属性。它实际上是通过向上访问foo .__ proto__所指向的原型链来获得的。这同样适用于Function.constructor。当我们看到Constructor.prototype,foo .__ proto__,Foo.prototype.constructor时,该图可能很复杂,有时会造成混淆。
为了验证该图,请注意,即使foo.constructor将显示一个值,该属性构造函数也不是foo的自己的属性,而是通过跟踪原型链来获得的,如foo.hasOwnProperty(“ constructor”)所示。
笔记:
**[[Prototype]]**
对象通过内部属性指定其原型
**__proto__**
直接访问[[Prototype]]
**prototype**
是的对象是用于构建__proto__
,当你创建一个对象new.
**prototype**
在实例本身(或其他对象)上不可用,而仅在构造函数上可用。
**prototype**
仅在函数上可用,因为它们是从中复制的Function
,Object,
而在其他任何函数中则不是。但是,**__proto__**
随处可见。
( new Foo ).__proto__ === Foo.prototype //true
( new Foo ).prototype === undefined //true
委托原型和串联继承
Cat.prototype = new Animal();
//它将通过继承层次结构正确遵循原型链。
Cat.prototype = Animal.prototype
//Cat原型的任何运行时更改也会影响动物
原型上不存在静态属性/功能。在prototype一个时才使用new被创建的实例。
喜欢这个故事吗?对别人有帮助吗?轻按下面的心脏,它可以帮助我知道您是否想写更多有关他的话题的信息,并帮助人们看到故事。
参考
Javascript inheritance behind the scene proto, [[prototype]] and prototype
网友评论