前面谈到了javascript的类式继承。这篇继续部分类式继承,及一些现代继承。

类式继承模式-代理构造函数

这种模式通过断开父对象与子对象之间原型之间的直接链接关系,来解决上次说到的共享一个原型所带来的问题,而且同时可以继续原型链带来的好处。

代码:

function inherit(C,P){
var F = function(){};
F.prototype = P.prototype;
C.prototype = new F();
}

可以看到,在这里面有一个空构造函数F(),充当了子对象和父对象之间的一个代理,F()的原型指向父对象的原型。子对象的原型是一个空白函数实例。
这个模式与默认原型继承模式有一些不同,是因为这里的子对象仅继承了原型的属性。这个情况比较理想,也更加可取,因为原型是放置复用功能的位置。在这种模式中,父构造函数添加到this的成员都不会被继承。示意图如下:

可以创建一个子对象:

var kid = new Child();

访问kid.say()时,在上图对象3中没有找到方法,需查询原型链。对象4也没有,对象1中有,可以调用这个方法。
在实际应用中,可以添加一个指向父构造函数原型对象的引用以备使用:

function inherit(C,P){
var F = function(){};
F.prototype = P.prototype;
C.prototype = new F();
C.uber = P.prototype;
}

下面还需要重置构造函数指针,以便使用:

function Parent(){}
function Child(){}
inherit(Child,Parent); 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;
}

这里还可以做的一个优化是避免每次需要继承时都创建代理构造函数,仅创建一次代理函数,并修改它的原型,这个已经可以达到目的了。在具体实现上,可以使用立即调用函数并且在闭包中存储代理函数:

var inherit =  (fucntion(){
var F = function(){};
return function(C,P){
F.prototype = P.prototype;
C.prototype = new F();
C.uber = P.prototype;
C.prototype.constructor = C;
};
})();

现代继承-对象的原型继承

这个是一种无类继承模式,不涉及类,这里的对象都是继承子其它对象。可以用这个方式考虑:有一个想要复用的对象,并且创建的第二个对象要从第一个对象中获取内容。

代码:

var parent = {
name:"Papa"
}; var child = object(parent);
child.name;//"Papa"

parent是以对象字面量方式创建的一个父对象,需要创建一个与parent有相同属性和方法的child对象,其中的object()函数实现如下,与类式继承的代理构造函数类似:

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

下图显示了使用这个模式的原型链。child最初是一个空对象,没有自身的属性,同时又通过_proto_链接而具有父对象的全部功能。

在这个模式中,不需要使用对象字面量来创建父对象,其实也可以使用构造函数创建,如果使用构造函数,自身的属性和构造函数的原型属性都将被继承:

function Person(){
this.name = "Adam";//own property
}
Person.prototype.getName = function(){
return this.name;
};
var papa = new Person();
var kid = object(papa);
kid.getName();//"Adam"

其实可以选择只继承现有构造函数的原型对象,如下:

function Person(){
this.name = "Adam";//own property
}
Person.prototype.getName = function(){
return this.name;
};
var kid = object(Person.prototype);
typeof kid.getName();//function
typeof kid.name;//undefined

在ES5中,原型继承模式已成为该语言的一部分,是通过Object.create()来实现的:

var child = Object.create(parent);

Object.create()接受另外一个参数,可传入一个对象,这个对象的属性将作为新对象的自身属性:

var child = Object.create(parent,{
age:{value:2}
)};
child.hasOwnProperty("age");//true

现代继承-通过复制属性实现继承

下面是extend()的一个例子:

function extend(parent,child){
var i;
child = child||{};
for (i in parent){
if(parent.hasOwnProperty(i)){
child[i] = parent[i];
}
}
return child;
}

使用方法如下:

var dad = {name:"Adam"};
var kid = extend(dad);
kid.name;//"Adam"

上面实现的是浅复制,深复制需要进行属性检查,如果复制的是一个对象或一个数组,在使用浅复制的时候,如果改变了子对象的属性,且该属性是一个对象,父对象也会被修改,这个情况可能会导致意外:

var dad = {
counts:[1,2,3],
reads:{paper:true}
};
var kid = extend(dad);
kid.counts.push(4);
dad.counts.toString();//"1,2,3,4"
dad.reads === kid.reads;//true

实现深复制,需要修改extend(),判断每个属性是对象还是数组:

function extendDeep(parent,child){
var i,
toStr = Object.prototype.toString,
astr = "[object Array]";
child = child||{};
for (i in parent){
if(parent.hasOwnProperty(i)){
if(typeof parent[i] === "object"){
child[i] = (toStr.call(parent[i]) === astr?) [] : {};
extendDeep(parent[i],child[i]);
}else{
child[i] = parent[i];
}
}
}
return child;
}

测试:

var dad = {
counts:[1,2,3],
reads:{paper:true}
};
var kid = extendDeep(dad);
kid.counts.push(4);
kid.counts.toString();//"1,2,3,4"
dad.counts.toString();//"1,2,3" dad.reads === kid.reads;//false
kid.reads.paper = false;
dad.reads.paper;//true

这种模式应用广泛,例如FireBug有一个extend()方法可以实现浅复制,Jquery中的extend()可以实现深复制。

javascript代码复用模式(三)的更多相关文章

  1. javascript代码复用模式(二)

    前面说到,javascript的代码复用模式,可分为类式继承和非类式继承(现代继承).这篇就继续类式继承. 类式继承模式-借用构造函数 使用借用构造函数的方法,可以从子构造函数得到父构造函数传任意数量 ...

  2. javascript代码复用模式

    代码复用有一个著名的原则,是GoF提出的:优先使用对象组合,而不是类继承.在javascript中,并没有类的概念,所以代码的复用,也并不局限于类式继承.javascript中创建对象的方法很多,有构 ...

  3. 《JavaScript 模式》读书笔记(6)— 代码复用模式2

    上一篇讲了最简单的代码复用模式,也是最基础的,我们普遍知道的继承模式,但是这种继承模式却有不少缺点,我们下面再看看其它可以实现继承的模式. 四.类式继承模式#2——借用构造函数 本模式解决了从子构造函 ...

  4. 《JavaScript模式》第6章 代码复用模式

    @by Ruth92(转载请注明出处) 第6章:代码复用模式 GoF 在其著作中提出的有关创建对象的建议原则: -- 优先使用对象组合,而不是类继承. 传统模式:使用类继承: 现代模式:"类 ...

  5. 深入理解JavaScript系列(46):代码复用模式(推荐篇)

    介绍 本文介绍的四种代码复用模式都是最佳实践,推荐大家在编程的过程中使用. 模式1:原型继承 原型继承是让父对象作为子对象的原型,从而达到继承的目的: function object(o) { fun ...

  6. 深入理解JavaScript系列(45):代码复用模式(避免篇)

    介绍 任何编程都提出代码复用,否则话每次开发一个新程序或者写一个新功能都要全新编写的话,那就歇菜了,但是代码复用也是有好要坏,接下来的两篇文章我们将针对代码复用来进行讨论,第一篇文避免篇,指的是要尽量 ...

  7. javascript代码复用(四)-混入、借用方法和绑定

    这篇继续说js的现代复用模式:混入.借用方法和绑定. 混入 可以针对前面提到的通过属性复制实现代码复用的想法进行一个扩展,就是混入(mix-in).混入并不是复制一个完整的对象,而是从多个对象中复制出 ...

  8. 《JavaScript 模式》读书笔记(6)— 代码复用模式3

    我们之前聊了聊基本的继承的概念,也聊了很多在JavaScript中模拟类的方法.这篇文章,我们主要来学习一下现代继承的一些方法. 九.原型继承 下面我们开始讨论一种称之为原型继承(prototype ...

  9. javascript代码复用--继承

    由于javascript没有类的概念,因此无法通过接口继承,只能通过实现继承.实现继承是继承实际的方法,javascript中主要是依靠原型链要实现. 原型链继承 原型链继承是基本的继承模式,其本质是 ...

随机推荐

  1. 常​用​的​邮​箱​服​务​器​(​S​M​T​P​、​P​O​P​3​)​地​址​、​端​口

    常用的邮箱服务器(SMTP.POP3)地址.端口 gmail(google.com)  POP3服务器地址:pop.gmail.com(SSL启用 端口:995)  SMTP服务器地址:smtp.gm ...

  2. TCP非阻塞通信

    一.SelectableChannel SelectableChannel支持阻塞和非阻塞模式的channel 非阻塞模式下的SelectableChannel,读写不会阻塞 SelectableCh ...

  3. Workflow_工作流发送Document和Form链接的实现(案例)

    2014-06-01 Created By BaoXinjian

  4. python--输入一组无序的数,排序

    N=int(raw_input('input the number N=')) number=[] while(N): m=int(raw_input('input..\n')) number.app ...

  5. C++模板元编程 - 3 逻辑结构,递归,一点列表的零碎,一点SFINAE

    本来想把scanr,foldr什么的都写了的,一想太麻烦了,就算了,模板元编程差不多也该结束了,离开学还有10天,之前几天部门还要纳新什么的,写不了几天代码了,所以赶紧把这个结束掉,明天继续抄轮子叔的 ...

  6. LPC1768之ISP

    一 使用到的芯片内部资源: 1必须是P2.10 2RESET引脚 3必须是串口0 4使用FLASH magic工具. 二操作方法: 先按下reset不放,然后按下ISP,抬起reset,抬起ISP就能 ...

  7. iOS 程序打包,安装流程

    一.发布测试,是指将你的程序给   * 你的测试人员,因为程序总归是要测试的   * 你的客户,在正式发布之前,客户肯定是要先看(验收)的 在他们的iOS设备(iphone,ipod, ipad)安装 ...

  8. sqlldr导入数据

    直接在cmd输入sqlldr即可,不需要先输sqlplus. 参考链接:每次提交多少行很重要:http://www.cnblogs.com/wingsless/archive/2012/08/04/2 ...

  9. sublimetext3 安装php语法检测

    打开控制台,install package 搜 sublimelinter 先安装sublimelinter本体 安装完以后再搜索一下,安装sublimelinter-php 接下来,打开prefer ...

  10. angularjs ng-select ng-options 默认选中项.

    <!DOCTYPE html> <html ng-app="myApp"> <head> <meta charset="utf- ...