javascript代码复用模式(二)

前面说到,javascript的代码复用模式,可分为类式继承和非类式继承(现代继承)。这篇就继续类式继承。

类式继承模式-借用构造函数

使用借用构造函数的方法,可以从子构造函数得到父构造函数传任意数量的参数。这个模式借用了父构造函数,它传递子对象以绑定到this,并转发任意数量的参数:

function Child(a,b,c,d){
    Parent.apply(this,arguments);
}

在这种方式中,只能继承在父构造函数中添加到this的属性,并不能继承添加到原型中的成员。

使用借用函数构造模式的时候,子对象获得了继承成员的副本,这个与默认原型继承中的仅获取引用的方式是不同的。可以参考下面的例子:

funciton Article(){
    this.tags = [‘js‘,‘css‘];
}
var article = new Article();
function BlogPost(){
}
BlogPost.prototype = article;
var blog = new BlogPost();

function StaticPage(){
    Article.call(this);
}
var page = new StaticPage();

console.log(article.hasOwnProperty(‘tags‘));//true
console.log(blog.hasOwnProperty(‘tags‘));//false
console,log(page.hasOwnProperty(‘tags‘));//true

上面用两种方式继承了Article(),默认原型模式导致blog对象通过原型来获得他对tags属性的访问,所以blog对象没有将article作为自身的属性,所以当调用hasOwnProperty()时会返回false.而page对象本身具有一个tags属性,是因为他在调用父构造函数时,新对象会获得父对象中tags成员的副本,而不是引用。
可以通过下面的代码看到这个差异:

blog.tags.push(‘html‘);
page.tag.push(‘php‘);
console.log(article.tags.join(‘,‘));//"js,css,html"

上面代码中,子对象blog修改了其tags属性,而这种方式也会修改父对象article,因为本质上blog.tags和article.tags指向了同一个数组,但修改page的tags不会影响父对象article,是由于在继承过程中page.tags是独立创建的一个副本。
关于原型链的工作流程:

function Parent(name){
    this.name = name||"Adam";
}
Parent.prototype.say = {
    return this.name;
};
function Child(name){
    Parent.apply(this,arguments);
}
var kid = new Child("Patrick");
console.log(kid.name);//"Patric"
console.log(typeof kid.say);//undefined 

上面代码里面没有使用Child.prototype,它只是指向一个空对象,借用父构造函数时,kid获得了自身属性name,没有继承过say()方法。继承是一次性完成的,仅会复制父对象的属性并将其作为自身的属性,所以也不会保留_proto_链接。

使用借用构造函数时,可以通过借用多个构造函数实现多重继承:

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);

运行结果:

    fly        true
    legs       4
    wings      2
    say        function()

借用构造函数的缺点,很明显,不能从原型中继承任何属性和方法,如上面Parent和Child的例子。对于父构造函数上使用this定义的方法也会创建多个副本。优点可以获得父对象自身成员的真实副本,不会存在子对象覆盖父对象的风险,可以传参数,可以多重继承。

类式继承模式-借用和设置原型

这个模式就是结合前面两种,先借用构造函数,也设置子构造函数的原型使其指向一个构造函数创建的实例。代码如下:

function Child(a,b,c,d){
    Parent.apply(this,arguments);
}
Child.prototype = new Parent();

这样的优点,是代码运行后的结果对象能够获得父对象本身的成员副本以及指向父对象中可复用功能(以原型方式实现的功能),同时,子对象也可以将任意参数传递到父构造函数中,
这个是最接近Java或者C#的实现方式。可以继承父对象的一切,同时也可以安全的修改自身的属性,不会带来修改父对象的风险。

这样的缺点,是父构造函数被调用了两次,这会导致效率低下,自身的属性会被继承两次,如下面的name:

function Parent(name){
    this.name = name||"Adam";
}
Parent.prototype.say = {
    return this.name;
};
function Child(name){
    Parent.apply(this,arguments);
}
Child.prototype = new Parent();
var kid = new Child("Patrick");
kid.name;//"Patrick"
kid.say();//"Patrick"
delete kid.name;
kid.say();//"Adam"

上面代码中。say()被继承了。可以看到,name属性被继承了两次,在删除了kid本身的name属性的副本之后,可以看到输出的是原型链所引出的name.
原型链示意图:

类式继承模式-共享原型

和前面的模式需要调用两次父构造函数不同,下面的模式不涉及调用父构造函数。

这个模式的法则在于,可复用成员应该转移到原型中而不是放在this中,所以,出于继承的目的,任何需要继承的属性和方法都应该放在原型中,所以可以仅将子对象的原型和父对象的设置成相同。代码如下:

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

这种模式可以提供简短而迅速的原型链查询,这是因为所有的对象实际上共享了一个原型。但这也同时是一个缺点,因为如果在继承链下方的某处存在的一个子对象中修改了原型,他会影响到所有父对象和祖先对象。
如下图,下面的子对象和父对象共享了同一个原型,并且可以同等访问say()方法,但子对象没有继承name属性。

时间: 2024-12-23 15:43:29

javascript代码复用模式(二)的相关文章

javascript代码复用模式

原文链接:http://www.faceye.net/search/143351.html 代码复用有一个著名的原则,是GoF提出的:优先使用对象组合,而不是类继承.在中,并没有类的概念,所以代码的复用,也并不局限于类式继承.javascript中创建对象的方法很多,有构造函数,可以使用new创建对象,并且可以动态的修改对象.javascript的非类式继承(可称为现代继承模式)复用方法也很多,例如,利用其它对象组合成所需要的对象,对象混入技术,借用和复用所需要的方法. 类式继承模式-默认模式

javascript代码复用模式(三)

前面谈到了javascript的类式继承.这篇继续部分类式继承,及一些现代继承. 类式继承模式-代理构造函数 这种模式通过断开父对象与子对象之间原型之间的直接链接关系,来解决上次说到的共享一个原型所带来的问题,而且同时可以继续原型链带来的好处. 代码: function inherit(C,P){ var F = function(){}; F.prototype = P.prototype; C.prototype = new F(); } 可以看到,在这里面有一个空构造函数F(),充当了子对

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

介绍 本文介绍的四种代码复用模式都是最佳实践,推荐大家在编程的过程中使用. 模式1:原型继承 原型继承是让父对象作为子对象的原型,从而达到继承的目的: function object(o) { function F() { } F.prototype = o; return new F(); } // 要继承的父对象 var parent = { name: "Papa" }; // 新对象 var child = object(parent); // 测试 console.log(c

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

介绍 任何编程都提出代码复用,否则话每次开发一个新程序或者写一个新功能都要全新编写的话,那就歇菜了,但是代码复用也是有好要坏,接下来的两篇文章我们将针对代码复用来进行讨论,第一篇文避免篇,指的是要尽量避免使用这些模式,因为或多或少有带来一些问题:第二排是推荐篇,指的是推荐大家使用的模式,一般不会有什么问题. 模式1:默认模式 代码复用大家常用的默认模式,往往是有问题的,该模式使用Parent()的构造函数创建一个对象,并且将该对象赋值给Child()的原型.我们看一下代码: function i

JavaScript模式读书笔记 第6章 代码复用模式

主要使用代码继承来完成复用. 1,使用类式继承. -1,类式继承:按照类的方式来实现继承,即所谓的类式. -2,类式继承:通过构造函数(child)获取来自parent的属性,从而创建对象. <script> //parent function Parent(name){ this.name = name || 'Adam'; } Parent.prototype.say = function(){   return this.name; } //child function Child(na

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

这篇继续说js的现代复用模式:混入.借用方法和绑定. 混入 可以针对前面提到的通过属性复制实现代码复用的想法进行一个扩展,就是混入(mix-in).混入并不是复制一个完整的对象,而是从多个对象中复制出任意的成员并将这些成员组合成一个新的对象. 混入的实现并不难,只需要遍历每个参数,并且复制出传递给这个函数的每个对象中的每个属性. function mix(){ var arg,prop,child={}; for(arg=0:arg<arguments.length;arg++){ for(ar

Atitit 代码复用的理解attilax总结

1.1. 继承1 1.1.1. 模式1:原型继承1 1.1.2. 模式2:复制所有属性进行继承 拷贝继承1 1.1.3. 模式3:混合(mix-in)1 1.1.4. 模式4:借用方法1 1.2. 组合2 1.3. API提供了一种代码复用的机制.2 1.4. 类库机制2 1.5. Include import2 1.6. Cfg2 1.7. 良好的复用和不良的复用2 1.8. 可复用组件的 5 种类型  代码块 Code Block算法 模式   数据类型 库3 1.9. 2. 算法 Algo

javascript-代码复用模式

代码复用模式 1)使用原型继承 函数对象中自身声明的方法和属性与prototype声名的对象有什么不同: 自身声明的方法和属性是静态的, 也就是说你在声明后,试图再去增加新的方法或者修改已有的方法, 并不会由其创建的对象产生影响,也即继承失败. 而prototype可以动态地增加新的方法或者修改已有的方法, 从而是动态的,一旦父函数对象声明了相关的prototype属性,由其创建的对象会自动继承这些prototype的属性. 既然有函数对象本身的属性, 也有prototype的属性, 那么是由其

【转】使用Jasob混淆javascript代码

在平常的web开发中,我们时常需要写一些js的类库,当我们发布自己产品的时候,不得不把源代码分发出去:但是这样就会泄露自己的代码.今天使用了一下Jasob感觉不错: 使用Jasob,我们的JavaScript代码无法被任何人理解从而杜绝剽窃和泄密,别人再也不能在我们的代码上做点修改就成了他的作品了.使用Jasob混淆以后,JavaScript的代码大小将缩小为原来的30%,因此浏览器将用更短的时间下载并执行网页代码. Jasob分析JavaScript的代码并替换掉描述性的变量和函数名称,例如客