第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面向对象编程指南(六) 继承的更多相关文章

  1. 《JavaScript面向对象编程指南(第2版)》读书笔记(一)

    目录 一.对象 1.1 获取属性值的方式 1.2 获取动态生成的属性的值 二.数组 2.1 检测是否为数组 2.2 增加数组长度导致未赋值的位置为undefined 2.3 用闭包实现简易迭代器 三. ...

  2. 《JavaScript面向对象编程指南(第2版)》读书笔记(二)

    <JavaScript面向对象编程指南(第2版)>读书笔记(一) <JavaScript面向对象编程指南(第2版)>读书笔记(二) 目录 一.基本类型 1.1 字符串 1.2 ...

  3. 《JavaScript面向对象编程指南》读书笔记②

    概述 <JavaScript面向对象编程指南>读书笔记① 这里只记录一下我看JavaScript面向对象编程指南记录下的一些东西.那些简单的知识我没有记录,我只记录几个容易遗漏的或者精彩的 ...

  4. 《JavaScript面向对象编程指南》读书笔记①

    概述 JavaScript快忘完了,想看一本专业书拾遗,所以看了这本<JavaScript面向对象编程指南>. 个人觉得这本书讲的很透彻很易懂,一些原来有疑惑的地方在这本书里面豁然开朗,看 ...

  5. 闭包初体验 -《JavaScript面向对象编程指南》

    下面是我对闭包的理解:(把他们整理出来,整理的过程也是在梳理) 参考<JavaScript面向对象编程指南> 1.首先,在理解闭包之前: 我们首先应该清楚下作用域和作用域链 作用域:每个函 ...

  6. 《JavaScript面向对象编程指南》

    第一章.引言 1.5 面向对象的程序设计常用概念 对象(名词):是指"事物"在程序设计语言中的表现形式. 这里的事物可以是任何东西,我们可以看到它们具有某些明确特征,能执行某些动作 ...

  7. [已读]JavaScript面向对象编程指南

    又是一个忽悠人的书名,其实这本书的花了大量内容阐述JS的基础语法,BOM,DOM,事件,ajax(这个和很多js书一样).最后一章则是编程模式与设计模式. 我觉得与面向对象没多大关系,要算的话,pro ...

  8. 《JavaScript面向对象编程指南》译者序

    相对于Perl.Python等动态脚本语言来说,JavaScript确实是一门饱受误解的语言.对于译者这种从20世纪90年代末走过来的C++程序员来说,尤其如此.在那个年代,提起JavaScript总 ...

  9. JavaScript面向对象编程指南

    引言 面向对象程序设计 基本数据类型.数组.循环及条件表达式 基本数据类型 函数 函数Function 预定义函数 变量的作用域 函数也是数据 闭包 对象 原型 原型 继承 原型链 浅拷贝与深拷贝 原 ...

随机推荐

  1. 【面试题】java中高以上必会技能

    java基础 1.集合相关 1.1 java中常见的集合 答:Arraylist,LinkedList,ListedList,HashMap,HashSet. 1.2 arraylist和linked ...

  2. Tools - 速查表与备忘单(Cheat Sheet)

    Cheat Sheets Rico's cheatsheets Cheat-Sheets.org Python Python Cheat sheet Python Programming Cheat ...

  3. 简单聊一聊那些svg的沿路径运动

    之前遇见动画就很想用css实现,显然有些效果是我们力所不能及,实现起来麻烦,效果不好,让人捉急.其实归结起来,不同的动画有自己的优势,根据实际情况进行取舍.本文就告诉大家如何用SVG写出个简单动画.就 ...

  4. java相关知识点

    Java基础.语法 1. 简述Java跨平台原理 2. Java的安全性 3. Java三大版本 4. 什么是JVM?什么是JDK? 什么是JRE? 5. Java三种注释类型 6. 8种基本数据类型 ...

  5. springBoot(2)---快速创建项目,初解jackson

    快速创建项目,初解jackson 一.快速创建项目 springboot官网提供了工具类自动创建web应用:网址:http://start.spring.io/ 官网页面 1.快速创建一个 选择web ...

  6. Docker容器中开始.Net Core之路

    开始写这篇博客前,已经尝试练习过好多次Docker环境安装,.Net Core环境安装了,在这里替腾讯云做一个推广,假如我们想学习.练手.net core 或是Docker却苦于没有开发环境,服务器也 ...

  7. SpringBoot 启动概述

    透过现象看本质,SpringApplication 只是将一个典型的Spring应用的启动流程进行了扩展,因此,透彻理解 Spring 容器是打开 Spring Boot 大门的一把钥匙. Sprin ...

  8. Hadoop-HDFS

    HDFS - 写文件 1.客户端将文件写入本地磁盘的N#x4E34;时文件中 2.当临时文件大小达到一个block大小时,HDFS client通知NameNode,申请写入文件 3.NameNode ...

  9. 【Python】正则表达式纯代码极简教程

    <Python3正则表达式>文字版详细教程链接:https://www.cnblogs.com/leejack/p/9189796.html ''' 内容:Python3正则表达式 日期: ...

  10. 连载《一个程序猿的生命周期》-《发展篇》- 22.城市奋斗者的阿Q精神

    好久没有写文章了,有些人会认为博主肯定是没有什么好写的了.其实不然,是想写的太多,实在是没有时间.上半年一直比较忙,处于加班常态的状态,身心疲惫.相较于城市的伪奋斗者,我算比较实干的,而界定“实干”的 ...