JavaScript继承(图解笔记)
JavaScript有多种继承模式,总结起来用到的方法有:原型链的传递、构造函数的借用、对象的复制。

对于原型链和原型的解释,可参考:JavaScript 原型中的哲学思想
这篇文章讲得很清晰,让我们明白:所有JS对象源于null,并通过原型指针和原型对象来实现继承。
构造函数和原型对象的关系如下:

每个构造函数都有一个prototype属性,指向函数的原型对象;原型对象中又有一个constructor属性,重新指向构造函数。而对象实例中有一个原型指针[[prototype]](在Firefox、Safari和Chrome中,对应属性proto),指向原型对象。
明白原型之后,就进入正题继承了。
1.原型链继承
function SuperType(){
this.superproperty = true;
}
SuperType.prototype.getSuperValue = function(){
return this.superproperty;
}
function SubType(){
this.subproperty = false;
}
SubType.prototype = new SuperType(); //原型链继承
SubType.prototype.getSubValue =function(){
return this.subproperty;
}
var instance = new SubType();
alert(instance.getSuperValue());//true

通过SubType.prototype=new SuperType(),实现了以下三点:
A:重写了SubType的原型,让子类原型和子类构造函数之间断开联系。
B:子类原型是父类的实例,其原型指针[[prototype]]指向了父类的原型对象,这样子类就可以沿着原型链访问到父类的方法getSuperValue()。
C:子类原型是父类实例,通过父类构造函数,子类原型继承了父类的属性superproperty。
最终,子类继承了父类的方法和属性。
原型链继承的问题:
父类的实例属性成了子类的原型属性,如上面的superproperty,会被子类所有实例共享。该属性是基本类型值时没有问题,但如果是引用类型值(比如数组),那么修改实例1的该属性(比如向数组push一个新值),实例2也会跟着改变。
也就是说,实例们只有共性,不能保持个性。
2.构造函数继承
function SuperType(name){
this.name = name;
}
function SubType(){
//继承了SuperType,同时还传递了参数
SuperType.call(this,"Nicholas");
this.age = 29;
}
var instance = new SubType();
alert(instance.name); //"Nicholas"
alert(instance.age); //29

通过SuperType.call(this),在子类构造函数中调用了父类的构造函数,创建子类实例会执行子类的构造函数(含父类的构造函数),也就完成了继承。当然,子类和父类的原型是没有关系的,子类实例不能访问父类原型对象中的属性和方法。
构造函数继承的问题:
方法在构造函数中定义,无法实现函数复用。比如父类中有一个方法getName(),则每次创建子类实例的时候,都要创建一个新的getName(),通过instance1.getName() !== instance.getName()就可以验证这一点。
这就是说,实例们保持了个性,却不能共享方法。
3.组合继承
function SuperType(name){
this.name = name;
this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
}
function SubType(name,age){
//继承属性
SuperType.call(this,name); //第二次调用SuperTyper()
this.age = age;
}
//继承方法
SubType.prototype = new SuperType(); //第一次调用SuperTyper()
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
alert(this.age);
}
var instance1 = new SubType("Nicholas",29);
instance1.colors.push("black");
alert(instance1.colors); // "red","blue","green","black"
instance1.sayName(); //"Nicholas"
instance1.sayAge(); //29
var instance2 = new SubType("Greg",27);
alert(instance2.colors); // "red","blue","green"
instance2.sayName(); //"Greg"
instance2.sayAge(); //27

通过借用构造函数来继承属性,原型链来继承方法。结合了两者的优点,让实例们即保持个性,又共享方法。
组合继承的问题:
两次调用父类的构造函数。第一次(A):SubType.prototype=new SuperType(),子类原型对象取得了父类的实例属性。第二次(B):
SuperType.call(this),创建子类实例时,调用父类构造函数,重写实例属性,屏蔽了原型对象上同名属性。
4.原型式继承
function object(o){
function F(){};
F.prototype = o;
return new F();
}
var person = {
name:"Nicholas",
friends:["Shelby","Court","Van"]
};
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"

以一个对象为基础,通过object()函数进行浅复制,再将得到的对象实例加以修改。
可以看到,这种继承方法是没有父类和子类的,只是通过复制对象来得到副本。
ES5有object.create()方法,是object()的规范化,可以传入两个参数:要复制的对象和额外的属性对象(如{name:{value:Greg}},这种方式会覆盖基础对象上的同名属性)。
原型式继承的问题:
和原型链继承一样,继承的属性由所有实例共享,改动一个实例的引用类型值时,所有实例都会改变。
5.寄生式继承
function createAnother(original){
var clone = object(original);//object()函数创建对象
clone.sayHi = function(){ //增强这个对象
alert("hi");
};
return clone; //返回这个对象
}
var person = {
name:"Nicholas";
friends:["Shelby","Court","Van"];
} //基础对象
var anotherPerson = createAnother(person); //新对象
anotherPerson.sayHi(); //"hi"
寄生式和原型式方法相同,都是复制一个基础对象来得到新对象,不同的是它将对象实例的修改放到也放到函数中,将整个过程(创建、增强、返回)封装了起来。
6.寄生组合式继承
function inheritPrototype(subType,superType){
var prototype = object(superType.prototype); //创建对象
prototype.constructor = subType; //增强对象
subType.prototype = prototype; //指定对象
}
function SuperType(name){
this.name = name;
this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
}
function SubType(name,age){
//继承属性
SuperType.call(this,name); //只调用一次SuperTyper()
this.age = age;
}
//继承方法
inheritPrototype(SubType,SuperType);
SubType.prototype.sayAge = function(){
alert(this.age);
}

顾名思义,这种继承模式就是寄生式(复制)+组合式(原型链+构造函数),将几种方法组合起来。解决了组合式继承两次调用父类构造函数的问题。
代码来源:
《JavaScript 高级程序设计》
原文链接:http://www.jianshu.com/p/0045cd01e0be
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
JavaScript继承(图解笔记)的更多相关文章
- JavaScript继承学习笔记
JavaScript作为一个面向对象语言(JS是基于对象的),可以实现继承是必不可少的,但是由于本身并没有类的概念,所以不会像真正的面向对象编程语言通过类实现继承,但可以通过其他方法实现继承.(jav ...
- 图解JavaScript 继承
JavaScript作为一个面向对象语言,可以实现继承是必不可少的,但是由于本身并没有类的概念(不知道这样说是否严谨,但在js中一切都类皆是对象模拟)所以在JavaScript中的继承也区别于其他的面 ...
- 【转载】Javascript原型继承-学习笔记
阮一峰这篇文章写的很好 http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javas ...
- 【读书笔记】javascript 继承
在JavaScript中继承不像C#那么直接,C#中子类继承父类之后马上获得了父类的属性和方法,但JavaScript需要分步进行. 让Brid 继承 Animal,并扩展自己fly的方法. func ...
- JS学习笔记——JavaScript继承的6种方法(原型链、借用构造函数、组合、原型式、寄生式、寄生组合式)
JavaScript继承的6种方法 1,原型链继承 2,借用构造函数继承 3,组合继承(原型+借用构造) 4,原型式继承 5,寄生式继承 6,寄生组合式继承 1.原型链继承. <script t ...
- javascript继承机制的设计思想(ryf)
我一直很难理解Javascript语言的继承机制. 它没有"子类"和"父类"的概念,也没有"类"(class)和"实例" ...
- JavaScript语言精粹笔记
JavaScript语言精粹笔记 掌握语言的每个特性可以让你出风头,但是并不推荐,因为一部分的特性带来的麻烦可能远超本身的价值.正如书中所言,坏的材料并不能雕刻出好的作品,要成为一名更好的程序员,要取 ...
- 转:Javascript继承机制的设计思想
我一直很难理解Javascript语言的继承机制. 它没有"子类"和"父类"的概念,也没有"类"(class)和"实例" ...
- 《你不知道的javascript》读书笔记2
概述 放假读完了<你不知道的javascript>上篇,学到了很多东西,记录下来,供以后开发时参考,相信对其他人也有用. 这篇笔记是这本书的下半部分,上半部分请见<你不知道的java ...
- Javascript MVC 学习笔记(一) 模型和数据
写在前面 近期在看<MVC的Javascript富应用开发>一书.本来是抱着一口气读完的想法去看的.结果才看了一点就傻眼了:太多不懂的地方了. 仅仅好看一点查一点,一点一点往下看吧,进度虽 ...
随机推荐
- 第十四篇:JavaScript
本篇内容 简介 使用 DOM 一. 简介 JavaScript 是世界上最流行的编程语言. 这门语言可用于 HTML 和 web,更可广泛用于服务器.PC.笔记本电脑.平板电脑和智能手机等设备. Ja ...
- POJ 2142 The balance | EXGCD
题目: 求ax+by=c的一组解,使得abs(x)+abs(y)尽量小,满足前面前提下abs(ax)+abs(by)尽量小 题解: exgcd之后,分别求出让x尽量小和y尽量小的解,取min即可 #i ...
- css实现0.5像素
.border{ position: relative; } .border:before{ content: ''; position: absolute; width: 200%; height: ...
- 做一个类似JQuery获取DOM对象的$()
在dom操作时,有时根据id获取单个对象.有时根据className获取多个对象.平常可能我们用两个函数来实现这两个功能.不过我将它们整合了一下,目前使用情况良好,函数如下: view source ...
- AtCoder Regular Contest 093 E: Bichrome Spanning Tree(生成树)
Bichrome Spanning Tree 题意: 给出一个n个点,m条边的无向连通图,现在要给每条边染色,可以染成黑色或者白色. 现在要求在染色完毕后,找出一个至少包含一条黑边和一条白边的最小生成 ...
- DP———5.拣馅饼(记忆化搜索,得到最大值)
都说天上不会掉馅饼,但有一天gameboy正走在回家的小径上,忽然天上掉下大把大把的馅饼.说来gameboy的人品实在是太好了,这馅饼别处都不掉,就掉落在他身旁的10米范围内.馅饼如果掉在了地上当然就 ...
- swiper伸缩侧边菜单栏
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8&quo ...
- display:inline、block、inline-block的区别 摘】
display:block就是将元素显示为块级元素. block元素的特点是: 总是在新行上开始: 高度,行高以及顶和底边距都可控制: 宽度缺省是它的容器的100%,除非设定一个宽度 <div& ...
- matlab 命令行快捷键
- POCO库中文编程参考指南(5)Poco::Net::SocketAddress
1 枚举 最大地址长度,这个与Poco::Net::IPAddress中的定义可以类比,不过这里指的是`struct sockaddr_in6 enum { MAX_ADDRESS_LENGTH = ...