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 预定义函数 变量的作用域 函数也是数据 闭包 对象 原型 原型 继承 原型链 浅拷贝与深拷贝 原 ...
随机推荐
- 认识jsp
jsp头部指令 <%@page import="com.offcn.utils.PageUtils"%> <%@ taglib uri="http:/ ...
- [2019BUAA软工助教]第0次代码作业
[2019BUAA软工助教]第0次代码作业 前言 本博客为完成结对项目所需的先导知识,题目不难,请认真对待 :) 欢迎来到软件工程 :) 注:本次实验为附加作业,不做不扣分,做了有附加分 Part 0 ...
- [P4886] 快递员
考虑在树上选个点rt作为根,并且快递中心就选这儿.计算出所有配送的代价(2*两段之和),设他们的最大值为Max.若此时存在下列情况时,可以判定Max已经为最优解. 1)存在代价为Max的配送(u,v) ...
- 如何用chrome注册版权登记系统
版权登记系统的网址: http://apply.ccopyright.com.cn/goadatadic/registergetList.do 打开网站,一股古朴的气息扑面而来,嗯,一看就是IE时代的 ...
- shell变量定义与数组-1
1.查看系统所有shell和默认shell 查看系统所有的shell: cat /etc/shells 查看系统默认shell: echo $SHELL 2.第一个shell脚本,打印字符串Hello ...
- java中String类为什么不可变?
在面试中经常遇到这样的问题:1.什么是不可变对象.不可变对象有什么好处.在什么情景下使用它,或者更具体一点,java的String类为什么要设置成不可变类型? 1.不可变对象,顾名思义就是创建后的对象 ...
- 【Go】IP地址转换:数字与字符串之间高效转换
转载:https://blog.thinkeridea.com/201903/go/ip2long.html IP 地址库中 IP 地址的保存格式一般有两种,一种是点分十进制形式(192.168.1. ...
- Jenkins+Git+Gitlab+Ansible实现持续集成自动化部署动态网站(二)--技术流ken
项目前言 在上一篇博客<Jenkins+Git+Gitlab+Ansible实现持续化集成一键部署静态网站(一)--技术流ken>中已经详细讲解了如何使用这四个工具来持续集成自动化部署一个 ...
- vmware vcsa-6.5 网络架构之虚拟机的分布式交换机
一.配置VDS 必须来用vcenter server来配置 下面一些理论是抄的王老师的,供大家学习,主意在于学习技术,分享知识. 1.VDS架构图如下: 2.架构图里面有两个逻辑层,数据面板,管理面板 ...
- 使用 Cglib 实现多重代理
前言 由于 Cglib 本身的设计,无法实现在 Proxy 外面再包装一层 Proxy(JDK Proxy 可以),通常会报如下错误: Caused by: java.lang.ClassFormat ...