JS面向对象编程(二):构造函数的继承
对象之间继承的 5 中方法.
比如, 现在有一个"动物"对象的构造函数.
function Animal(){
this.species = "动物";
}
还有一个"猫"对象构造函数
function Cat(name,color){
this.name = name;
this.color = color;
}
怎样才能使猫继承动物呢?
一.构造函数绑定
第一种方法,也是最简单的方法,使用call 或 apply 方法, 将父对象的构造函数绑定在子对象上,即在子对象构造函数中加一行:
function Cat(name,color){
Animal.apply(this, arguments);
this.name = name;
this.color = color;
}
var cat1 = new Cat("大毛","黄色");
alert(cat1.species);//猫科动物
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>0.2-1 obj</title>
</head>
<body>
<script>
//父构造函数
function Animal(){
this.species = "猫科动物"
} //子构造函数
function Cat(name,color){
Animal.apply(this,arguments);
this.name = name;
this.color = color;
} //构造实例
var cat1 = new Cat("大毛","黑色");
alert(cat1.species);
</script>
</body>
</html>
二.Prototype模式
第二种方法更常见,使用 Prototype属性.
如果用"猫"的prototype对象,指向一个Animal的实例,那么所有"猫"的实例,就能继承Animal了.
Cat.prototype = new Animal();
它相当于完全删除了prototype对象原先的值, 然后赋予一个新值.但是第二行又是什么意思呢?
Cat.prototype.constructor = Cat;
原来, 任何一个prototype对象都有一个constructor属性,指向它的构造函数.如果没有"Cat.prototype=new Animal();"这一行,Cat.prototype.constructor是指向Cat的;加了这一行以后,Cat.prototype.constructor指向Animal.
alert(Cat.prototype.constructor == Animal);//true
cat1使用构造函数Cat生成的,因此我们需要手动纠正,将Cat.prototype对象的contructor值改为Cat,不然就会导致继承链的紊乱.
注: 这是编程中很重要的一点,编程时务必遵守.
如果替换了prototype对象,
o.prototype = {};
那么, 下一步必然会成为新的 prototype对象加上constructor属性,并将这个属性指回原来的构造函数.
o.prototype.constructor = o;
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>0.2-2 </title>
</head>
<body>
<script>
function Animal(){
this.species = "动物";
} function Cat(name,color){
this.name = name;
this.color = color;
}
Cat.prototype = new Animal();
alert(Cat.prototype.constructor);//Animal
Cat.prototype.constructor = Cat;
alert(Cat.prototype.constructor);//Cat var cat1 = new Cat("大毛","黄色");
alert(cat1.species);//动物 </script>
</body>
</html>
三.直接继承prototype
第三种方法是对第二种方法的改进. 由于Animal对象中, 不变的属性都可以直接写入 Animal.prototype. 所以,我们也可以让 Cat()跳过Aniaml(),直接继承Animal.prototype.
现在, 我们先将Animal对象改写:
function Animal(){}
Animal.prototype.species = "动物";
然后,将 Cat的prototype对象,然后指向Animal的prototype对象,这样就完成了继承.
Cat.prototype = Animal.prototype;
Cat.prototype.constructor = Cat;
var cat1 = new Cat("大毛","黄色");
alert(cat1.species);//动物
与前一种方法相比, 这样做的优点是效率比较高(不用执行和建立Animal的实例了),比较省内存. 缺点是Cat.prototype和Animal.prototype现在指向了同一个对象,那么任何对Cat.prototype的修改,都会反映到Animal.prototype.
所以,上面这一段代码其实是有问题的.请看第二行
Cat.prototype.constructor = Cat;
这一句话实际上把Aniaml.prototype对象的constructor属性也改掉了!
alert(Animal.prototype.constructor);//Cat
四.利用空对象作为中介
由于"直接继承prototype"存在上述的缺点,所以就有第四种方法,利用一个空对象作为中介.
var F = function(){};
F.prototype = Animal.prototype;
Cat.prototype = new F();
Cat.prototype.constructor = Cat;
F是空对象,所以几乎不占内存.这时,修改Cat的prototype对象,就不会影响到Animal的prototype对象.
alert(Animal.prototype.constructor);//Animal
我们将上边的方法,封装成一个函数,便于使用.
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库如何实现继承的方法.
另外,说明一点,函数体最后一行
Child.uber = Parent.prototype;
意思是为子对象设一个uber属性, 这个属性直接指向父对象的prototype属性.这等于在子对象上打开一条通道,可以直接调用父对象的方法.这一行放在这里,只是为了实现继承的完备性,纯属备用性质.
五.拷贝继承
上面采用prototype对象,实现继承.我们也可以换一种思路,纯粹采用"拷贝"方法实现继承.简单说,如果把父对象的所有属性和方法,拷贝进子对象,不也能够实现继承吗?
首先,还是把Animal的所有不变属性, 都放到它的prototype对象上.
function Animal(){};
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对象.
使用的时候,这样写:
extent2(Cat,Animal);
var cat1 = new Cat("大毛","黄色");
alert(cat1.species);//动物
原文链接:http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance_continued.html
JS面向对象编程(二):构造函数的继承的更多相关文章
- (二)Javascript面向对象编程:构造函数的继承
Javascript面向对象编程:构造函数的继承 这个系列的第一部分,主要介绍了如何"封装"数据和方法,以及如何从原型对象生成实例. 今天要介绍的是,对象之间的"继承 ...
- Javascript面向对象编程:构造函数的继承
今天要介绍的是,对象之间的"继承"的五种方法. 比如,现在有一个"动物"对象的构造函数. function Animal(){ this.species = & ...
- js面向对象编程(第2版)——js继承多种方式
附带书籍地址: js面向对象编程(第2版)
- Js面向对象编程
Js面向对象编程 1. 什么是面向对象编程? 我也不说不清楚什么是面向对象,反正就那么回事吧. 编程有时候是一件很快乐的事,写一些小游戏,用编程的方式玩游戏等等 2. Js如何定义一个 ...
- 简单粗暴地理解js原型链–js面向对象编程
简单粗暴地理解js原型链–js面向对象编程 作者:茄果 链接:http://www.cnblogs.com/qieguo/archive/2016/05/03/5451626.html 原型链理解起来 ...
- 带你一分钟理解闭包--js面向对象编程
上一篇<简单粗暴地理解js原型链--js面向对象编程>没想到能攒到这么多赞,实属意外.分享是个好事情,尤其是分享自己的学习感悟.所以网上关于原型链.闭包.作用域等文章多如牛毛,很多文章写得 ...
- js面向对象编程 ---- 系列教程
原 js面向对象编程:数据的缓存 原 js面向对象编程:如何检测对象类型 原 js面向对象编程:if中可以使用那些作为判断条件呢? 原 js面向对象编程:this到底代表什么?第二篇 原 js面向对象 ...
- C++ Primer 学习笔记_72_面向对象编程 --句柄类与继承[续]
面向对象编程 --句柄类与继承[续] 三.句柄的使用 使用Sales_item对象能够更easy地编写书店应用程序.代码将不必管理Item_base对象的指针,但仍然能够获得通过Sales_item对 ...
- JS面向对象编程,对象,属性,方法。
document.write('<script type="text/javascript" src="http://api.map.baidu.com/api?v ...
- Python进阶之面向对象编程(二)
Python面向对象编程(二) .note-content {font-family: "Helvetica Neue",Arial,"Hiragino Sans GB& ...
随机推荐
- 快速理解类的访问控制(public,protected,private)
接触过面向对象编程的朋友们都知道类中的访问控制符无非有三个,public, protected, private. 理解他就先从期望他达到的效果先说吧 Public: 使成员对于整个程序内(类内类外) ...
- 浏览器中查看HTTP的头部文件
本文以chrome浏览器为例,来讲解下在浏览器中,如何查看http的头部文件. 1.打开chrome浏览器,输入地址,如下图所示. 2.鼠标右击,在右键菜单中选择[检查],如下图所示. 3.选择“Ne ...
- 确认过眼神,看清HTTP协议
导读:什么是 HTTP?它有什么属性?我们常用的是什么呢?快来阅读本文,将会为你一一道来. 什么是 HTTP 协议? 在了解HTTP之前,我们需要了解什么是网络通信模型(也就是我们常说的 OSI 模型 ...
- Docker镜像和容器管理(二)
Docker安装 Docker镜像管理 https://hub.docker.com/ 是公共的一个Docker镜像仓库,类似GitHub一样,上面有非常多的开源项目镜像. 可以直接在命令行搜索镜像 ...
- Python笔记【2】_列表学习
#!/usr/bin/env/python #-*-coding:utf-8-*- #Author:LingChongShi #查看源码Ctrl+左键 #字符串:通常有单引号“'”.双引号“" ...
- 记一次基于Cloudflare服务的爬虫
前言 前几天有个朋友托我帮忙爬一个网站,第一次打开那个网站时,我去,它竟然就要验证码,不过当时是想加几个header应该就能解决,不过事实证明我还是错了.接下来将记录下爬虫中遇到的一些坑以及解决办法. ...
- 趣解 ceph rgw multisite data sync 机制
multisite是ceph rgw对象数据异地容灾备份的一个有效方案,笔者希望深入理解该技术,并应用于生产环境中,然而rgw的这部分代码晦涩难懂,笔者多次尝试阅读,仍云里雾里不解其意,最终流着泪咬着 ...
- Python爬虫入门:爬取pixiv
终于想开始爬自己想爬的网站了.于是就试着爬P站试试手. 我爬的图的目标网址是: http://www.pixiv.net/search.php?word=%E5%9B%9B%E6%9C%88%E3%8 ...
- Appium+python自动化(十八)- 你难道是猴哥失散多年的混血弟弟还是妹妹???- Monkey事件(超详解)
操作事件简介 Monkey所执行的随机事件流中包含11大事件,分别是触摸事件.手势事件.二指缩放事件.轨迹事件.屏幕旋转事件.基本导航事件.主要导航事件.系统按键事件.启动Activity事件.键盘事 ...
- 环形缓存RingBuf的几种实现方式(数组,链表),及Disruptor的分析
先贴个头文件的设计: 首先缓冲区中没有任何数据时,nIdWrite.nIdRead读写下标都为0. 为了判断缓冲区中是否还有数据可读或者可写,我判断的依据是:1)当nIdWrite 等于 nIdRea ...