深入剖析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 parseInt 大改造
Sep 27 Javascript
基于jQuery的的一个隔行变色,鼠标移动变色的小插件
Jul 06 Javascript
jQuery弹出(alert)select选择的值
Apr 21 Javascript
jquery获取复选框被选中的值
Apr 10 Javascript
整理Javascript事件响应学习笔记
Dec 02 Javascript
JS函数arguments数组获得实际传参数个数的实现方法
May 28 Javascript
AngularJS基础 ng-csp 指令详解
Aug 01 Javascript
js的三种继承方式详解
Jan 21 Javascript
vue移动端路由切换实例分析
May 14 Javascript
微信小程序实现两个页面传值的方法分析
Dec 11 Javascript
记录微信小程序 height: calc(xx - xx);无效问题
Dec 30 Javascript
详解Js模块化的作用原理和方案
Apr 29 Javascript
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
Windows IIS PHP 5.2 安装与配置方法
2009/06/08 PHP
php 判断服务器操作系统的类型
2014/02/17 PHP
PHP中浮点数计算比较及取整不准确的解决方法
2015/01/09 PHP
PHP调用Linux命令权限不足问题解决方法
2015/02/07 PHP
wamp服务器访问php非常缓慢的解决过程
2015/07/01 PHP
wordpress自定义标签云与随机获取标签的方法详解
2019/03/22 PHP
php如何获取Http请求
2020/04/30 PHP
node.js中的http.response.writeHead方法使用说明
2014/12/14 Javascript
JS实现table表格数据排序功能(可支持动态数据+分页效果)
2016/05/26 Javascript
Vue.js学习笔记之 helloworld
2016/08/14 Javascript
JavaScript 继承详解(六)
2016/10/11 Javascript
BootStrap Table对前台页面表格的支持实例讲解
2016/12/22 Javascript
Angular项目从新建、打包到nginx部署全过程记录
2017/12/09 Javascript
实例详解Vue项目使用eslint + prettier规范代码风格
2018/08/20 Javascript
Vue 组件注册实例详解
2019/02/23 Javascript
vue-i18n实现中英文切换的方法
2020/07/06 Javascript
jquery实现简单每周轮换的日历
2020/09/10 jQuery
[01:31]DOTA2上海特级锦标赛 SECRET战队完整宣传片
2016/03/16 DOTA
python实现批量下载新浪博客的方法
2015/06/15 Python
python更新列表的方法
2015/07/28 Python
详解Python操作RabbitMQ服务器消息队列的远程结果返回
2016/06/30 Python
解决PySide+Python子线程更新UI线程的问题
2019/01/11 Python
TensorFlow卷积神经网络之使用训练好的模型识别猫狗图片
2019/03/14 Python
Python数据类型之Dict字典实例详解
2019/05/07 Python
OpenCV python sklearn随机超参数搜索的实现
2020/01/17 Python
python使用yaml 管理selenium元素的示例
2020/12/01 Python
Python虚拟环境virtualenv创建及使用过程图解
2020/12/08 Python
阿姆斯特丹城市卡:Amsterdam Pass
2019/12/01 全球购物
会计职业生涯规划范文
2014/01/04 职场文书
关于打架的检讨书
2014/01/17 职场文书
模具毕业生推荐信
2014/02/15 职场文书
大学生职业生涯规划书参考模板
2014/03/05 职场文书
欢送领导祝酒词
2015/08/12 职场文书
Navicat for MySQL的使用教程详解
2021/05/27 MySQL
JavaScript 定时器详情
2021/11/11 Javascript
漫画「你在春天醒来」第10卷封面公开
2022/03/21 日漫