javascript代码复用模式(三)
前面谈到了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代码复用模式(三)的更多相关文章
- javascript代码复用模式(二)
前面说到,javascript的代码复用模式,可分为类式继承和非类式继承(现代继承).这篇就继续类式继承. 类式继承模式-借用构造函数 使用借用构造函数的方法,可以从子构造函数得到父构造函数传任意数量 ...
- javascript代码复用模式
代码复用有一个著名的原则,是GoF提出的:优先使用对象组合,而不是类继承.在javascript中,并没有类的概念,所以代码的复用,也并不局限于类式继承.javascript中创建对象的方法很多,有构 ...
- 《JavaScript 模式》读书笔记(6)— 代码复用模式2
上一篇讲了最简单的代码复用模式,也是最基础的,我们普遍知道的继承模式,但是这种继承模式却有不少缺点,我们下面再看看其它可以实现继承的模式. 四.类式继承模式#2——借用构造函数 本模式解决了从子构造函 ...
- 《JavaScript模式》第6章 代码复用模式
@by Ruth92(转载请注明出处) 第6章:代码复用模式 GoF 在其著作中提出的有关创建对象的建议原则: -- 优先使用对象组合,而不是类继承. 传统模式:使用类继承: 现代模式:"类 ...
- 深入理解JavaScript系列(46):代码复用模式(推荐篇)
介绍 本文介绍的四种代码复用模式都是最佳实践,推荐大家在编程的过程中使用. 模式1:原型继承 原型继承是让父对象作为子对象的原型,从而达到继承的目的: function object(o) { fun ...
- 深入理解JavaScript系列(45):代码复用模式(避免篇)
介绍 任何编程都提出代码复用,否则话每次开发一个新程序或者写一个新功能都要全新编写的话,那就歇菜了,但是代码复用也是有好要坏,接下来的两篇文章我们将针对代码复用来进行讨论,第一篇文避免篇,指的是要尽量 ...
- javascript代码复用(四)-混入、借用方法和绑定
这篇继续说js的现代复用模式:混入.借用方法和绑定. 混入 可以针对前面提到的通过属性复制实现代码复用的想法进行一个扩展,就是混入(mix-in).混入并不是复制一个完整的对象,而是从多个对象中复制出 ...
- 《JavaScript 模式》读书笔记(6)— 代码复用模式3
我们之前聊了聊基本的继承的概念,也聊了很多在JavaScript中模拟类的方法.这篇文章,我们主要来学习一下现代继承的一些方法. 九.原型继承 下面我们开始讨论一种称之为原型继承(prototype ...
- javascript代码复用--继承
由于javascript没有类的概念,因此无法通过接口继承,只能通过实现继承.实现继承是继承实际的方法,javascript中主要是依靠原型链要实现. 原型链继承 原型链继承是基本的继承模式,其本质是 ...
随机推荐
- 黄聪:360浏览器、Chrome调试(debugger)JS总是进入paused in debugger状态
在通过Chrome浏览器进行web前端开发时,我们会经常用到Chrome自带的debugger工具,但是经常按完快捷键(F12)后,页面会进入paused in debugger状态,需要点击右上角的 ...
- The tag 'ChartPlotter' does not exist in XML namespace
本地build的时候每次都是OK的,但是Shelveset到Server上build的时候,总是出错. 果断google/bing了几个建议,无果. 不得不重新仔细的看server上的building ...
- python (1)一个简单的爬虫: python 在windows下 创建文件夹并写入文件
1.一个简单的爬虫:爬取豆瓣的热门电影的信息 写在前面:如何创建本来存在的文件夹并写入 t_path = "d:/py/inn" #本来不存在inn,先定义路径,然后如果不存在,则 ...
- file_get_content和curl的性能比较
今天在获取微信一张二维码图片时发现使用php中的file_get_content方式和curl方式竟然相差了50倍左右,直接晕倒!!!
- Linq常用操作
http://www.cnblogs.com/knowledgesea/p/3897665.html
- 过滤3个字节以上的utf-8字符
/** * 过滤掉超过3个字节的UTF8字符 * @param text * @return * @throws UnsupportedEncodingException */ public stat ...
- 项目中用到的logback列子
<?xml version="1.0" encoding="UTF-8"?> <configuration> <appender ...
- arm-linux-objcopy
被用来复制一个目标文件的内容到另一个文件中,可用于不同源文件的之间的格式转换示例: arm-linux-objcopy –O binary –S file.elf file.bin 常用的选项(大写) ...
- ORA-30036
http://blog.sina.com.cn/s/blog_676255e101018d5s.html
- c# as
as:用于检查在兼容的引用类型之间执行某些类型的转换. Employee myEmployee = myObject as Employee; if (myEmployee != null) { } ...