深入剖析JavaScript面向对象编程


Posted in Javascript onJuly 12, 2016

二. Javascript 面向对象编程:构造函数的继承

本节主要介绍,如何生成一个"继承"多个对象的实例。

比如,现在有一个"动物"对象的构造函数,

function Animal(){ 
this.species = "动物"; 
}

还有一个"猫"对象的构造函数,

function Cat(name,color){ 
this.name = name; 
this.color = color; 
}

怎样才能使"猫"继承"动物"呢?

1. 构造函数绑定

最简单的方法,大概就是使用call或apply方法,将父对象的构造函数绑定在子对象上,也就是在子对象构造函数中加一行:

 function Cat(name,color){ 
Animal.apply(this, arguments); 
this.name = name; 
this.color = color; 
} 
var cat1 = new Cat("大毛","黄色"); 
alert(cat1.species); // 动物

2. prototype模式

更常见的做法,则是使用prototype属性。

如果"猫"的prototype对象,指向一个Animal的实例,那么所有"猫"的实例,就能继承Animal了。

Cat.prototype = new Animal(); 
Cat.prototype.constructor = Cat; 
var cat1 = new Cat("大毛","黄色"); 
alert(cat1.species); // 动物

代码的第一行,我们将Cat的prototype对象指向一个Animal的实例。

1.Cat.prototype = new Animal();

它相当于完全删除了prototype 对象原先的值,然后赋予一个新值。但是,第二行又是什么意思呢?

1.Cat.prototype.constructor = Cat;

原来,任何一个prototype对象都有一个constructor属性,指向它的构造函数。也就是说,Cat.prototype 这个对象的constructor属性,是指向Cat的。

我们在前一步已经删除了这个prototype对象原来的值,所以新的prototype对象没有constructor属性,所以我们必须手动加上去,否则后面的"继承链"会出问题。这就是第二行的意思。

总之,这是很重要的一点,编程时务必要遵守。下文都遵循这一点,即如果替换了prototype对象,

1.o.prototype = {};

那么,下一步必然是为新的prototype对象加上constructor属性,并将这个属性指回原来的构造函数。

1.o.prototype.constructor = o;

3. 直接继承prototype

由于Animal对象中,不变的属性都可以直接写入Animal.prototype。所以,我们也可以让Cat()跳过 Animal(),直接继承Animal.prototype。

现在,我们先将Animal对象改写:

1.function Animal(){ } 
2.Animal.prototype.species = "动物";

然后,将Cat的prototype对象,然后指向Animal的prototype对象,这样就完成了继承。

Cat.prototype = Animal.prototype; 
CatCat.prototype.constructor = Cat; 
var cat1 = new Cat("大毛","黄色"); 
alert(cat1.species); // 动物

与前一种方法相比,这样做的优点是效率比较高(不用执行和建立Animal的实例了),比较省内存。缺点是 Cat.prototype和Animal.prototype现在指向了同一个对象,那么任何对Cat.prototype的修改,都会反映到 Animal.prototype。

所以,上面这一段代码其实是有问题的。请看第二行

1.Cat.prototype.constructor = Cat;

这一句实际上把Animal.prototype对象的constructor属性也改掉了!

1.alert(Animal.prototype.constructor); // Cat

4. 利用空对象作为中介

由于"直接继承prototype"存在上述的缺点,所以可以利用一个空对象作为中介。

var F = function(){}; 
F.prototype = Animal.prototype; 
Cat.prototype = new F(); 
Cat.prototype.constructor = Cat;

F是空对象,所以几乎不占内存。这时,修改Cat的prototype对象,就不会影响到Animal的prototype对象。

1.alert(Animal.prototype.constructor); // Animal

5. prototype模式的封装函数

我们将上面的方法,封装成一个函数,便于使用。

function extend(Child, Parent) { 
 
var F = function(){}; 
F.prototype = Parent.prototype; 
Child.prototype = new F(); 
Child.prototype.constructor = Child; 
Child.uber = Parent.prototype; 
}

使用的时候,方法如下

extend(Cat,Animal); 
var cat1 = new Cat("大毛","黄色"); 
alert(cat1.species); // 动物

这个extend函数,就是YUI库如何实现继承的方法。

另外,说明一点。函数体最后一行

1.Child.uber = Parent.prototype;

意思是为子对象设一个uber属性,这个属性直接指向父对象的prototype属性。这等于是在子对象上打开一条通道,可以直接调用父对象的方法。这一行放在这里,只是为了实现继承的完备性,纯属备用性质。

6. 拷贝继承

上面是采用prototype对象,实现继承。我们也可以换一种思路,纯粹采用"拷贝"方法实现继承。简单说,如果把父对象的所有属性和方法,拷贝进子对象,不也能够实现继承吗?

首先,还是把Animal的所有不变属性,都放到它的prototype对象上。

1.function Animal(){} 
2.Animal.prototype.species = "动物";

然后,再写一个函数,实现属性拷贝的目的。

function extend2(Child, Parent) { 
var p = Parent.prototype; 
var c = Child.prototype; 
for (var i in p) { 
c[i] = p[i]; 
} 
c.uber = p; 
}

这个函数的作用,就是将父对象的prototype对象中的属性,一一拷贝给Child对象的prototype对象。

使用的时候,这样写:

extend2(Cat, Animal); 
var cat1 = new Cat("大毛","黄色"); 
alert(cat1.species); // 动物

以上这篇深入剖析JavaScript面向对象编程就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
JavaScript的变量作用域深入理解
Oct 25 Javascript
ECMAScript 创建自己的js类库
Nov 22 Javascript
window.location不跳转的问题解决方法
Apr 17 Javascript
JS判断是否360安全浏览器极速内核的方法
Jan 29 Javascript
JS+CSS实现美化的下拉列表框效果
Aug 11 Javascript
jQuery的deferred对象使用详解
Sep 25 Javascript
分享javascript、jquery实用代码段
Oct 20 Javascript
vuejs2.0实现分页组件使用$emit进行事件监听数据传递的方法
Feb 22 Javascript
原生JS实现圆环拖拽效果
Apr 07 Javascript
Angular网络请求的封装方法
May 22 Javascript
layui 实现表单和文件上传一起传到后台的例子
Sep 16 Javascript
jQuery实现颜色打字机的完整代码
Mar 19 jQuery
JS及PHP代码编写八大排序算法
Jul 12 #Javascript
微信支付 JS API支付接口详解
Jul 11 #Javascript
判断输入的字符串是否是日期格式的简单方法
Jul 11 #Javascript
JS判断日期格式是否合法的简单实例
Jul 11 #Javascript
深入浅析JavaScript中的scrollTop
Jul 11 #Javascript
js鼠标单击和双击事件冲突问题的快速解决方法
Jul 11 #Javascript
js 弹出对话框(遮罩)透明,可拖动的简单实例
Jul 11 #Javascript
You might like
用PHP和ACCESS写聊天室(十)
2006/10/09 PHP
PHP取得一个类的属性和方法的实现代码
2011/05/22 PHP
PHP strip_tags保留多个HTML标签的方法
2016/05/22 PHP
PHP中的use关键字及文件的加载详解
2016/11/28 PHP
用PHP的socket实现客户端到服务端的通信实例详解
2017/02/04 PHP
Laravel 实现Eloquent模型分组查询并返回每个分组的数量 groupBy()
2019/10/23 PHP
jQuery中的常用事件总结
2009/12/27 Javascript
将string解析为json的几种方式小结
2010/11/11 Javascript
javascript 节点排序 2
2011/01/31 Javascript
使用js简单实现了tree树菜单
2013/11/20 Javascript
一个css与js结合的下拉菜单支持主流浏览器
2014/10/08 Javascript
jQuery+PHP实现动态数字展示特效
2015/03/14 Javascript
javascript常用功能汇总
2015/07/05 Javascript
jQuery动态添加可拖动元素完整实例(附demo源码下载)
2016/06/21 Javascript
jQuery 生成svg矢量二维码
2016/08/09 Javascript
JS实现针对给定时间的倒计时功能示例
2017/04/11 Javascript
vue的事件绑定与方法详解
2017/08/16 Javascript
JavaScript实现随机数生成器(去重)
2017/10/13 Javascript
ExtJs使用自定义插件动态保存表头配置(隐藏或显示)
2018/09/25 Javascript
微信小程序实现原生步骤条
2019/07/25 Javascript
微信小程序实现多张图片上传功能
2020/11/18 Javascript
Python类属性的延迟计算
2016/10/22 Python
使用python实现接口的方法
2017/07/07 Python
python2.7和NLTK安装详细教程
2018/09/19 Python
python实现彩色图转换成灰度图
2019/01/15 Python
PyCharm中Matplotlib绘图不能显示UI效果的问题解决
2020/03/12 Python
基于python和flask实现http接口过程解析
2020/06/15 Python
四年大学自我鉴定
2014/02/17 职场文书
高中军训感想800字
2014/02/23 职场文书
团代会主持词
2014/04/02 职场文书
旅游局领导班子“四风”问题对照检查材料思想汇报
2014/09/29 职场文书
简单的离婚协议书范本
2014/11/16 职场文书
上甘岭观后感
2015/06/10 职场文书
售房协议书范本
2015/08/11 职场文书
搞笑婚礼主持词开场白
2015/11/24 职场文书
Python爬虫入门案例之爬取二手房源数据
2021/10/16 Python