javascript继承之借用构造函数与原型
在js中,关于继承只有利用构造函数和原型链两种来现实。以前所见到的种种方法与模式,只不过是变种罢了。
借用构造函数
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// 一个动物类,包含名字和性别属性function Animal (name, sex) { this.name = name; this.sex = sex; this.getName = function(){ return this.name; }; }// Cat类继承Animal基类,并且拥有额外的属性function Cat (name, sex, hasLegs) { this.hasLegs = hasLegs; Animal.apply(this, arguments);// 借用Animal的构造器}// Dog类继承Animal基类,并且拥有与Cat类不一样的额外的属性function Dog (name, sex, otherFeatures) { this.otherFeatures= otherFeatures; Animal.apply(this, arguments); // 借用Animal的构造器} |
借用构造函数的优点就是能够复用代码;缺点就是它不能继承基类的原型,以及部分代码累赘。像Animal类中的getName方法,本该有一个就可以了,但是每次调用其构造器都会开辟新的空间来存放这个方法。如果把这些共有的属性或者方法放入原型链中,就不会需要每个实例都有一个这样的属性或者方法,而是大家共用一个模板。
构造函数与原型并用
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// 重新定义动物类,function Animal (name, sex) { this.name = name; this.sex = sex; }// 提取公共的方法或者属性放入原型链中Animal.prototype.getName = function (){ return this.name;}//Cat类不变,修改Cat的原型链,使其指向基类的原型Cat.prototype = Animal.prototype;//Dog类不变,修改Dog的原型链,使其指向基类的原型Dog.prototype = Animal.prototype; |
测试代码1
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
// 分别new一个对象var cat = new Cat('咪咪', 'female', true), dog = new Dog('汪汪', 'male', null);// 功能已实现console.log(cat.getName(),dog.getName()); // 咪咪 汪汪// 新的问题1console.log(cat instanceof Cat, dog instanceof Cat); // true true 现在猫狗不分了/*原因是在改变各个具体子类的原型是,它们的构造器都指向了基类,它们拥有同一个构造器。如果修改某个子类的原型constructor,必然会影响到其它子类*/// 新问题2。如果现在Cat类的getName逻辑有变,不能修改基类的原型。现作出如下改动function Cat (name, sex, hasLegs) { this.hasLegs = hasLegs; Animal.apply(this, arguments); // 新的逻辑 this.getName = function (){ return this.name+','+this.sex; } }//但是这样代码又不能达到复用,因为每个Cat实例都有一个getName方法。/*如何解决上述问题呢,也许你想到了——原型【链】。突出个链字,链说明是一节一节的,如果我们在子类与基类原型中间再加一节,不就完事了么*///定义一个空函数来做这个节点function o (){}// 让‘空’节点指向基类的原型,Cat类再指向空节点o.prototype = Animal.prototype;Cat.prototype = new o();// 重置Cat的构造器指针Cat.prototype.constructor = Cat;o.prototype = Animal.prototype;Dog.prototype = new o();Dog.prototype.constructor = Dog; |
完整的代码
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
// 一个动物类,包含名字和性别属性function Animal (name, sex) { this.name = name; this.sex = sex;}// 提取公共的方法或者属性放入原型链中Animal.prototype.getName = function (){ return this.name;}function o (){}var oCat = new o(); // 修改Cat类的getName逻辑oCat.getName = function (){return this.name+','+this.sex;}o.prototype = Animal.prototype;Cat.prototype = oCat;//重值Cat构造器指针Cat.prototype.constructor = Cat;// 同上。并且这三行代码的顺序不能随意改动o.prototype = Animal.prototype;Dog.prototype = new o();Dog.prototype.constructor = Dog;// Cat类继承Animal基类,并且拥有额外的属性function Cat (name, sex, hasLegs) { this.hasLegs = hasLegs; Animal.apply(this, arguments);}// Dog类继承Animal基类,并且拥有与Cat类不一样的额外的属性function Dog (name, sex, otherFeatures) { this.otherFeatures= otherFeatures; Animal.apply(this, arguments);}var cat = new Cat('咪咪', 'female', true),dog = new Dog('汪汪', 'male', null);// 功能正常,代码也达到进一步复用console.log(cat.getName(), dog.getName());// 现在猫是猫,狗是狗了console.log(cat instanceof Cat, dog instanceof Cat);// 两个子类的构造器也是对的了console.log(cat.constructor, dog.constructor); |
现在似乎完整了,可是好像还是有些遗憾。如同被妹子拒了一样:你人很好,我们还是做朋友吧。言外之意就是还没好到让妹子想跟你在一起的程度。那么哪里不够呢?现在只有两个子类,如果有几十个的话,还是要做很多重复的工作;如果又有一个机械的基类,又要做同样的事情。那么,我们可以把这个继承的方法写成面向对象的形式么?答案是:可以滴。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
// 将继承的实现细节用函数包裹起来,classPropers是需要覆盖的属性和方法function inherit(classPropers){ var o = function (){}, // 空函数用做空节点 parent = this, // 这里的this代表基类构造器 child = function(){}, // 返回一个子类 hasOwnConstructor = false; // 是否拥有自己的构造器 if(typeof classPropers === 'object' && classPropers.hasOwnProperty('constructor')){ //如果有构造器属性,则覆盖构造器 child = function (){ classPropers.constructor.apply(this,arguments); } hasOwnConstructor = true; }else{ // 否则使用基类的构造器 child = function(){ parent.apply(this, arguments); } } o.prototype = parent.prototype; child.prototype = new o(); if(hasOwnConstructor){ // 重置构造器指针 child.prototype.constructor = classPropers.constructor } if(classPropers){ /*$.extend是jQ函数,这里不再实现。如果classPropers与基类有相同的方法,则会‘覆盖’ 基类的方法*/ $.extend(child.prototype, classPropers); } // 继承基类的静态方法,这样子类还可以被继承 $.extend(child, parent); child.__super__ = parent.prototype; // 以防万一以后还要调用基类相同方法 return child;} |
完整测试代码2
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
// 一个动物类,包含名字和性别属性 function Animal (name, sex) { this.name = name; this.sex = sex; } Animal.prototype = { getName: function(){ return this.name;}, getSex: function(){ return this.sex;} }; function inherit(classPropers){ var o = function (){}, // 空函数用做空节点 parent = this, // 这里的this代表基类构造器 child = function(){}, // 返回一个子类 hasOwnConstructor = false; // 是否拥有自己的构造器 if(typeof classPropers === 'object' && classPropers.hasOwnProperty('constructor')){ //如果有构造器属性,则覆盖构造器 child = function (){ classPropers.constructor.apply(this,arguments); } hasOwnConstructor = true; }else{ // 否则使用基类的构造器 child = function(){ parent.apply(this, arguments); } } o.prototype = parent.prototype; child.prototype = new o(); if(hasOwnConstructor){ // 重置构造器指针 child.prototype.constructor = classPropers.constructor } if(classPropers){ /*$.extend是jQ函数,这里不再实现。如果classPropers与基类有相同的方法,则会‘覆盖’ 基类的方法*/ $.extend(child.prototype, classPropers); } // 继承基类的静态方法,这样子类还可以被继承 $.extend(child, parent); child.__super__ = parent.prototype; // 以防万一以后还要调用基类相同方法 return child; } Animal.inherit = inherit; var Cat = Animal.inherit({sayHi:function(){console.log('喵喵...')}}), cat = new Cat('咪咪', '不告诉你'); console.log(cat.getName(),cat.getSex()); var Dog = Animal.inherit({ constructor:function(name){ this.name = name; console.log('我有自己的工厂(构造器)'); } }), dog = new Dog('我为自己代言'); console.log(dog.getName(),dog.constructor); // 老虎小时候就是猫,不信,我有证据如下。 var Tiger = Cat.inherit({constructor:function(){console.log('出来一声吼啊!喵喵......咋变猫叫了呢?wuwu...')}}), tiger = new Tiger(); tiger.sayHi(); |
记得引用jQuery或者自己实现$.extend函数。
javascript继承之借用构造函数与原型的更多相关文章
- javascript继承之借用构造函数(二)
//简单的函数调用 function Father() { this.nums= [1,2]; } function Son() { Father.call(this);//调用超类型,完成son继承 ...
- javascript实现继承3种方式: 原型继承、借用构造函数继承、组合继承,模拟extends方法继承
javascript中实现继承的三种方式:原型继承.借用构造函数继承.混合继承: /* js当中的继承 js中 构造函数 原型对象 实力对象的关系: 1 构造函数.prototype = 原型对象 2 ...
- js继承之组合继承(结合原型链继承 和 借用构造函数继承)
在我的前两篇文章中,我们已经介绍了 js 中实现继承的两种模式:原型链继承和借用构造函数继承.这两种模式都存在各自的缺点,所以,我们考虑是否能将这二者结合到一起,从而发挥二者之长.即在继承过程中,既可 ...
- javascript中继承(二)-----借用构造函数继承的个人理解
本人目录如下: 零.寒暄&回顾 一,借用构造函数 二.事件代理 三,call和apply的用法 四.总结 零.寒暄&回顾 上次博客跟大家分享了自己对原型链继承的理解,想看的同学欢迎猛击 ...
- js继承之借用构造函数继承
我的上一篇文章介绍了,原型链继承模式.但是单纯的原型链模式并不能很好地实现继承. 一.原型链的缺点 1.1 单纯的原型链继承最大的一个缺点,来自于原型中包含引用类型的值. 本来,我们没有通过原型链实现 ...
- Javascript面向对象——创建对象、构造函数的原型
Javascript面向对象--创建对象.构造函数的原型 其实:JavaScript中的创建类,就是创建一个构造函数,在创建对象时用到new这个关键字, 一.创建对象 1.函数创建对象 functio ...
- JS学习笔记——JavaScript继承的6种方法(原型链、借用构造函数、组合、原型式、寄生式、寄生组合式)
JavaScript继承的6种方法 1,原型链继承 2,借用构造函数继承 3,组合继承(原型+借用构造) 4,原型式继承 5,寄生式继承 6,寄生组合式继承 1.原型链继承. <script t ...
- JS继承之借用构造函数继承和组合继承
根据少一点套路,多一点真诚这个原则,继续学习. 借用构造函数继承 在解决原型中包含引用类型值所带来问题的过程中,开发人员开始使用一种叫做借用构造函数(constructor stealing)的技术( ...
- JavaScript之工厂方式 构造函数方式 原型方式讲解
一.工厂方式可以为一个对象,创建多个实例. var oCar = new Object; oCar.color = "red"; oCar.doors=4; oCar.mpg=23 ...
随机推荐
- TortoiseGit push失败原因小结(转)
花了我一个晚上,终于弄明白为什么总是 push 失败的原因了!竟然是因为我用的是注册的用户名而不是邮箱名……囧死. 另外搞清楚了一个问题,就是 Git 和远程仓库交互有两种方式,即 https 方式和 ...
- 创建自定义的Middleware中间件
创建自定义的Middleware中间件 阅读目录 何为Middleware中间件 使用Inline方式注册Middleware 使用Inline+ AppFunc方式注册Middleware 定义原生 ...
- 【Flume NG用户指南】(2)构造
作者:周邦涛(Timen) Email:zhoubangtao@gmail.com 转载请注明出处: http://blog.csdn.net/zhoubangtao/article/details ...
- 【软件project】生存期模型(含图)
为了反映软件生存周期内各个工作应怎样组织,各阶段怎样衔接,须要软件开发模型给出直观图示表达.软件开发模型是软件思想的详细化,是实施在过程模块中的软件开发方法和工具. 以下来介绍开发模型的特点以及他们的 ...
- Swift游戏开发实战教程(霸内部信息大学)
Swift游戏开发实战教程(大学霸内部资料) 试读下载地址:http://pan.baidu.com/s/1sj7DvQH 介绍:本教程是国内第一本Swift游戏开发专向资料. 本教程具体解说记忆配对 ...
- 10分钟学会Linux
10分钟学会Linux有点夸张,可是能够让一个新手初步熟悉Linux中最重要最主要的知识,本文翻译的英文网页在众多Linux入门学习的资料中还是很不错的. 英文地址:http://freeengine ...
- c++使用stmp协议发送电子邮件(163邮箱,TTL非SSL)
0.有关TLS和SSL SSL/TLS是用来加密邮件流的. 假设不加密的话非常easy被人破解. 只是既然是要发送广告邮件,这个就不用在意了,使用没加密的即可. 另外在使用的时候,发现,qq的邮箱须要 ...
- 关于webbrowser控件自动登陆的问题
原文:关于webbrowser控件自动登陆的问题 楼主dtb(陈少)2004-03-04 22:16:55 在 VB / 网络编程 提问 请问怎么用webbrowser自动登陆www.jp168.co ...
- iOS程序发布时出现your application is being uploaded解决办法
当用Xcode发布app时候出现“your application is being uploaded”或者用Application Loader 一直出现“ 正在通过ITUNES STORE进行鉴定 ...
- ArcGIS API for Silverlight 编辑Geometry
概述 ArcMap的编辑功能是非常强大的,ArcEngine编写的CS程序也可以用到ArcMap中提供的编辑功能,那么ArcGIS API forSilverlight针对Geometry的编辑提供了 ...