前面谈到了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. C# 通过线程来控制进度条(转)--讲解多线程对界面的操作

    // 通过创建委托解决传递参数问题 private void _btnRun_Click( object sender, System.EventArgs e ) { RunTaskDelegate ...

  2. NeHe OpenGL教程 第五课:3D空间

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  3. 设置Excel的自动筛选功能

    单元格数字格式的问题 NPOI向Excel文件中插入数值时,可能会出现数字当作文本的情况(即左上角有个绿色三角),这样单元格的值就无法参与运算.这是因为在SetCellValue设置单元格值的时候使用 ...

  4. Task.Run Vs Task.Factory.StartNew z

    在.Net 4中,Task.Factory.StartNew是启动一个新Task的首选方法.它有很多重载方法,使它在具体使用当中可以非常灵活,通过设置可选参数,可以传递任意状态,取消任务继续执行,甚至 ...

  5. svn: Can't convert string from 'UTF-8' to native encoding 的解决办法

    http://www.leakon.com/archives/610 http://www.toplee.com/blog/566.html http://svnbook.red-bean.com/e ...

  6. MYSQL C API : mysql_init()

    MYSQL * mysql_init(MYSQL *mysql); // 初始化一个MYSQL 连接的实例对象 void mysql_close(MYSQL *sock); // 释放一个MYSQL ...

  7. TFS如何设置在客户端独占签出

    步骤:1.打开源代码管理资源管理器,点击“工作区”的下拉框,选择,“工作区”2.选择编辑3.选择“高级”4.进入编辑工作区,tfs中“位置”选项中,默认的时本地,如果想独占签出,这里我们就必须设置成“ ...

  8. div的contenteditable和placeholder蹦出的火花

    今天在做手机端发布描述内容时,需要实现换行,还需要有plachholder. 在文本框中换行自然想到了textarea. 问题似乎已经解决了,但是当内容发布后,在html中显示换行都丢失了. 这个时候 ...

  9. 破解ckfinder2.3 去除版本号和标题提示

    1.找到ckfinder.js 2.找到这样的字符串 <h4 class='message_content'></h4> 3.改成这样 <h4 style='displa ...

  10. sql server Geometry 类型操作 笔记

    sqlGeometry 类型为sql server 2008之后的版本 新加的一种CLR扩展数据类型,为广大sql server开发人员存储几何类型及空间运算提供极大的便利,下面说明geometry类 ...