由于对原型继承的了解较少,我陷入困境。我想知道原型继承到底是什么以及它是如何实现的。
你能举一个简单的例子吗?
任何帮助表示赞赏。
想象一下,您有一个对象,并且想要查找一个属性。现在想象该属性不存在。如果您可以让它自动继续在不同对象上搜索该属性怎么办?这基本上就是原型继承。
那么唯一的问题是如何在对象之间建立这种关系。嗯,这就是奇怪的部分。
我将从主要的历史方式开始。那就是使用函数。
首先要注意的是,JavaScript 中的函数本身就是一个对象。它可以有自己的属性,并且它使用原型继承来访问其他属性。
所以让我们从创建一个函数开始。
function Foo() {
// our function
}
所以现在我们有一个名为Foo
. 我们的新函数在创建时会自动获取一个命名的属性prototype
。该属性引用了一个(几乎)空对象。
console.log(typeof Foo.prototype); // object
为什么该属性和对象存在?嗯,它们的存在是为了支持 JavaScript 在我上面描述的对象之间形成这种关系的奇怪方式。
基本上,该Foo.prototype
对象是我们在寻找对象的新属性时将用作“备份”对象的对象。但是我们还没有在我们想要使用的对象和Foo.prototype
对象之间形成任何特殊的关系。
为此,我们实际上使用new
运算符调用函数。
var my_object = new Foo();
我们开始了。所以现在my_object
是一个新的空对象。但它在它的“原型链”中有一个对象,它从我们的Foo
函数中悬挂下来,脱离了它的.prototype
属性。换句话说,当我们在 上查找属性时my_object
,如果该属性不存在,它将继续在该Foo.prototype
对象上进行搜索。
问题是我们没有添加任何我们可能会觉得有用的东西Foo.prototype
。但实际上该对象有一个属性。该属性也是在我们创建Foo
函数时自动创建的,它就是.constructor
属性。
该属性参考什么?它有一个对Foo
函数的引用。换句话说:
Foo.prototype.constructor === Foo; // true
好吧,所以如果我们my_object
是空的,并且如果在寻找my_object
不存在的属性时,它会继续在Foo.prototype
对象上搜索,那么这应该意味着我们应该能够自动Foo.prototype.constructor
从my_object
.
my_object.constructor === Foo; // true
它有效。由于my_object
没有名为 的属性constructor
,它继续搜索它所继承的对象,即Foo.prototype
,正如我们所知,它具有.constructor
引用该Foo
函数的属性。
极好的。但是我们如何在代码中设置对我们更有用的其他属性呢?我们只是将它们添加到Foo.prototype
. my_object
如果对象不直接拥有它们,这将让我们找到这些属性。
// give a custom property to `Foo.prototype`
Foo.prototype.bar = "foobar";
// see if we can access that property on your object
my_object.bar === "foobar"; // true
果然,它奏效了。因此,让我们看看我们是否可以从中创建一个新对象,Foo
该对象也可以访问该.bar
属性。
var another_object = new Foo();
another_object.bar === "foobar"; // true
再次,它有效。这是因为通过Foo
使用new
关键字调用创建的所有对象都将在其原型链中包含该Foo.prototype
对象。换句话说,在从创建的所有实例Foo.prototype
之间共享Foo
。
因此,如果我们现在修改Foo.prototype.bar
属性,它将反映在我们创建的两个对象中。
Foo.prototype.bar = "raboof";
my_object.bar === "raboof"; // true
another_object.bar === "raboof"; // true
所以我们可以看到,我们的两个对象都只是在寻找它们没有的属性,方法是将搜索传递给它们“原型链”中的下一个对象,也就是悬挂在Foo
函数之外的那个奇怪的对象…… Foo.prototype
。
建立这种对象关系有更新的方法,但这是原始方法,尽管它很奇怪,但可能应该首先理解。
我是这样理解的:
这可以被认为是一个构造函数
var Thing = function(){
this.method1 = function(){
alert( "method 1" );
}
}
这是它的一个实例
var a_thing = new Thing();
a_thing.method1();
现在,如果你在构造函数的原型中添加一些东西,它就会自动提供给已经实例化的对象。
Thing.prototype.method2 = function(){
alert( "method2" );
}
a_thing.method2();
希望这可以帮助。
这是我能想到的最简单的例子,
pizza 类通过使用这一行从 circle 继承:
pizza.prototype = new circle();
完整示例:
<html>
<head>
<script>
// base class
function circle(radius){
this.radius = radius;
this.getArea = function ()
{
return (this.radius * this.radius) * Math.PI;
};
this.foo = function ()
{
return "circle foo";
};
return true;
}
// child class
function pizza(flavour, radius){
circle.call(this, radius);
this.flavour = flavour;
this.foo = function ()
{
return "pizza foo";
};
return true;
}
// Inheritance
pizza.prototype = new circle();
function Go(){
// Instancing new object
var myCircle = new circle(8);
var myPizza = new pizza("Onion", 5);
// Calling property
var pizza_area = myPizza.getArea();
// Calling override foo function
var foo = myPizza.foo();
// Calling foo base class
var base = pizza.prototype.foo.call(myPizza);
//Line.prototype.someFunction.call(myLine);
var isBase = myCircle instanceof pizza;
isBase = myPizza instanceof pizza;
}
</script>
</head>
<body onload="Go();">
</body>
</html>