javascript继承之借用构造函数与原型
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了javascript继承之借用构造函数与原型,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6310字,纯文字阅读大概需要10分钟。
内容图文
在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());
// 咪咪 汪汪
// 新的问题1
console.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函数。
原文:http://www.cnblogs.com/m-v-p/p/3548021.html
内容总结
以上是互联网集市为您收集整理的javascript继承之借用构造函数与原型全部内容,希望文章能够帮你解决javascript继承之借用构造函数与原型所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。