// the parent constructor

function Parent(name) {

    this.name = name || 'Adam';

}

// adding functionality to the prototype

Parent.prototype.say = function () {

    return this.name;

};

// empty child constructor

function Child(name) {}

inherit(Child, Parent);

A method say() added to the parent constructor’s prototype, and a call to a function called inherit() that takes care of the inheritance. The  inherit() function is not provided by the language, so you have to implement it yourself.

Classical Pattern #1—The Default Pattern

Create an object using the  Parent() constructor and assign this object to the Child()’s prototype.

function inherit(C, P) {

    C.prototype = new P();
} var kid = new Child(); kid.say(); // "Adam"
  1. Following the Prototype Chain

  1. Drawbacks when Using Pattern #1
  1. Inherit both own properties added to this and prototype properties.

Note: reusable members should be added to the prototype.

  1. It doesn't enable you to pass parameters to child constructor, which the child then passes to the parent.

Classical Pattern #2 -- Rent-a-Constructor

Passing arguments from the child to the parent.

function Child(a, c, b, d) {

    Parent.apply(this, arguments);

}

// a parent constructor

function Article() {

    this.tags = ['js', 'css'];

}

var article = new Article();

// a blog post inherits from an article object

// via the classical pattern #1

function BlogPost() {}

BlogPost.prototype = article;

var blog = new BlogPost();

// note that above you didn't need `new Article()`

// because you already had an instance available

// a static page inherits from article

// via the rented constructor pattern

function StaticPage() {

    Article.call(this);

}

var page = new StaticPage();

alert(article.hasOwnProperty('tags')); // true

alert(blog.hasOwnProperty('tags')); // false

alert(page.hasOwnProperty('tags')); // true
  1. The Prototype Chain

The inheritance was a one-off action that copied parent’s own properties as child’s own properties and that was about it; no __proto__ links were kept.

// the parent constructor

function Parent(name) {

    this.name = name || 'Adam';

}

// adding functionality to the prototype

Parent.prototype.say = function () {

    return this.name;

};

// child constructor

function Child(name) {

    Parent.apply(this, arguments);

}

function showMsg(msg) {

    $('#msg').append(msg).append('<br/>');

}

$(function () {

    var kid = new Child("Patrick");

    showMsg(kid.name); // "Patrick"

    showMsg(typeof kid.say); // "undefined"

});

  1. Multiple Inheritance by Borrowing constructors

Implement multiple inheritance simply by borrowing from more than one constructor

function Cat() {

    this.legs = 4;

    this.say = function () {

        return "meaowww";

    }

}

function Bird() {

    this.wings = 2;

    this.fly = true;

}

function CatWings() {

    Cat.apply(this);

    Bird.apply(this);

}
var jane = new CatWings(); console.dir(jane);

  1. Pros and Cons of the Borrowing Constructor Pattern

Pros: Get true copies of the parent's own members and there's no risk that a child can accidentally overwrite a parent's property.

Cons: Nothing from the prototype gets inherited.

Classical Pattern #3—Rent and Set Prototype

function Child(a, c, b, d) {

    Parent.apply(this, arguments);

}

Child.prototype = new Parent();

The benefit is that the result objects get copies of the parent’s own members and references to the parent’s reusable functionality (implemented as members of the prototype). The child can also pass any arguments to the parent constructor. This behavior is probably the closest to what you’d expect in Java; you inherit everything there is in the parent, and at the same time it’s safe to modify own properties without the risk of modifying the parent.

A drawback is that the parent constructor is called twice, so it could be inefficient. At the end, the own properties (such as name in our case) get inherited twice.

// the parent constructor
function Parent(name) {
this.name = name || 'Adam';
}
// adding functionality to the prototype
Parent.prototype.say = function () {
return this.name;
};
// child constructor
function Child(name) {
Parent.apply(this, arguments);
}
Child.prototype = new Parent(); function showMsg(msg) {
$('#msg').append(msg).append('<br/>');
}
var kid = new Child("Patrick");
kid.name; // "Patrick"
kid.say(); // "Patrick"
delete kid.name; kid.say(); // "Adam"

Classical Pattern #4—Share the Prototype

This gives you short and fast prototype chain lookups because all objects actually share the  same  prototype.

function inherit(C, P) {

    C.prototype = P.prototype;

}

Drawback

if  one  child  or  grandchild somewhere down the inheritance chain modifies the prototype, it affects all parents and grandparents.

Classical Pattern #5—A Temporary Constructor

An empty function  F(), which serves as a proxy between the child and the parent. F()’s  prototype property points to the prototype of the parent. The prototype of the child is an instance of the blank function:

function inherit(C, P) {

    var F = function () {};

    F.prototype = P.prototype;

    C.prototype = new F();

}

In this pattern, any members that the parent constructor adds to this are not inherited.

  1. Storing the Superclass

The property is called uber because “super” is a reserved word and “superclass” may

lead the unsuspecting developer down the path of thinking that JavaScript has classes.

Here’s an improved implementation of this classical pattern:

function inherit(C, P) {

    var F = function () {};

    F.prototype = P.prototype;

    C.prototype = new F();

    C.uber = P.prototype;

}
  1. Resetting the Constructor Pointer

If you don’t reset the pointer to the constructor, then all children objects will report that Parent() was their constructor, which is not useful.

// parent, child, inheritance

function Parent() {}

function Child() {}

inherit(Child, Parent);

// testing the waters

var kid = new Child();

kid.constructor.name; // "Parent"

kid.constructor === Parent; // true

function inherit(C, P) {

    var F = function () {};

    F.prototype = P.prototype;

    C.prototype = new F();

    C.uber = P.prototype;

    C.prototype.constructor = C;

}

Create temporary (proxy) constructor once and only change its prototype. You can use an immediate function and store the proxy function in its closure:

var inherit = (function () {

        // This will only be executed once which means only one function object is created for every inheritance.

        var F = function () {};     

        return function (C, P) {

        F.prototype = P.prototype; // F.prototype.constructor is pointed to Parent.

        C.prototype = new F();

        C.uber = P.prototype;

        C.prototype.constructor = C;

       }

}());

References: 

JavaScript Patterns - by Stoyan Stefanov (O`Reilly)

JavaScript Patterns 6.2 Expected Outcome When Using Classical Inheritance的更多相关文章

  1. JavaScript Patterns 7.1 Singleton

    7.1 Singleton The idea of the singleton pattern is to have only one instance of a specific class. Th ...

  2. JavaScript Patterns 6.7 Borrowing Methods

    Scenario You want to use just the methods you like, without inheriting all the other methods that yo ...

  3. JavaScript Patterns 6.6 Mix-ins

    Loop through arguments and copy every property of every object passed to the function. And the resul ...

  4. JavaScript Patterns 6.5 Inheritance by Copying Properties

    Shallow copy pattern function extend(parent, child) { var i; child = child || {}; for (i in parent) ...

  5. JavaScript Patterns 6.4 Prototypal Inheritance

    No classes involved; Objects inherit from other objects. Use an empty temporary constructor function ...

  6. JavaScript Patterns 6.3 Klass

    Commonalities • There’s a convention on how to name a method, which is to be considered the construc ...

  7. JavaScript Patterns 6.1 Classical Versus Modern Inheritance Patterns

    In Java you could do something like: Person adam = new Person(); In JavaScript you would do: var ada ...

  8. JavaScript Patterns 5.9 method() Method

    Advantage Avoid re-created instance method to this inside of the constructor. method() implementatio ...

  9. JavaScript Patterns 5.8 Chaining Pattern

    Chaining Pattern - Call methods on an object one after the other without assigning the return values ...

随机推荐

  1. Qt的tablewidget行列头自适应宽度

    Qt构造一个TableWidget后,窗口最大化后,列头默认不能自适应宽度,研究了一下,Qt提供了两种方式来处理这个问题,如下:   1. 使用horizontalHeader()->setRe ...

  2. 孙鑫MFC学习笔记1.Windows应用程序运行机理

    1.MSG结构 hwnd:窗口句柄 message:消息类型 wParam & lParam:消息的附加信息(比如键值) time:消息被投递的时间 tip:typedef的作用是从变量类型区 ...

  3. 关于【error C3646: 未知重写说明符】的若干种可能性

    如果在程序中出现了error C3646,那么这个错误可能是由多种问题所导致的,这篇文章将对多种错误及对应解决方法进行分析. 在MSDN的官方网站中,Complier Error C3646的定义为u ...

  4. Java--Exchanger用于进行线程间的数据交换

    package com; import java.util.concurrent.Exchanger; /** * Created by yangyu on 16/11/28. */ /** * Ex ...

  5. log4j配置文件详解

    在开发中经常会碰到日志,网上关于日志的框架也很多,像log4j.self4j.common-logging等,下面对log4j进行介绍. log4j是java开发的日志框架,具有低侵入的特点,其重点使 ...

  6. Bug管理工具之Mantis_配置篇

    角色管理员.经理.开发人员.修改人员.报告人员.查看人员,权限从大到小递减.分配: My View Settings 'assigned' => '1', 'unassigned' => ...

  7. 性能测试学习之三—— PV->TPS转换模型&TPS波动模型

    PV->TPS转换模型 由上一篇“性能测试学习之二 ——性能测试模型(PV计算模型)“ 得知 TPS = ( (80%*总PV)/(24*60*60*(T/24)))/服务器数量 转换需要注意: ...

  8. 命令行工具解析Crash文件,dSYM文件进行符号化

    备份   文/爱掏蜂窝的熊(简书作者)原文链接:http://www.jianshu.com/p/0b6f5148dab8著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”. 序 在日常开发 ...

  9. jQuery自定义漂亮的下拉框插件8种效果

    jquery美化选择器实例有:边框.下划线. 伸缩 .滑动. 覆盖. 旋转. 弹出层选择 .环形效果. 在线预览 实例代码 <body class="demo-1"> ...

  10. Velocity – 另外一款加速的 jQuery 动画插件

    Velocity 是一款 jQuery 插件,重新实现了 $.animate() 方法,提供更高的性能(比 CSS 动画还更快),同时包括一些新的功能,以改进动画工作流程.Velocity 除了包括所 ...