第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. JavaScript 对象(上)

    简述: 1.是 JavaScript 的基本类型 2.是一种复合值,可通过名字访问这些值 3.可看作属性的无序集合,每个属性都是一个名/值对(属性名是字符串或标识符) 4.可以从一个称为原型的对象继承 ...

  2. 【Spark调优】小表join大表数据倾斜解决方案

    [使用场景] 对RDD使用join类操作,或者是在Spark SQL中使用join语句时,而且join操作中的一个RDD或表的数据量比较小(例如几百MB或者1~2GB),比较适用此方案. [解决方案] ...

  3. Cocos2d-x环境配置步骤

    Cocos2d-x环境配置: (1)安装Visual Studio 2013 软件安装包为:VS2013_RTM_ULT_CHS.iso文件,将其解压后可以直接安装,也可以使用虚拟光驱等软件进行安装. ...

  4. C/C++结构体成员偏移量获取

    分析代码节选自muduo. 以下代码通过offsetof获取sin_family在sockaddr_in6中的字段偏移量. static_assert(offsetof(sockaddr_in6, s ...

  5. 阿里云申请ssl证书

    申请证书(本文以阿里云服务器为背景,申请证书也以阿里云域名申请证书来作为实例) (1)登陆阿里云服务器,初次配置的用户,不建议直接搜索‘ssl证书’进行购买,因为这样购买后证书与域名对应的引导性并不强 ...

  6. [EXP]Microsoft Windows 10 (Build 17134) - Local Privilege Escalation (UAC Bypass)

    #include "stdafx.h" #include <Windows.h> #include "resource.h" void DropRe ...

  7. 好用的shell可以事半功倍

    程序员离不开shell,一个好用的shell可以事半功倍,推荐zsh以及一些插件 # install zsh $ brew install zsh # install a framework, we ...

  8. newwork setup

    #-*-coding:utf-8-*- ######################################################################### # Copy ...

  9. ES6躬行记(3)——解构

    解构(destructuring)是一种赋值语法,可从数组中提取元素或从对象中提取属性,将其值赋给对应的变量或另一个对象的属性.解构地目的是简化提取数据的过程,增强代码的可读性.有两种解构语法,分别是 ...

  10. C# 锁系列目录

    1.lock.Monitor lock(obj){} 编译之后是如下代码 Monitor.Enter(obj); try { // } finally { Monitor.Exit(obj); } 2 ...