Javascript Patterns--读书笔记6 (Code Reuse)

提到代码重用,我们往往会想到inherits,当然还有其它的方式 ,我们还可以通过compoite来达到代码重用的目的。不过,当我们在试图实现代码重用的时候,请记住“Prefer object composition to class inheritance"

Classical Versus Modern Inheritance Patterns

在JS中什么是Classical继承呢,这个命名方式不是通用的。所表达的意思其实就是别的语言中的类继承。因为在JS中不存在类这个概念,我们可以随时改变它的属性和方法,而不必像其他语言那样麻烦。
在JS中,有constructor,还有可以用new来产生一个新的对象实例。我们首先定义一个constructor function,然后再new一下,是不是和JAVA, C#中的用类来生成object非常类似。所以这种方式就称为"classical" inherits, 而modern的继承方式就是指,我们不需要通过这种方式来实现的代码重用。 

继承的目的就是当我们在实现一个子类对象的时候,我们希望这个子类对象可以继承父类的所有属性和方法。

View Code
//the parent construcotr

function Parent(name){

    this.name = name || 'Adam';

}



//adding functionality to the prototype

Parent.prototype.say = function() {

    return this.name;

}



//empty child construcotr

function Child(name) {}



//inhertiance ,我们将会在后面来实现 

inherit(Child, Parent);

Classica Pattern #1 -- The Default Pattern

我们将最常用的方式就是我们把子类的prototype来设置成Parent()的一个实例。
function inherit(C, P) {
C.prototype = new P();
}

结合着上面的代码在前一个例子中,我们可以得到如下结果
var kid = new Child();
kid.say(); //"Adam"

Prototype Chain
当我们用prototype来实现继承的时候,我们不但会继承你类所有的属性和方法,还包括它的prototype的所有的属性和方法。
那这种机制如何来实现的,当们来创建一个new Parent()的时候,实际上我们创建了如下的一个对象(注意__proto__并不是一个标准属性,我们只是借用来示例一下)
new Parent();
name = Adam
__proto__ ---> Parent.prototype
say()
而当我们试图来访问say()时,请注意,现在我们的对象中并不含有这个方法,所以现在就会用到那个隐含的对象,__proto__它指向的是一个Parent()函数的prototype对象。
现在让我们来看一下new Child()的时候发生了什么:

new Child()
__proto__ ----> new Parent()
name = Adama
__proto__ ---> Parent.prototype
say()
Child() construcotr是空的,没有任何的属性,当我们试图用kid.say的时候,它会首先检查自己是不是有这个方法,没有,它会查找它的prototype,而它的prototype在检查的时候,它会去检查它的__proto__指向的prototype.

Classical Pattern #2 ---Rent-a-Constructor
看下面的代码:
function Child(a,c,b,d) {
Parent.apply(this, arguments);
}
通过这种方式,子类只会继承那些通过this添加的属性和方法,它不会继承那些添加到prototype对象中的那些属性。使用这种方式,子对象将会把那些属性全部复制到这个对象上,而不像使用prototype继承那样得到的仅仅是一个引用。

View Code
//a parent constructor

function Article() {

    this.tags = ['js', 'css'];    

}

var article = new Article();



//a blog post inhertis from an article object

//via the prototype

function BlogPost() {

    BlogPost.prototype = article;

    var blog = new BlogPost();

    //a staic page inhertis from the article

    //via the rented constructor pattern

    function StaicPage() {

        Article.call(this);

    }

    

    var page = new StaticPage();

    alert(article.hasOwnProperty('tags'));//true

    alert(blog.hasOwnProperty('tags'));//false

    alert(Page.hasOwnProperty('tags'));//true;

    //当我们改变tags的时候

    blog.tags.push('html');

    page.tags.push('php');

    alert(article.tags.join(','));//"js,css, html"    

}

Multiple Inheritance by Borrowing Constructors

View Code
function Cat() {

    this.tags = 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, lengs 4, wings 2, say function()

Classical Pattern #3 --Rent and Set Prototype
function Child(a,c,b,d) {
Parent.apply(this, arguments);
}
Child.prototype = new Parent();
这种模式的好处在于,它会复制父类的那些私有属性,还可以引用那些父类重用的代码


Classical Pattern #4 --Share the Prototype
function inherit(C,P) {
C.prototype = P.prototypel;
}

Classical Pattern #5 ---A Temporary Constructor
function inherit(C, P) {
var F= function() {};
F.prototype = P.prototype;
C.prototype = new F();
}

重设构造函数

为何要重设构造函数

View Code
function Parent() {}

function Child(){}

inherit(Child, Parent);



var kid = new Child();

kid.constructor.name;//"Parent"

kid.constructor === Parent;//true

在上面的代码中,我们可以看到当我们通过继承来生成一个子类的实例时,发现其中的construcotr被重写了,究其根源是因为,我们在设置prototype的时候,并没有重设constructor,因为constructor是prototype的一个属性,所以我们当通过重写prototype来实现继承时,一定要记住重写prototype的construcotr函数,请看下面修正好的结果:

function inherit(C,P){

  var F = function(){};

  F.prototype = P.prototype;

  C.prototype = new F();

  C.uber = P.prototype;

  C.protoype.constructor = C;



}

Klass

让我们来看一个实现的例子:

View Code
var klass = function(Parent, props) {

  var Child, F, i;

  //new constructor

  Child = function() {

      if(Child.uber && Child.uber.hasOwnProperty("__construct")){

      Child.uber.__construct.apply(this, arguments);

    }



    if(Child.prototype.hasOwnProperty("__construct")){

      Child.protoype.__construct.apply(this, arguments);

    }

}



//inherit

Parent = Parent || Object;

F = function() {}

F.prototype = Parent.prototype;

Child.prototype = new F();

Child.uber = Parent.prototype;

Child.prototype.constructor = Child;



//add implementation methods

for(i in props){

  if(props.hasOwnProperty(i)){

    Child.protoype[i] = props[i];

  }

}

return Child;

};

Prototypal Inheritance

所谓的modern继承模式,就是不再有class出现。我们直接继承自其他的对象。你可以这样来想象一下,你有一个object,然后你想再创建一个对象,然后新建对象重用上一个对象的所有方法:

 View Code

通过copy属性来完成继承 

View Code
function extend(parent, child) {

  var i;

  child = child || {};

  for(i in parent) {

    child[i] = parent[i];

  }

}



var dad = {name: "Adam"};

var kid = extend(dad);

kid.name;//"Adam"

 

你可能感兴趣的:(JavaScript)