我的学习笔记是根据我的学习情况来定期更新的,预计 2-3 天更新一章,主要是给大家分享一下,我所学到的知识,如果有什么错误请在评论中指点出来,我一定虚心接受,那么废话不多说开始我们今天的学习分享吧!
上回我们说到组合继承在使用构造函数继承时继承了一遍父类构造函数,在实现子类原型的类式继承时又调用了一遍父类构造函数。因此父类构造函数调用了两遍,并不算最优的继承方式,下面我们再来介绍更好的方式。
首先我们声明一个对象
- function proObject(o) {
- //声明一个过渡函数对象
- function Obj() {}
- //过渡对象的原型继承父对象
- Obj.prototype = o;
- //返回过渡对象的一个实例,该实例的原型继承了父对象
- return new Obj();
- }
是不是觉得这种方式和我们之前讲到的类式继承很相似,的确原型式继承是对类式继承的一个封装,其中的过渡对象就相当于类式继承中的子类,过渡的意义主要是想返回一个新的实例化对象。
Object.create() 方法就是原型式继承。
那么类式继承的那些缺点是否也会在原型式继承中提现出来呢?答案是肯定的,我们来看看下面的例子
- var Students = {
- admissionTime: "2017",
- hobby: ["唱歌", "画画"]
- };
- var student1 = proObject(Students);
- student1.admissionTime = "2016";
- student1.hobby.push("游泳");
- var student2 = proObject(Students);
- student2.admissionTime = "2015";
- student2.hobby.push("看书");
接着我们把结果打印出来看看
- console.log(student1.admissionTime);//2016
- console.log(student1.hobby);//["唱歌","画画","游泳","看书"]
- console.log(student2.admissionTime);//2015
- console.log(student2.hobby);//["唱歌","画画","游泳","看书"]
- console.log(Students.admissionTime);//2017
- console.log(Students.hobby);//["唱歌","画画","游泳","看书"]
还是和之前的类式继承一样值类型的属性被复制,引用类型的属性被共用了。所以在原型式继承的基础上做了些增强出现了下面的继承方式。
寄生式继承其实就是对原型式继承的第二次封装,并且在第二次封装过程中对继承的对象进行了拓展,这样新创建的对象不仅仅有父类中的睡醒和方法,而且还添加了新的属性和方法。
首先我们先声明基类对象
- var Students = {};
- function CreateStu(obj) {
- //通过原型式继承方式创建新对象
- var stu = proObject(obj);
- //扩展新对象
- stu.getAdmissionTime = function() {
- console.log(stu.admissionTime);
- };
- //返回拓展后的新对象
- return stu;
- }
- var student1 = CreateStu(Students);
- student1.admissionTime = "2016";
- student1.hobby.push("游泳");
- var student2 = CreateStu(Students);
- student2.admissionTime = "2015";
- student2.hobby.push("看书");
接着我们把结果打印出来看看
- student1.getAdmissionTime(); //2016
- console.log(student1.hobby); //["唱歌","画画","游泳","看书"]
- student2.getAdmissionTime(); //2015
- console.log(student2.hobby); //["唱歌","画画","游泳","看书"]
这种类型的继承就跟他的名字一样,像寄生虫一样寄托于某个对象内部生长,当然这种思想是为了我们接下来的继承模式的实现
我们之前讲到的组合式继承,是将类式继承和构造函数继承组合使用,但这种方式有个问题,父类构造函数调用了两遍而且子类不是父类的实例,子类的原型才是父类的实例,所以才有了我们现在讲到的寄生组合式继承。
那么寄生组合式继承又是哪两种模式的组合呢?
由名字我们可以看出,寄生当然是指寄生式继承而寄生式继承又依托于原型式继承,我们之前讲到原型式继承和类式继承相似,所以另一种继承模式就是构造函数继承。
寄生式继承有些特殊,他处理的不是对象,而是类的原型。
下面我们来看一下具体的实现步骤
- function parasiticType(ParentClass, ChildClass) {
- //复制一份父类的原型保存在变量中
- var parent = proObject(ParentClass.prototype);
- //修正因为重写子类原型导致子类的constructor属性被修改
- parent.constructor = ChildClass;
- //设置子类的原型
- ChildClass.prototype = parent;
- }
组合式继承中,通过构造函数继承的属性和方法是没有问题的,所以这里我们主要探究通过寄生式继承重新继承父类的原型。
我们需要继承的仅仅是父类的原型,不再需要调用父类的构造函数。
所以我们需要的其实就只有父类原型对象的副本,而这个副本我们可以通过原型式继承得到,但是我们直接赋值给子类会有问题的,因为对父类原型对象复制得到的复制对象 parent 中的 constructor 指向的不是 ChildClass 子类对象,
因此在寄生式继承中,我们要对复制对象 parent 做一次增强,修复器 constructor 属性指向不正确的问题,最后我们将得到的复制对象 P 赋值给子类的原型,这样子类的原型就继承了类的原型并且没有执行父类的构造函数。
constructor 是一个属性,当创建一个函数或者对象时都会为其创建一个原型对象 prototype,在 prototype 对象中,又会想函数中创建 this 一样创建一个 constructor 属性,那么 constructor 属性指向的就是拥有整个原型对象的函数或者对象。
下面我们来看一下具体实现的步骤
首先我们定义一个父类
- function ParentClass(id) {
- //引用类型的公有属性
- this.parentValue = ['C#', 'JAVA', 'PHP'];
- //值类型公有属性
- this.id = id;
- }
接着我们声明父类的原型方法
- ParentClass.prototype.getParentValue = function() {
- console.log(this.parentValue);
- }
下面我们声明子类
- function ChildClass(id, childValue) {
- //构造函数式继承父类
- ParentClass.call(this, id);
- //子类新增属性
- this.childValue = childValue;
- }
寄生式继承父类原型
- parasiticType(ParentClass, ChildClass);
子类新增原型方法
- ChildClass.prototype.getChildValue = function() {
- console.log(this.time);
- }
接着我们创建两个测试方法
- var test1 = new ChildClass(1, "张三");
- var test2 = new ChildClass(2, "李四");
接着我们来测试一下
- test1.parentValue.push("C++");
- console.log(test1.parentValue);//["C#", "JAVA", "PHP", "C++"]
- console.log(test2.parentValue);//["C#", "JAVA", "PHP"]
- test1.getParentValue();//["C#", "JAVA", "PHP", "C++"]
- test1.getChildValue();//张三
- test2.getParentValue();//["C#", "JAVA", "PHP"]
- test2.getChildValue();//李四
这里我们要注意一点,子类再想添加原型方法必须通过 prototype 对象,通过点语法的形式一个一个添加方法,否则直接赋予对象就会覆盖掉从父类原型继承的对象。
到这里我们的继承大致就介绍完了,下面我们开始介绍如何使用 javascript 实现多态
多态,就是同一个方法的多种调用方式,在 javascript 中我们可以对传入的参数做判断实现多种调用方式。
首先我们定义一个方法
- function polymorphism() {
- //获取参数
- var argument = arguments;
- //获取参数长度
- var len = argument.length;
- switch (len) {
- //如果没有参数
- case 0:
- return 0;
- //如果只有一个参数
- case 1:
- return 1;
- //如果有两个参数
- case 2:
- return 2;
- }
- }
我们来试一试
- console.log(polymorphism());//0
- console.log(polymorphism(1));//1
- console.log(polymorphism(1,2));//2
这样我们就很简单的实现了多态的效果,好了这就是本次分享的全部内容,下一章我们开始正式进入 javascript 设计模式。
也谢谢大家看到这里:)如果你觉得我的分享还可以请点击推荐,分享给你的朋友让我们一起进步~
好了以上就是本次分享的全部内容,本次示例参考自 JavaScript 设计模式一书,让我们一点点积累一点点成长,希望对大家有所帮助。
来源: http://www.cnblogs.com/chen-jie/p/javascript_inheritance_polymorphism.html