您的位置:首页 > Web前端 > JavaScript

JavaScript代码复用模式

2015-09-22 15:48 423 查看
转自:http://segmentfault.com/a/1190000000762220

代码复用及其原则

代码复用
,顾名思义就是对曾经编写过的代码的一部分甚至全部重新加以利用,从而构建新的程序。在谈及代码复用的时候,我们首先可以想到的是
继承性
。代码复用的原则是:

优先使用对象组合,而不是类继承

在js中,由于没有类的概念,因此实例的概念也就没多大意义,js中的对象是简单的键-值对,可以动态的创建和修改它们。

但在
js
中,我们可以使用构造函数和
new
操作符来实例化一个对象,这与其他使用类的编程语言在语法上有其相似之处。

例如:

var trigkit4 = new Person();

js
在调用构造函数
Person
时似乎看起来是一个类,但其实际上仍然是一个函数,这让我们产生了一些假定在类的基础上的开发思路和继承模式,我们可以称之为“类式继承模式”。

传统的继承模式是需要
class
关键字的,我们假定以上的类式继承模式为
现代继承模式
,这是一种不需要以类的方式考虑的模式。

类式继承模式

看下面两个构造函数
Parent()
Child()
的例子:

<script type="text/javascript">
function Parent(name){
this.name = name || 'Allen';
}

Parent.prototype.say = function(){
return this.name;
}

function Child(name){}

//用Parent构造函数创建一个对象,并将该对象赋值给Child原型以实现继承
function inherit(C,P){
C.prototype = new P();//原型属性应该指向一个对象,而不是函数
}

//调用声明的继承函数
inherit(Child,Parent);
</script>

当使用
new Child()
语句创建一个对象时,它会通过原型从
Parent()
实例获取它的功能,比如:

var kid = new Child();
kid.say();//Allen

原型链

讨论一下类式继承模式下原型链的工作原理,我们将对象看做是内存中某处的块,该内存块包含数据以及指向其他块的引用。当用
new Parent()
语句创建一个对象时,就会创建如下图左边的这样一个块,这个块保存了
name
属性,如果想访问
say()
方法,我们可以通过指向构造函数
Parent()
prototype
(原型)属性的隐式链接
__proto__
,便可访问右边区块
Parent.prototype




那么,当使用
var kid = new Child()
创建新对象时会发生什么?如下图:



使用
new Child()
语句所创建的对象除了隐式链接
__proto__
外,它几乎是空的。这种情况下,
__proto__
指向了在
inherit()
函数中使用
new Parent()
语句所创建的对象

当执行
kid.say()
时,由于最左下角的区块对象并没有
say()
方法,因此他将通过原型链查询中间的区块对象,然而,中间的区块对象也没有
say()
方法,因此他又顺着原型链查询到最右边的区块对象,而该对象正好有
say()
方法。完了吗?

执行到这里的时候并没有完,在
say()
方法中引用了
this.name
,this指向构造函数所创建的对象,在这里,它指向了
new Child()
这个区块,然而,
new Child()
中并没有
name
属性,为此,将查询中间区块,而中间区块正好有
name
属性,至此,原型链的查询完毕。

更详细的讨论请查看我这篇文章:JavaScript学习总结(五)原型和原型链详解

共享原型

本模式的法则在于:可复用的成员应该转移到原型中而不是放置在this中。因此,处于继承的目的,任何值得继承的东西都应该放在原型中实现。所以,可以将子对象的原型与父对象的原型设置为相同即可,如下示例所示:

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




子对象和父对象共享同一个原型,并且可以同等的访问
say()
方法。然而,子对象并没有继承
name
属性

原型继承

原型继承是一种“现代”无类继承模式。看如下实例:

<script type="text/javascript">
//要继承的对象
var parent = {
name : "Jack"  //这里不能有分号哦
};

//新对象
var child = Object(parent);

alert(child.name);//Jack
</script>

在原型模式中,并不需要使用对象字面量来创建父对象。如下代码所示,可以使用构造函数来创建父对象,这样做的话,自身的属性和构造函数的原型的属性都将被继承。

<script type="text/javascript">
//父构造函数
function Person(){
this.name = "trigkit4";
}
//添加到原型的属性
Person.prototype.getName = function(){
return this.name;
};

//创建一个新的Person类对象
var obj = new Person();

//继承
var kid = Object(obj);

alert(kid.getName());//trigkit4
</script>

本模式中,可以选择仅继承现有构造函数的原型对象。对象继承自对象,而不论父对象是如何创建的,如下实例:

<script type="text/javascript">
//父构造函数
function Person(){
this.name = "trigkit4";
}
//添加到原型的属性
Person.prototype.getName = function(){
return this.name;
};

//创建一个新的Person类对象
var obj = new Person();

//继承
var kid = Object(Person.prototype);

console.log(typeof kid.getName);//function,因为它在原型中
console.log(typeof kid.name);//undefined,因为只有该原型是继承的
</script>

继承一个对象的功能

使用构造函数链的概念和Function.apply()方法,来模拟js中传统的类继承行为:

<script>
function oldObject(param1){
this.param1 =param1;
this.getParam = function () {
return this.param1;
}
}

function newObject(param1,param2){
this.param2 =param2;
this.getParam2 = function () {
return this.param2;
};
oldObject.apply(this,arguments);
this.getAllParams = function () {
return this.getParam() + "" + this.getParam2();
}
}

window.onload = function () {
newObject.prototype = new oldObject();
var obj = new newObject("value1","value2");
//打印出两个参数
alert(obj.getAllParams());
};
</script>

首先,在
newObject
的构造函数中,在
oldObject
上调用一个
apply
方法,传入对新的对象的引用和参数数组。
apply
方法继承自
Function
对象

newObject.prototype = new oldObject();

这是
js
中构造函数链的一个示例。当创建一个
newObject
的新实例的时候,
newObject
以这样一种方式继承了旧对象的方法和属性。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: