第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. 页面css样式找不到问题

    出现了一个页面没有样式的问题: 问题: 1.路径不对, 可以打开页面f12看样式是否找到 检查路径是否正确. 2.样式没引全或者没引对. 查看引入的样式是否正确或缺少样式. 3.路径明明写对了却404 ...

  2. ubuntu16.04 下鼠标变成十字形状无法点击情况解决

    出现这种问题的原因是把shell命令行终端当成了python环境,误输入了"import"命令. (当然如果你真的希望在shell中输入import指令除外...) 我自己想当然的 ...

  3. exec 命令简单用法 和 find 搭配用法示例

    find是我们很常用的一个Linux命令,但是我们一般查找出来的并不仅仅是看看而已,还会有进一步的操作,这个时候exec的作用就显现出来了. 看例子: find ./ -name "*.tx ...

  4. gcc编译参数详解一(-ffunction-sections -fdata-sections)

    背景 有时我们的程序会定义一些暂时使用不上的功能和函数,虽然我们不使用这些功能和函数,但它们往往会浪费我们的ROM和RAM的空间.这在使用静态库时,体现的更为严重.有时,我们只使用了静态库仅有的几个功 ...

  5. ASCII码字符串普通加密解密-android

    //android后台Java //ASCII加密 String str = e.getText().toString(); StringBuilder s = new StringBuilder() ...

  6. vue 移动端屏幕适配 使用rem

    要想移动端适配 并使用 rem  您需要先看这篇文章,配置好less ➡️ 在vue 中使用 less,就可以使用rem了 如果项目已经开发的差不多了,没有用到rem 又要使用rem,您用这招. po ...

  7. extjs 解决使用store.sync()方法更新item有时不触发后台action的问题

    问题描述: extjs 解决使用store.sync()方法更新item有时不触发后台action,不出发后台action的原因是item的字段值没有变化 解决方法: item.setDirty(tr ...

  8. Linux编程 10 (shell外部命令与内建命令,alias ,type命令)

    一.  内部命令 Linux命令有内部命令(内建命令)和外部命令之分,内部命令和外部命令功能基本相同,但也有些细微差别.内部命令不需要使用子进程来执行,它们已经和shell编译成一体,作为shell工 ...

  9. Java后端工程师必备书单(含大后端方向相关书籍)

    学习Java和其他技术的资源其实非常多,但是我们需要取其精华去其糟粕,选择那些最好的,最适合我们的,同时也要由浅入深,先易后难.基于这样的一个标准,我在这里为大家提供一份Java的学习资源清单. 一: ...

  10. 解决Unity中模型部件的MeshCollider不随动画一起运动的问题

    Unity的3d游戏开发中,经常遇到需要将模型的某一部分(比如武器),单独做碰撞处理的情况. 导入模型后,给武器部分添加MeshCollider,MeshCollider的Mesh通常包含在模型里,如 ...