Javascript中的寄生继承使用纯Prototypal方法
Parasitic Inheritance in Javascript using pure Prototypal approach
我正在用JavaScript学习OOP,并浏览了关于同一领域的各种帖子。据我所知,道格拉斯·克罗克福德(Douglas Crockford(规定了一种纯粹的原型遗传方法,而不是经典方法。
从这里获取的以下代码实现了 Crockford 的方法:
var superInstance = {
member1: 'superMember1',
member2: 'superMember2'
};
var subInstance = Object.create(superInstance);
subInstance.member3 = 'subMember3';
我知道 Crockford 的方法取消了构造函数(如果我错了,请纠正我(。这是否意味着使用此方法初始化对象成员的唯一方法是使用对象文本,如上面的代码所示?另外,我如何使用这种方法实现寄生继承以允许父类中的共享成员、私有变量和非标量值(请参阅这篇文章(?
Crockford在他的文章中提到了"制造商函数",但没有给出任何示例代码。如果有人可以使用Crockford的纯原型方法证明寄生遗传,那就太好了。
谢谢。
对原型继承的误解源于与经典继承相反,不调用基构造函数来实例化基对象的问题。将原型设置为基对象并不等同于经典继承,因为原型在实例之间共享。正如Jimmy Breck-McKye详细描述的那样。因此,要实现寄生继承,您必须遵循两条规则。
- 切勿直接在原型中定义字段成员。
- 实例化后继函数时始终调用基构造函数
后者可以使用Object.create
或将基本对象的实例直接分配给原型来实现。鉴于Base
是一个构造函数,继承代码将如下所示
方式#1
function Base(){
//a new object is created which is assigned to 'this'
//this object has __proto__ === Base.prototype
this.baseMember = 'I am the parent';
}
Base.prototype.baseMethod = function(){
console.log('I am Base');
};
function Successor(){
//a new object is created which is assigned to 'this'
//this object has __proto__ === Successor.prototype
//we override the object's property which is used for prototypal lookup
//we lose members defined in Successor.prototype
this.__proto__ = new Base();
//we add a new property in the inherited object
this.successorMember = 'I am a child';
}
Successor.prototype.successorMethod = function(){
console.log('I am Successor');
};
我们将通过以下方式使用定义的构造函数
var child = new Successor();
//resulting in structure
//child: { //instance of Successor
// successorMember: 'I am a child',
// __proto__: {//instance of Base
// baseMember: 'I am the parent'
// __proto__: {//Base.prototype
// baseMethod : function
// }}}
console.log(child.successorMember);//accessible via direct property
console.log(child.baseMember);//accessible via prototype lookup
console.log('baseMethod' in child);//true, accessible via prototype lookup
console.log('successorMethod' in child);//false, method doesn't exist anywhere in the chain
注意通过Successor.prototype
定义的缺失successorMethod
。发生这种情况是因为我们已经重写了对象的__proto__
属性。
方式#2
覆盖 __proto__
属性的另一种方法是调用 Object.create
。但是,此函数返回一个新对象,因此我们将不得不覆盖构造函数返回Successor
的对象
function Successor(){
//a new object #1 is created which is assigned to 'this'
//this object has __proto__ === Successor.prototype
//a new instance #2 of Base is created with __proto__ === Base.prototype
//a new object #3 is created with a __proto__ set to #2
var successor = Object.create(new Base());
//a new property is added to #1
this.neverShowMember = 'I will not exist in resulting object';
//a new property is added to #3
successor.successorMember = 'I am a child';
//return of a non-primitive type object from constructor overrides the result
return successor;//return object #3
}
让我们详细研究一下这种方法的用法:
var child = new Successor();
//child: { //instance of Object
// successorMember: 'I am a child',
// __proto__: {//instance of Base
// baseMember: 'I am the parent'
// __proto__: {//Base.prototype
// baseMethod : function
// }}}
console.log(child.successorMember);//accessible via direct property
console.log(child.baseMember);//accessible via prototype lookup
console.log('baseMethod' in child);//true, accessible via prototype lookup
console.log('successorMethod' in child);//false, method doesn't exist anywhere in the chain
由此产生的行为几乎相同。请注意缺少的neverShowMember
尽管它是为构造函数中的this
定义的。这可能是错误的根源。
方式#3
另一种继承方式是不要乱用原始链。这种方法在Jimmy Breck-McKye的文章中有所描述。我将跳过之前提供的详细评论,并将重点放在更改上
function Successor(){
//a new instance Base is created with __proto__ === Base.prototype
var successor = new Base();
//extend object with a new property
successor.successorMember = 'I am a child';
return successor;//return instance of Base with extra properties
}
var child = new Successor();
//child: { //instance of Base
// successorMember: 'I am a child',
// baseMember: 'I am the parent'
// __proto__: {//Base.prototype
// baseMethod : function
// }}
console.log(child.successorMember);//accessible via direct property
console.log(child.baseMember);//accessible via direct property
console.log('baseMethod' in child);//true, accessible via prototype lookup
console.log('successorMethod' in child);//false, method doesn't exist anywhere in the chain
您会看到架构变得扁平化。一个显而易见的结论是,如果您覆盖基本成员,则无法访问它们。因此,如果在Successor
内部,我们定义
successor.baseMember = 'I am already grown enough!';
实例 ( child
( 将失去对等于"我是父级"的baseIntance.baseMember
的访问权限。与以前可以通过child.__proto__.baseMember
访问的方法相反。但我相信在 javascript 中开发时这不是常见的情况,应该在另一个问题中介绍。
请注意,在所有情况下,Successor.prototype
中定义的成员都将丢失。您应该注意在构造函数中手动复制它们Successor
。
结论
我希望这个描述足够清晰,可以理解
object
功能
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
始终需要作为参数传递的新实例o
以实现寄生继承。因此它的用法应该如下所示
var child = object(new Base());
child.successorMember = 'I am a child';
这同样适用于 OP 中的代码。要遵循寄生继承superInstance
每次传递给Object.create
时都应该是一个新实例。因此它应该是一个工厂函数
var superInstance = function(){
return {
member1: 'superMember1',
member2: 'superMember2'
}
};
var subInstance = Object.create(superInstance());
或构造函数
function superInstance(){
this.member1: 'superMember1',
this.member2: 'superMember2'
};
var subInstance = Object.create(new superInstance());
希望这有帮助
- electronic BrowserWindow的最小高度和宽度在hide()show()方法之后不起作用
- 有没有任何方法可以将控制器从文件加载到ui路由器$stateProvider中
- 数组在递归方法中设置为null
- 打破承诺链的好方法是什么
- 在使用Polymer'加载所有json文件后执行方法;s的核心ajax
- 使用“;这个“;JavaScript原型方法中的关键字
- 序列化数据属性中对象的最可靠方法
- 使用Objective-C的JavaScript注入方法
- 有没有一种方法可以添加相同的项目val=“0”;4〃;到JavaScript中数组的每个对象
- 有没有一种方法可以防止img get请求使用css或js发生
- Javascript,有没有一种方法可以将数组写成没有逗号或空格的单个文本字符串
- toBoolean方法类似于toString
- 如何在单击复选框后调用控制器方法
- 是否有任何方法可以使用jQuery替换在数组中定义值的文本
- 递归使用 eval() 是检查程序执行的好方法吗?
- 如何在webView,Android中从@JavascriptInterface方法调用Javascript
- toLocaleDateString和toLocaleString方法不尊重机器时区
- 有条件更新d3.js力图中节点的最佳方法
- TypeError:在不兼容的接收器nodejs上调用了方法Uint8Array.length
- Javascript中的寄生继承使用纯Prototypal方法