JavaScript面向对象编程指南(六) 继承
第6章 继承
6.1 原型链
6.1.1原型链示例
原型链法:Child.prototype=new Parent();
<script>
function Shape(){
this.name='shape';
this.toString=function (){
return this.name;
};
}
function TwoDShape(){
this.name='2D shape';
}
function Triangle(side,height){
this.name='Triangle';
this.side=side;
this.height=height;
this.getArea=function(){
return this.side*this.height/2;
};
}
TwoDShape.prototype=new Shape();//TwoDShape对象的原型等于Shape对象的实体
Triangle.prototype=new TwoDShape();
TwoDShape.prototype.constructor=TwoDShape; //确保原型的构造函数没有发生改变
Triangle.prototype.constructor=Triangle; var my=new Triangle(5,10);
my.getArea();//
my.toString();//"Triangle"
</script>
6.1.2 将共享属性迁移到原型中去
<script>
function Shape(){};
//共享属性放置在原型中
Shape.prototype.name='Shape';
Shape.prototype.toString=function(){
return this.name;
}; function TwoDShape(){}; //设置继承 在对象原型扩展前完成继承,后续新内容有可能抹掉我们继承的东西
TwoDShape.prototype=new Shape();
TwoDShape.prototype.constructor=TwoDShape; // 扩展原型
TwoDShape.prototype.name='2D Shape'; function Triangle(side,height){
this.side=side;
this.height=height;
} //设置继承
Triangle.prototype=new TwoDShape();
Triangle.prototype.constructor=Triangle; //扩展原型
Triangle.prototype.name='Triangle';
Triangle.prototype.getArea=function(){
return this.side*this.height/2;
}; var my=new Triangle(5,10);
my.getArea();//
my.toString();//"Triangle"
</script>
6.2 只继承于原型
原型继承法:Child.prototype= Parent.prototype;
<script>
function Shape(){}; //共享属性放在原型中
Shape.prototype.name='shape';
Shape.prototype.toString=function(){
return this.name;
}; //新建构造函数TwoDShape
function TwoDShape(){};
//设置原型继承
TwoDShape.prototype=Shape.prototype;
TwoDShape.prototype.constructor=TwoDShape;
//扩展原型
TwoDShape.prototype.name='2D Shape'; /****新建构造函数Triangle****/
function Triangle(side,height){
this.height=height;
this.side=side;
};
//设置继承
Triangle.prototype=TwoDShape.prototype;
Triangle.prototype.constructor=Triangle;
//扩展原型
Triangle.prototype.name='Triangle';
Triangle.prototype.getArea=function(){
return this.height*this.side/2;
} var my=new Triangle(5,10);
my.getArea();//
my.toString();//"Triangle"
</script>
临时构造器——new F();
function Shape(){}; //共享属性放在原型中
Shape.prototype.name='shape';
Shape.prototype.toString=function(){
return this.name;
}; //新建构造函数TwoDShape
function TwoDShape(){};
//使用临时构造器设置原型继承
var F=function(){};
F.prototype=Shape.prototype;
TwoDShape.prototype=new F();
TwoDShape.prototype.constructor=TwoDShape;
//扩展原型
TwoDShape.prototype.name='2D Shape'; /****新建构造函数Triangle****/
function Triangle(side,height){
this.height=height;
this.side=side;
};
//使用临时构造器设置原型继承
var F=function(){};
F.prototype=TwoDShape.prototype;
Triangle.prototype=new F();
Triangle.prototype.constructor=Triangle;
//扩展原型
Triangle.prototype.name='Triangle';
Triangle.prototype.getArea=function(){
return this.height*this.side/2;
};
6.3 uber——子对象访问父对象的方式
<script>
function Shape(){};
//共享属性放在原型中
Shape.prototype.name='shape';
//检查对象中是否存在this.constructor.uber方法,如果存在就调用该函数的toString方法。this.constructor.uber指向当前对象父级函数的引用
Shape.prototype.toString=function(){
return this.constructor.uber
?this.constructor.uber.toString() + ',' + this.name:this.name;
}; //新建构造函数TwoDShape
function TwoDShape(){};
//使用临时构造器设置原型继承
var F=function (){};
F.prototype=Shape.prototype;
TwoDShape.prototype=new F();
TwoDShape.prototype.constructor=TwoDShape;
//将uber属性设置为指向父级原型的引用
TwoDShape.uber=Shape.prototype;
//扩展原型
TwoDShape.prototype.name='2D shape'; /****新建构造函数Triangle****/
function Triangle(side,height){
this.side=side;
this.height=height;
};
//使用临时构造器设置原型继承
var F=function(){};
F.prototype=TwoDShape.prototype;
Triangle.prototype=new F();
Triangle.prototype.constructor=Triangle;
//将uber属性设置为指向父级原型的引用
Triangle.uber=TwoDShape.prototype;
//扩展原型
Triangle.prototype.name='Triangle';
Triangle.prototype.getArea=function(){
return this.side*this.height/2;
};
var my=new Triangle(5,10);
my.getArea();//
my.toString(); // "shape,2D shape,Triangle"
</script>
6.4 将继承部分封装为函数
临时构造器法:
<script>
//临时构造器法:将继承部分封装为函数
//优点:简洁、重用
function extend(Child,Parent){
var F=function (){};
F.prototype=Parent.prototype;
Child.prototype=new F();
Child.prototype.constructor=Child;
Child.uber=Parent.prototype;
}
function Shape(){};
//共享属性放在原型中
Shape.prototype.name='shape';
//检查对象中是否存在this.constructor.uber方法,如果存在就调用该函数的toString方法。this.constructor.uber指向当前对象父级函数的引用
Shape.prototype.toString=function(){
return this.constructor.uber
?this.constructor.uber.toString() + ',' + this.name:this.name;
}; //新建构造函数TwoDShape
function TwoDShape(){};
extend(TwoDShape,Shape); //使用封装函数,完成继承
//扩展原型
TwoDShape.prototype.name='2D shape'; /****新建构造函数Triangle****/
function Triangle(side,height){
this.side=side;
this.height=height;
};
//继承
extend(Triangle,TwoDShape);
//扩展原型
Triangle.prototype.name='Triangle';
Triangle.prototype.getArea=function(){
return this.side*this.height/2;
}; // 测试
var my=new Triangle();
my.toString(); //"shape,2D shape,Triangle"
</script>
6.5 属性拷贝
<script>
//临时构造器法:将继承部分封装为函数
//优点:简洁、重用
function extend(Child,Parent){
var F=function (){};
F.prototype=Parent.prototype;
Child.prototype=new F();
Child.prototype.constructor=Child;
Child.uber=Parent.prototype;
}
//将父对象的属性拷贝给子对象
// 只适用只包含基本数据类型的对象
function extend2(Child,Parent){
var c=Child.prototype;
var p=Parent.prototype;
for(var i in p){
c[i]=p[i];
};
c.uber=p;
} function Shape(){};
Shape.prototype.name='shape';
Shape.prototype.toString=function(){
return this.uber
?this.uber.toString()+','+this.name
:this.name;
}; function TwoDShape(){}; extend(TwoDShape,Shape);
// 示例
var my=new TwoDShape();
//通过extend方法获得继承,name属性不会是TwoDShape实例的属性
//也不是其原型对象的属性,但仍可以通过继承方式来访问
my.name;//"shape"
TwoDShape.prototype.name;//"shape"
my.hasOwnProperty('name');//false
my.__proto__.hasOwnProperty('name');//false extend2(TwoDShape,Shape);
// //通过extend方法获得继承
var my1=new TwoDShape(); my1.__proto__.hasOwnProperty('name'); // true
my1.toString();// "shape,shape"
</script>
6.6 小心处理引用拷贝
<script>
//原型属性拷贝
function extend2(Child, Parent){
var c=Child.prototype;
var p=Parent.prototype;
for(var i in p){
c[i]=p[i];
}
c.uber=p;
}
function F1(){};
function F2(){};
F1.prototype.name='Alen';
F1.prototype.owns=['aa','bb','cc']; //继承
extend2(F2,F1);
F2.prototype.hasOwnProperty('name'); //true
F2.prototype.hasOwnProperty('owns');// true
//name是基本类型属性,创建的是全新的拷贝
//owns属性是一个数组对象,执行的是引用拷贝
F2.prototype.owns; //["aa", "bb", "cc"]
// 改变F2中的name属性,不会对F1产生影响
F2.prototype.name+=',liMing';//"Alen,liMing"
F1.prototype.name;//"Alen"
F2.prototype.owns.pop();//"cc" 移除F2最后一个元素
F1.prototype.owns; // ["aa", "bb"] F1受到影响
</script>
6.7 对象之间的继承
<script>
//浅拷贝 没有使用原型对象
function extendCopy(p){
var c={};
for(var i in p){
c[i]=p[i];
}
c.uber=p;
return c;
} //使用对象表达式创建对象
var shape={
name:'shape',
toString:function(){
return this.name;
}
};
// 使用extendCopy创建新对象
var f1=extendCopy(shape);
// 对新对象进行扩展
f1.name='2D shape';
f1.toString=function (){
return this.uber.toString()+', '+this.name;
};
// 让新对象继承f1
var triangle=extendCopy(f1);
// 进行扩展
triangle.name='Triangle';
triangle.getArea=function(){
return this.side*this.height/;
};
// 初始化对象 缺点:初始化对象较麻烦
triangle.side=;
triangle.height=;
triangle.getArea();//
triangle.toString(); //"shape, 2D shape, Triangle" </script>
6.8 深拷贝
浅拷贝:当拷贝对象时,实际上只拷贝了该对象在内存中的位置指针。
深拷贝:也通过遍历对象的属性来进行拷贝操作。当遇到对象引用性的操作时,需要再次调用深拷贝函数。
<script>
//浅拷贝
function extendCopy(p){
var c={};
for(var i in p){
c[i]=p[i];
}
c.uber=p;
return c;
} //深拷贝
function deepCopy(p,c){
c=c || {};
for(var i in p){
if(p.hasOwnProperty(i)){
if(typeof p[i] === 'object'){ //判断是否为对象
c[i]=Array.isArray(p[i])? []:{}; //判断是否为数组
deepCopy(p[i],c[i]);
}else{
c[i]=p[i];
}
}
}
return c;
}
// 实例
var parent={
numbers:[,,],
letters:['a','b','c'],
obj:{
prop:
},
bool:true
};
var mydeep=deepCopy(parent);
var myshallow=extendCopy(parent);
//深拷贝
mydeep.numbers.push(,,);//[1, 2, 4, 4, 5, 6]
parent.numbers;// [1, 2, 4] 深拷贝不会对父对象产生影响
//浅拷贝
myshallow.numbers.push();
myshallow.numbers;//[1, 2, 4, 10]
parent.numbers;// [1, 2, 4, 10] 浅拷贝父对象受影响
mydeep.numbers;//[1, 2, 4, 4, 5, 6]
</script>
6.9 object()
原型继承法:
<script>
function object(o){
function F(){};
F.prototype=o;
return new F();
}
//访问uber函数
function object1(o){
var n;
function F(){};
F.prototype=o;
n=new F();
n.uber=o;
return n;
} //浅拷贝 没有使用原型对象
function extendCopy(p){
var c={};
for(var i in p){
c[i]=p[i];
}
c.uber=p;
return c;
} //使用对象表达式创建对象
var shape={
name:'shape',
toString:function(){
return this.name;
}
};
// 使用extendCopy创建新对象
var f1=extendCopy(shape);
// 对新对象进行扩展
f1.name='2D shape';
f1.toString=function (){
return this.uber.toString()+', '+this.name;
}; //使用object1()
var triangle=object1(f1);
// 进行扩展
triangle.name='Triangle';
triangle.getArea=function(){
return this.side*this.height/;
}; triangle.toString();//"shape, 2D shape, Triangle" // 使用Object.create()方法
var f2=Object.create(triangle);
f2.toString(); //"shape, 2D shape, Triangle" </script>
6.10 原型继承与属性拷贝的混合应用
<script>
// o:用于继承 stuff:用于拷贝方法和属性
function objectPlus(o,stuff){
var n;
function F(){};
F.prototype=o;
n=new F();
n.uber=o; for(var i in stuff){
n[i]=stuff[i];
}
return n;
}
//实例
var shape={
name:'shape',
toString:function (){
return this.name;
}
}
//创建继承对象
var twoDee=objectPlus(shape,{
name:'2D shape',
toString:function(){
return this.uber.toString()+', '+this.name;
}
})
var triangle=objectPlus(twoDee,{
name:'Triangle',
getArea:function(){
return this.side*this.height/2;
},
side:0,
height:0
});
var my=objectPlus(triangle,{
side:4,height:4
});
my.getArea(); //
my.toString();//"shape, 2D shape, Triangle, Triangle"
//因为在具体化实例时是继承于triangle的,所以多了一层继承关系
var my1=objectPlus(triangle,{
side:4,
height:4,
name:'my1'
});
my1.toString();//"shape, 2D shape, Triangle, my1"
</script>
6.11 多重继承
一个子对象中有不知一个父对象的继承模式。
<script>
function multi(){
var n={};
for (var j = 0; j < arguments.length; j++) {
stuff=arguments[j];
for(var i in stuff){
n[i]=stuff[i];
}
}
return n;
}
//实例
var shape={
name:'shape',
toString:function (){
return this.name;
}
}
var twoDee={
name:'2D shape',
dimensions:2
};
var triangle=multi(shape,twoDee,{
name:'Triangle',
getArea:function(){
return this.side*this.height/2;
},
side:5,
height:10
});
triangle.getArea();//
triangle.dimensions; //2 继承自twoDee
triangle.toString(); //"Triangle"
</script>
6.12 寄生式继承
<script>
function object(o){
var n;
function F(){};
F.prototype=o;
n=new F();
n.uber=o;
return n;
}
var twoDee={
name:'2D shape',
dimensions:2
};
function triangle(s,h){
var that=object(twoDee);
that.name='Triangle';
that.getArea=function(){
return this.side*this.height/2;
};
that.side=s;
that.height=h;
return that;
}
var t=triangle(5,10);
t.getArea();//
t.dimensions;//
</script>
6.13 构造器借用
<script>
function Child(){
Parent.apply(this,arguments);
}
//父对象
function Shape(id){
this.id=id;
}
Shape.prototype.name='shape';
Shape.prototype.toString=function(){
return this.name;
}
//子对象
function Triangle(){
Shape.apply(this, arguments);
}
Triangle.prototype.name='Triangle'; var t=new Triangle(12);
t.name;//"Triangle"
t.id;//
t.toString();//"[object Object]" Shape()函数未实例化
//原型函数未用到 // 修改1
function Triangle1(){
Shape.apply(this, arguments);
}
Triangle.prototype=new Shape(101);
Triangle.prototype.name='Triangle';
var t1=new Triangle(201);
t1.id;//
delete t1.id;//true
t1.id;//
//缺点:父对象的构造器被继承调用了两次,一次通过apply、一次通过new // 修改2:借用构造器与原型复制
// 原型属性拷贝法
function extend2(Child,Parent){
var p=Parent.prototype;
var c=Child.prototype;
for(var i in p){
c[i]=p[i];
}
c.uber=p;
return c;
}
function Triangle2(){
Shape.apply(this, arguments);
};
extend2(Triangle2,Shape);
Triangle2.prototype.name='Triangle';
var t2=new Triangle2(101);
t2.toString();//"Triangle"
t2.id;//
typeof t2.__proto__.id; //"undefined" ok!
</script>
JavaScript面向对象编程指南(六) 继承的更多相关文章
- 《JavaScript面向对象编程指南(第2版)》读书笔记(一)
目录 一.对象 1.1 获取属性值的方式 1.2 获取动态生成的属性的值 二.数组 2.1 检测是否为数组 2.2 增加数组长度导致未赋值的位置为undefined 2.3 用闭包实现简易迭代器 三. ...
- 《JavaScript面向对象编程指南(第2版)》读书笔记(二)
<JavaScript面向对象编程指南(第2版)>读书笔记(一) <JavaScript面向对象编程指南(第2版)>读书笔记(二) 目录 一.基本类型 1.1 字符串 1.2 ...
- 《JavaScript面向对象编程指南》读书笔记②
概述 <JavaScript面向对象编程指南>读书笔记① 这里只记录一下我看JavaScript面向对象编程指南记录下的一些东西.那些简单的知识我没有记录,我只记录几个容易遗漏的或者精彩的 ...
- 《JavaScript面向对象编程指南》读书笔记①
概述 JavaScript快忘完了,想看一本专业书拾遗,所以看了这本<JavaScript面向对象编程指南>. 个人觉得这本书讲的很透彻很易懂,一些原来有疑惑的地方在这本书里面豁然开朗,看 ...
- 闭包初体验 -《JavaScript面向对象编程指南》
下面是我对闭包的理解:(把他们整理出来,整理的过程也是在梳理) 参考<JavaScript面向对象编程指南> 1.首先,在理解闭包之前: 我们首先应该清楚下作用域和作用域链 作用域:每个函 ...
- 《JavaScript面向对象编程指南》
第一章.引言 1.5 面向对象的程序设计常用概念 对象(名词):是指"事物"在程序设计语言中的表现形式. 这里的事物可以是任何东西,我们可以看到它们具有某些明确特征,能执行某些动作 ...
- [已读]JavaScript面向对象编程指南
又是一个忽悠人的书名,其实这本书的花了大量内容阐述JS的基础语法,BOM,DOM,事件,ajax(这个和很多js书一样).最后一章则是编程模式与设计模式. 我觉得与面向对象没多大关系,要算的话,pro ...
- 《JavaScript面向对象编程指南》译者序
相对于Perl.Python等动态脚本语言来说,JavaScript确实是一门饱受误解的语言.对于译者这种从20世纪90年代末走过来的C++程序员来说,尤其如此.在那个年代,提起JavaScript总 ...
- JavaScript面向对象编程指南
引言 面向对象程序设计 基本数据类型.数组.循环及条件表达式 基本数据类型 函数 函数Function 预定义函数 变量的作用域 函数也是数据 闭包 对象 原型 原型 继承 原型链 浅拷贝与深拷贝 原 ...
随机推荐
- 埃航和737MAX坠毁:软件优先级问题
事件背景: 2019年3月10日,埃塞俄比亚航空公司一架波音737MAX8飞机发生坠机,机上157人全部遇难,包括8名中国公民.这是继去年10月29日印尼狮航空难事故之后,波音737MAX8飞机在五个 ...
- Python中函数和模块的体验与使用
函数基础 目标 函数的快速体验 函数的基本使用 函数的参数 函数的返回值 函数的嵌套调用 在模块中定义函数 01. 函数的快速体验 1.1 快速体验 所谓函数,就是把 具有独立功能的代码块 组织为一个 ...
- SpringMvc + socket.io + vue + vue-socket.io实例
SpringMvc部分实现 1. 所需依赖 <dependency> <groupId>com.corundumstudio.socketio</g ...
- tensorflow 1.0 学习:池化层(pooling)和全连接层(dense)
池化层定义在 tensorflow/python/layers/pooling.py. 有最大值池化和均值池化. 1.tf.layers.max_pooling2d max_pooling2d( in ...
- jQuery源码——.html()方法原理解析
在将字符串转化为html碎片时,一般会将字符串作为容器的innerHTML属性赋值.但innerHTML有很多局限性,比如我们想转化的字符串中有<script>标签并且包含一个立即执行的函 ...
- Centos系统通过tar.gz包安装Mysql5.7
1.安装mysql之前需要确保系统中有libaio依赖,使用如下命令: yum search libaio yum install libaio 2.进入centos终端操作界面,使用wget命令下载 ...
- app 压力测试
monkey工具详解 https://blog.csdn.net/jffhy2017/article/details/54572400 ----------------------- Android ...
- Android UI(二)DridView的菜单
Jeff Lee blog: http://www.cnblogs.com/Alandre/ (泥沙砖瓦浆木匠),retain the url when reproduced ! Thanks ...
- 流式大数据计算实践(2)----Hadoop集群和Zookeeper
一.前言 1.上一文搭建好了Hadoop单机模式,这一文继续搭建Hadoop集群 二.搭建Hadoop集群 1.根据上文的流程得到两台单机模式的机器,并保证两台单机模式正常启动,记得第二台机器core ...
- Linux查询端口是否被占用的四种方法
一个面试题,使用三种不同的方法查看8080被哪个进程占用了.通常比较熟悉的方法是netstat和lsof两种,但还有什么方法呢. 1.netstat或ss命令 netstat -anlp | grep ...