资讯专栏INFORMATION COLUMN

JS面向对象的程序设计之继承的实现-原型式继承和寄生式继承

lewinlee / 3430人阅读

摘要:通过新增方法规范了原型式继承。适用场景在没有必要兴师动众地创建构造函数,而只想让一个对象与另外一个对象保持类似的情况下,原型式继承是完全可以胜任的。在主要考虑对象而不是自定义类型和构造函数的情况下,寄生式继承也是一种有用的模式。

--
前言:最近在细读Javascript高级程序设计,对于我而言,中文版,书中很多地方翻译的差强人意,所以用自己所理解的,尝试解读下。如有纰漏或错误,会非常感谢您的指出。文中绝大部分内容引用自《JavaScript高级程序设计第三版》。

原型式继承

道格拉斯 克劳克福德在2006年写了一篇文章,题为Prototypal Inhertitance in JavaScript(JavaScript中的原型式继承)。

在这篇文章中,他介绍了一种实现继承的方法,这种方法并没有使用严格意义上的构造函数。

他的想法是借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。

为了达到这个目的,他给出了如下函数。

function object(o) {
    function F(){};
    F.prototype = o;
    return new F();
}

在object()函数内部,先创建一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回了这个临时类型的一个新实例对象。

从本质上讲,object()对传入的对象执行了一次浅复制。

function object(o){
    function F(){};
    F.prototype = o;
    return new F();
}

var person = {
    name: "Shaw",
    friends: ["Sharon", "Sandy", "Van"]
}

var person1 = object(person);

/*
person1 = function object(person){
    function F(){};
    F.prototype = person1;
    return new F();
}()

person1 = function object({
    name: "Shaw",
    friends: ["Sharon", "Sandy", "Van"]
}){
    function F(){};
    F.prototype = {
        name: "Shaw",
        friends: ["Sharon", "Sandy", "Van"]
    }
    return {
    }
}

person1 = {

};

{}.__proto__ = {
    name: "Shaw",
    friends: ["Sharon", "Sandy", "Van"]
}
*/

person1.name = "Roc";
person1.friends.push("Roster");

var person2 = object(person);

person2.name = "Linda";
person2.friends.push("Jobs");

console.log(person.friends); //["Sharon", "Sandy", "Van", "Roster", "Jobs"]
console.log(person1.friends); //["Sharon", "Sandy", "Van", "Roster", "Jobs"]
console.log(person2.friends); //["Sharon", "Sandy", "Van", "Roster", "Jobs"]

克罗克福德主张的这种原型式继承,要求你必须有一个对象可以作为另一个对象的基础。

如果有这么一个对象的话,可以把它传给object()函数,然后再根据具体需求对得到的对象加以修改即可。

ECMAscript5通过新增Object.create()方法规范了原型式继承。
这个方法接收两个参数: 一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。

在传入一个参数的情况下,Object.create()与object()方法的行为相同。

var person = {
    name: "Shaw",
    friends: ["Sharon", "Sandy", "Van"]
}

var person1 = Object.create(person);
person1.name = "Roc";
person1.friends.push("Roster");

var person2 = Object.create(person);
person2.name = "Linda";
person2.friends.push("Messi");

console.log(person.friends); //["Sharon", "Sandy", "Van", "Roster", "Messi"]
console.log(person1.friends); //["Sharon", "Sandy", "Van", "Roster", "Messi"]
console.log(person2.friends); //["Sharon", "Sandy", "Van", "Roster", "Messi"]

Object.create()方法的第二个参数与Object.defienProperties()方法的第二个参数格式相同:

每个属性都是通过自己的描述符定义的。

以这种方式指定的任何属性都会覆盖原型对象上的同名属性。

var person = {
    name: "Shaw",
    friends: ["Sharon", "Sandy", "Selina"]
}

var person1 = Object.create(person, {
    name: {
        value: "Roc"
    }
})

console.log(person1.name); //"Roc"

支持Object.create()方法的浏览器有IE9+, Firefox 4+, Opera 12+ 和 Chrome。

适用场景:

在没有必要兴师动众地创建构造函数,而只想让一个对象与另外一个对象保持类似的情况下,原型式继承是完全可以胜任的。

千万要记住,包含引用类型值的属性始终都会共享相应的值,就像使用原型模式一样。

寄生式继承

寄生式(parasitic)继承是与原型式继承紧密相关的一种思路,并且也是由大神克劳克福推而广之的。

寄生式继承的思路与寄生构造函数和工厂模式类似。

创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象。

function object(o){
    function F(){};
    F.prototype = o;
    return new F();
}

function createAnother(original) {
    var clone = object(original); //通过调用函数创建一个新对象
    clone.sayHi = function(){ //以某种方式来增强这个对象
        console.log("hi");
    }
    return clone; //返回这个对象
}

在这个例子中, createAnother()函数接收了换一个参数,也就是将要作为新对象基础的对象。
然后,把这个对象参数(original)传递给object()函数, 将返回的结果赋值给clone。

再为clone对象添加一个新方法sayHi(),最后返回clone对象。

可以像下面这样来使用createAnother()函数:

function object(o){
    function F(){};
    F.prototype = o;
    return new F();
}

function createAnother(original) {
    var clone = object(original); //通过调用函数创建一个新对象
    clone.sayHi = function(){ //以某种方式来增强这个对象
        console.log("hi");
    }
    return clone; //返回这个对象
}

var person = {
    name: "Shaw",
    friends: ["Sandy", "Sharon", "Van"]
}

var anotherPerson = createAnother(person);

anotherPerson.sayHi(); //"hi"

这个例子中的代码基于person返回一个新对象——anotherPerson。新对象不仅具有person的所有属性和方法,而且还有还有自己的sayHi()方法。

在主要考虑对象而不是自定义类型和构造函数的情况下,寄生式继承也是一种有用的模式。

前面示范继承模式时使用的object()函数不是必需的,任何能够返回新对象的函数都适用于此模式。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/98656.html

相关文章

  • 《javascript高级程序设计继承实现

    摘要:寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部已某种方式来增强对象,最后再像真的是它做了所有工作一样返回对象。 这篇本来应该是作为写JS 面向对象的前奏,只是作为《javascript高级程序设计》继承一章的笔记 原型链 code 实现 function SuperType() { this.colors = [red,blu...

    cppprimer 评论0 收藏0
  • JS学习笔记(第6章)(面向对象继承——JS继承六大方

    摘要:除此之外,在超类型的原型中定义的方法,对子类型而言也是不可兼得,结果所有类型都只能用构造函数模式。创建对象增强对象指定对象继承属性这个例子的高效率体现在它只调用了一次构造函数。 1、原型链 原型链的基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。构造函数、原型和实例的关系:每个构造函数都有一个原型对象;原型对象都包含着一个指向构造函数的指针;实例都包含一个指向原型对象的...

    lscho 评论0 收藏0
  • js继承理解

    摘要:创建自定义的构造函数之后,其原型对象只会取得属性,其他方法都是从继承来的。优缺点寄生式继承在主要考虑对象而不是创建自定义类型和构造函数时,是十分有用的。 原文链接:https://kongchenglc.coding.me... 1.原型链   js的继承机制不同于传统的面向对象语言,采用原型链实现继承,基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。理解原型链必须先理...

    BlackFlagBin 评论0 收藏0
  • JS面向对象程序设计继承实现-寄生组合继承

    摘要:组合继承最大的问题就是无论在什么情况下,都会调用两次超类型构造函数一次是在创建子类型原型的时候。好在,我们已经找到了解决这个问题方法寄生组合式继承所谓寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。 寄生组合式继承 组合继承是JavaScript最常用的继承模式。 不过,它也有自己的不足。 组合继承最大的问题就是无论在什么情况下,都会调用两次超类型构造函数...

    y1chuan 评论0 收藏0
  • 我来重新学习js 面向对象(part 5)

    摘要:无限增殖返回苹果返回香蕉返回返回使用的新语法方法会创建一个新对象,使用现有的对象来提供新创建的对象的。是新增的,用来规范原型式继承。这里将返回的新对象放到子类的原型对象里面,这样子类就拥有了父类的原型对象,也就实现了方法的继承。 这是最后的最后了,我会顺便总结一下各种继承方式的学习和理解。(老板要求什么的,管他呢) 一、继承-组合继承、伪经典继承 showImg(https://seg...

    BicycleWarrior 评论0 收藏0

发表评论

0条评论

lewinlee

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<