美文网首页
瞎扯.javascript面向对象

瞎扯.javascript面向对象

作者: leleHappy | 来源:发表于2015-04-06 22:02 被阅读100次

    已经忘了多久没拿起javascirpt的书本了,无聊中拾起快被我遗忘在角落的书本<javascript高级程序设计>。

    尼古拉斯竟然把这么奇葩的js面向对象说的这么好

    从最原始的工厂模板说起

    function createPerson(name,age){

     var o = new Object();

     o.name = name;

     o.age = age;

    o.sayName = function(){

      console.log(this.name);

    }

     return o;

    }

    这样,but...等等,如何知道创建的对象是什么类型的?

    构造函数模式

    function Person(name,age){

    this.name = name;

    this.age = age;

    this.sayName = function(){

    }

    var person1 = new Person("三毛",25);

    简洁了不少,问题又来了:难道我每次new一个对象,就要重新创建个sayName函数吗?为什么这么说?

    函数也是对象,每次实例化Person时,都会实例化一个sayName Function。也就是说:每个Person的示例,都有一个不同的sayName Function实例。何必如此?

    理解原型模式

    原型模式很好的解决了上述问题,这么说吧,每个function都有一个prototype属性(我们叫原型),指向一个原型对象。

    所以,我们可以把公共的方法属性都加到它上面。

    function Person(){

    }

    Person.prototype.name = "三毛";

    Person.prototype.age = 25;

    Person.prototype.sayName = function(){

     console.log(this.name);

    }

    把属性方法加到了函数的prototype(实际上也是个对象)上,后续创建的实例对象都从这个原型对象上继承了属性和方法。

    然而,它也不是完美的。原型对象的问题也是显而易见的:由于所有的实例都是共享原型对象的方法属性,那么意思就是说所有的实例共享了一份属性方法!那创建的实例还有个毛用?

    联想到前面我们提过的构造函数模式,我们可以把构造函数+原型模式结合起来。

    构造函数负责自有的属性,而原型对象负责公共的方法,一种新的模式应运而生:

    组合模式

    Person.prototype.sayName = function(){

    console.log(this.name);

    }

    完美解决了构造函数模式和原型模式的问题。

    再谈谈javascript继承

    在“理解原型模式”中,已经谈到了js的原型模式,而js的继承就是依靠原型链来实现的。

    js原型链

    我们来简单回顾下前面讲过的内容:

    1 每个构造函数都有一个原型对象;

    2 原型对象包含一个指向构造函数的指针(证明自己是从哪来的);

    3 构造函数的实例(这么说可能有点不准确)包含一个指向原型对象的指针。

    有点晕,感觉有点像三角恋,看个实例:

    function SuperType(){

    this.property = true;

    }

    SuperType.prototype.getSuperValue = function(){

     return this.property;

    }

    function SubType(){

     this.subproperty = false;

    }

    //继承,使SubType的原型指向SuperType的原型

    SubType.prototype = new SuperType();

    SubType.prototype.getSubValue = function(){

     return this.subproperty;

    }

    var instance = new SubType();

    console.log(instance.getSuperValue());//true,实际上是SuperType的值

    看以看出,单独使用原型链实现继承,实际上生成的实例都是共享一份属性或者方法的。

    那么,实例就没有意义了。

    那如果借用构造函数呢?

    我们知道,构造函数只能实现对实例属性的继承,没办法实现方法的继承,所以如果单独使用构造函数模式,方法就需要都写在构造函数里面,函数复用就无从谈起了。

    组合继承

    组合继承借用了原型链实现原型属性和方法的继承,又可以通过构造函数实现实例属性的继承。可以说既实现了函数复用,又保证每个实例都有自己的属性。

    function SuperType(name){

     this.name = name;

     this.colors = ["red", "blue"];

    }

    SuperType.prototype.sayName = function(){

     console.log(this.name);

    }

    function SubType(name,age){

     SuperType.call(this,name);//在当前实例环境下执行SuperType构造函数->2

     this.age = age;

    }

    SubType.prototype = new SuperType();//->1

    SubType.prototype.sayAge = function(){

     console.log(this.age);

    }

    看以看到,这种模式结合了两者的优点,又弥补了相互的不足。可以说,是一种不错的用于实现继承的方法。

    但是,这种方法并不是最好的,我们来详细看一下:

    1 为了实现继承,第一点调用了SuperType的构造函数,这样SubType.prototype继承了两个属性

    2 SubType构造函数内部,又调用了一次SubType构造函数,显得有些多余了

    寄生组合继承

    通过借用构造函数来继承属性,通过原型链来继承方法。

    function object(super){

     var func = function(){};

     func.prototype = super;

     var o = new func();

     return o;

    }

    function inheritPrototype(sub,super){

     var prototype = object(super.prototype);

     prototype.constructor = sub;

     sub.prototype = prototype;

    }

    这是寄生组合继承的简单形式。

    通过接受子构造函数和父构造函数,第一步创建父类型原型的一个副本;

    第二步为副本添加constructor属性,最后再把新的原型赋给子原型,完美实现了继承关系。

    相关文章

      网友评论

          本文标题:瞎扯.javascript面向对象

          本文链接:https://www.haomeiwen.com/subject/doczxttx.html