JavaScript设计模式 Item 4 --继承

时间:2022-09-17 12:46:41

1、继承

在javascript中继承是一个非常复杂的话题,比其他任何面向对象语言的中的继承都复杂得多。在大多数其他面向对象语言中,继承一个类只需要使用一个关键字即可。与它们不同,在javascript中要想达到传承公用成员的目的,需要采取一系列措施。更有甚者,javascript属于使用原型式继承的少数语言之一。利益于这种语言的灵活性,你既可使用标准的基于类的继承,也可使用更微妙一些的原型式继承。

2、为什么需要继承?

一般来说,在设计类的时候,我们希望能减少重复性的代码,并且尽量弱化对象间的耦合。使用继承符合前一个设计原则的需要。借助这种机制,你可以在现有类的基础上进行设计并充分利用它们已经具备的各种方法,而对设计进行修改也更为轻松。假设你需要让几个类都拥有一个按特定方式输出类结构的toString()方法,当然可以用复制加粘贴的办法把定义toString()方法的代码添加到每一个类中,但这样做的话,每当需要改变这个方法的工作方式时,你将不得不在每一个类中重复同样的修改。反之,如果你提供了一个ToStringProvider类,然后让那些类继承这个类,那么toString这个方法只需在一个地方声明即可。

让一个类继承另一个类可能会导致二者产生强耦合,也即一个类的依赖于另一个类的内部实现。我们将讨论一些有助于避免这种问题的技术,其中包括用掺元类为其他类提供方法这种技术。

3、基于类的继承

下面看下面的代码:

 <script type="text/javascript">  

        function Person(name, age)
{
this.name = name;
this.age = age;
}
Person.prototype.say = function ()
{
console.log(this.name + " , " + this.age);
}
function Student(no)
{
this.no = no;
}
/**
* Student的prototype指向Person的对象
*/</span>
Student.prototype = new Person();
var stu1 = new Student("0001");
stu1.name = '张三';
stu1.age = '11';
console.log(stu1.no);
stu1.say();
</script>

输出结果:

0001
张三 , 11

可以看到Student成功集成了Person,并且拥有了Person的say方法,核心代码其实就是一句 Student.prototype = new Person();,下面通过图解来说明原理:

JavaScript设计模式 Item 4 --继承

将Student.prototype指向new Person() , new Person的_proto_又指向Person Prototype;这样完成了整个继承。

但是这种方式存在问题:

问题1:当父类存在引用类型变量时,造成数据不一致,下面我们给Person添加一个hobbies属性,类型为数组。

<script type="text/javascript">
/**
* 存在问题
* 1、无法在Student的构造方法中传递参数用于父类的构造方法
* 2、对于引用类型变量,造成数据不一致
*/ function Person(name, age)
{
this.name = name;
this.age = age;
this.hobbies = [] ;
}
Person.prototype.say = function ()
{
console.log(this.name + " , " + this.age +" , " +this.hobbies);
}
function Student(no)
{
this.no = no;
}
Student.prototype = new Person(); var stu1 = new Student("0001");
stu1.name = '张三';
stu1.age = '11';
stu1.hobbies.push("soccer");
stu1.say(); var stu2 = new Student("0002");
stu2.name = '李四';
stu2.age = '12';
stu2.hobbies.push("girl");
stu2.say();
</script>

输出结果:

张三 , 11 , soccer
李四 , 12 , soccer,girl

可以看出,李四的hobbies应该只有girl,但是上面的代码让所有对象共享了hobbies属性。

上述的继承方式还存在一个问题:

问题2:在Student的构造方法中,无法使用new Student(“00001” , “张三” , 12) ;创建对象,并初始化name和age属性,必须stu.name, stu.age进行赋值

为了解决上述问题,对上述代码进行修改:

<script type="text/javascript">  

       function Person(name, age)
{
this.name = name;
this.age = age;
this.hobbies = [];
}
Person.prototype.say = function ()
{
console.log(this.name + " , " + this.age +" , " + this.hobbies);
} function Student(name, age, no)
{
/**
* 使用call方法,第一个参数为上下文;
* 有点类似Java中的super(name,age)的感觉
*/
Person.call(this, name, age);
this.no = no;
} Student.prototype = new Person(); var stu1 = new Student("0001","张三",11);
stu1.hobbies.push("soccer");
stu1.say(); var stu2 = new Student("0002","李四",12);
stu2.hobbies.push("cangjin");
stu2.hobbies.push("basketball");
stu2.say();
</script>

输出:

0001 , 张三 , soccer
0002 , 李四 , cangjin,basketball

在Student的构造方法中使用了Person.call(this,name,age)感觉就像super(name,age)【call的第一个参数为上下文】;并且成功解决了对引用属性的共享问题,完美解决。

4、基于原型链的继承

<script type="text/javascript">  

    /**
* 基于原型链的集成中都是对象
* 存在问题:
* 1、对于引用类型变量,造成数据不一致
*/
var Person = {
name: "人",
age: 0,
hobbies: [],
say: function ()
{
console.log(this.name + " , " + this.age + " , " + this.hobbies);
}
}
; var Student = clone(Person);
Student.no ="";
Student.sayHello = function()
{
console.log(this.name +"hello ") ;
} var stu1 = clone(Student);
stu1.name = "zhangsan";
stu1.age = 12;
stu1.hobbies.push("Java");
stu1.say(); var stu2 = clone(Student);
stu2.name = "lisi";
stu2.age = 13;
stu2.hobbies.push("Javascript");
stu2.say(); /**
* 返回一个prototype执行obj的一个对象
* @param obj
* @returns {F}
*/
function clone(obj)
{
var F = function ()
{
};
F.prototype = obj;
return new F(); }
</script>

输出:

zhangsan , 12 , Java
lisi , 13 , Java,Javascript

可以看出同样存在引用属性不一致的问题,并且整个操作全部基于对象,给人的感觉不是很好,下面通过图解解释下原理:

JavaScript设计模式 Item 4 --继承

对象间通过一个clone函数,不断的返回一个新的对象,且prototype执行传入的对象,整个继承过程其实就是_proto_不断的指向,形成一个链,所以叫做原型链。

好了,已经介绍完了,js的两种集成的方式,最好使用的还是通过类的继承(上述第一种方案,解决存在问题的)。

版权声明:本文为小平果原创文章,转载请注明:http://blog.csdn.net/i10630226

JavaScript设计模式 Item 4 --继承的更多相关文章

  1. JavaScript设计模式Item 1—多态

    多态的实际含义是:同一操作作用于不同的对象上面,可以产生不同的解释和不同的执行结果.换句话说,给不同的对象发送同一个消息的时候,这些对象会根据这个消息分别给出不同的反馈. 从字面上来理解多态不太容易, ...

  2. JavaScript设计模式 Item 7 --策略模式Strategy

    1.策略模式的定义 何为策略?比如我们要去某个地方旅游,可以根据具体的实际情况来选择出行的线路. 如果没有时间但是不在乎钱,可以选择坐飞机. 如果没有钱,可以选择坐大巴或者火车. 如果再穷一点,可以选 ...

  3. JavaScript设计模式 Item 6 --单例模式Singleton

    单例模式的定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 单例模式是一种常用的模式,有一些对象我们往往只需要一个,比如线程池.全局缓存.浏览器的window对象.在js开发中,单例模式的 ...

  4. JavaScript设计模式 Item 3 --封装

    在JavaScript 中,并没有对抽象类和接口的支持.JavaScript 本身也是一门弱类型语言.在封装类型方面,JavaScript 没有能力,也没有必要做得更多.对于JavaScript 的设 ...

  5. JavaScript设计模式 Item 2 -- 接口的实现

    1.接口概述 1.什么是接口? 接口是提供了一种用以说明一个对象应该具有哪些方法的手段.尽管它可以表明这些方法的语义,但它并不规定这些方法应该如何实现. 2. 接口之利 促进代码的重用. 接口可以告诉 ...

  6. JavaScript设计模式 Item 5 --链式调用

    1.什么是链式调用 这个很容易理解,例如: $(this).setStyle('color', 'red').show(); 一般的函数调用和链式调用的区别:调用完方法后,return this返回当 ...

  7. JavaScript的学习--JavaScript设计模式的总结

    这篇博客只是自己对设计模式的理解的备忘~ 看完了<JavaScript设计模式>这本书,一直没有写博客记录一下,最近抽出时间来重读了一下,就顺便记录一下~ 如果你只是想粗略了解一下Java ...

  8. 【读书笔记】读《JavaScript设计模式》之装饰者模式

    一.定义 装饰者模式可用来透明地把对象包装在具有同样接口的另一个对象之中.这样一来,你可以给一个方法添加一些行为,然后将方法调用传递给原始对象.相对于创建子类来说,使用装饰者对象是一种更灵活的选择(装 ...

  9. 再起航,我的学习笔记之JavaScript设计模式15&lpar;组合模式&rpar;

    组合模式 组合模式(Composite): 又称部分-整体模式,将对象组合成树形结构以表示"部分整体"的层次结构.组合模式使得用户对单个对象和组合对象的使用具有一致性. 如果有一个 ...

随机推荐

  1. SurfaceView的简单使用

    package com.example.administrator.mystudent.surfaceView; import android.content.Context; import andr ...

  2. js 点名

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  3. MFC中SQLite数据库的使用

    1打开数据库 BOOL playDlg::openData() { WCHAR a[100]; CString path; path = m_exePath+L"sentence_makin ...

  4. php测试时不出现错误信息

    来源:http://blog.sina.com.cn/s/blog_6c9d65a101013vdj.html 在练习程序时,有时候写错了,在浏览器会打印出出错信息. 可我的程序始终没有出现. 我的环 ...

  5. 如何在RecyclerView上面实现&quot&semi;拖放&quot&semi;和&quot&semi;滑动删除&quot&semi;-1

    Android上面有许多的教程, 库和示例, 在RecyclerView上面实现"拖放"和"滑动删除"功能. 尽管有更新, 更好的方法可用, 但是大多数人依然使 ...

  6. iOS&amp&semi;nbsp&semi;动画总结—UIView动画

    1.概述 UIKit直接将动画集成到UIView类中,实现简单动画的创建过程.UIView类定义了几个内在支持动画的属性声明,当这些属性发生改变时,视图为其变化过程提供内建的动画支持. 执行动画所需要 ...

  7. hive中beeline取回数据的完整流程

    这里我们从BeeLine.execute讲起. 接下来来到BeeLine.dispatch,这里的入参就是sql语句.方法的最后调用了Commands.sql,然后调用到了Commands.execu ...

  8. &lbrack;物理学与PDEs&rsqb;第1章第8节 静电场和静磁场 8&period;2 稳定电流的电场

    1. 此时, Maxwell 方程组为 $$\beex \bea \Div{\bf D}&=\rho_f,\\ \rot {\bf E}&={\bf 0},\\ \Div{\bf B} ...

  9. Java 基础:hashCode方法

    Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket 一.前言 泥瓦匠最近被项目搞的天昏地暗.发现有些要给自己一些目标,关于技术的目标: 专注很重要.专注J ...

  10. java7 java MethodHandle解析

    简介 JDK6之前我们会使用java反射来实现动态方法调用,多数框架用反射的比较多,例如mybatis.spring等.在JDK7中,新增了java.lang.invoke.MethodHandle( ...