全文转载自:http://www.blogjava.net/baoyaer/articles/105481.html
每当我们说到
js
的继承时,在您的脑袋的第一反应就是
prototype
原型机制来实现。但是您是否使用过其他的方法来实现继承呢,或者您是否了解其他
实现方式及各种不同的继承实现机制的优缺点呢?
好了,下面我们就来看看几种比较常见的继承实现吧。
1、 prototype方式
1
var
BaseClass
=
function
()
2

3
{
4

5
this
.name
=
"
3zfp
"
;
6

7
this
.age
=
100
;
8

9
this
.ToString
=
function
()
{
10

11
return
this
.name
+
"
"
+
this
.age;
12

13
}
14

15
}
16

17
var
Derived
=
function
()
18

19
{
20

21
this
.address
=
"
ShenZhen
"
;
22

23
}
24

25
Derived.prototype
=
new
BaseClass();
26

27
var
instance
=
new
Derived();
28

29
instance.ToString();
30
这种方式最为简单,只需要让一个类的prototype
为被继承的一个实例就
ok
,然后直接使用
BaseClass
的方法。
prototype
属性是啥意思呢?
prototype
即为原型,每一个对象
(
由
function
定义出来
)
都有一个默认的原型属性,该属性是个对象类型。
并且该默认属性用来实现链的向上攀查。意思就是说,如果某个对象的属性不存在,那个将通过
prototype
属性对应的对象的来查找该对象的属性。
如果
prototype
查找不到呢?
js
会自动地找
prototype
的
prototype
属性对应的对象来查找,这样就通过
prototype
一直往上索引攀查,直到查找到了
该属性或者
prototype
最后为空
("undefined");
例如:上例中的
instance.ToString()
方法。
js
会先在
instance
实例中查找是否有
ToString()
方法,因为没有,所以查找
Derived.prototype
属性,
而
prototype
为
NewClass
的一个实例,该实例有
ToString()
方法,于是调用成功;同样给
instance
的
name
属性赋值时也是查找
prototype
来实现的。
注意,每一个对象得
prototype
都默认对应一个
object
对象,但是该对象不等于
Object
;如何验证呢?看如下代码:
1
var
foo
=
function
()
{}
;
2

3
var
result
=
(foo.prototype
==
Object);
这段代码的result
所得值为
false;
以下几个需要注意:
1
typeof
(Object.prototype)
==
"
object
"
;
2

3
4

5
typeof
(Object.prototype.prototype)
==
"
undefined
"
;
6

7
8

9
var
obj
=
new
Object();
10

11
typeof
(obj.prototype)
==
"
undefined
"
;
12

13
14

15
var
obj
=
{}
;
16

17
typeof
(obj.prototype)
==
"
undefined
"
;
18

19
20

21
2
、
apply
方式
1
var
BaseClass
=
function
()
2

3
{
4

5
this
.name
=
"
3zfp
"
;
6

7
this
.age
=
100
;
8

9
this
.ToString
=
function
()
{
10

11
return
this
.name
+
"
"
+
this
.age;
12

13
}
14

15
}
16

17
var
Derived
=
function
()
18

19
{
20

21
BaseClass.apply(
this
,
new
Array());
22

23
this
.address
=
"
ShenZhen
"
;
24

25
}
26

27
var
instance
=
new
Derived();
28

29
instance.ToString();
30

31
32
在这种方式下,我们最需要理解的就是
apply
函数的作用。
该方法普遍的解释为用
A
方法去替换
B
方法。第一个参数为
B
方法的对象本身,第二个参数为一个数组,该数组内的值集合为需要传递给
A
方法对应的
参数列表,如果参数为空,即没有参数传递,则通过
new Array()
来传递,
null
无效。
一般的方式为:
但是在本例当中,
apply
方法执行了两步操作。
第一
:将
BaseClass
以
apply
传递的
Array
数组作为初始化参数进行实例化。
第二
:将新生成的实例对象的所有属性(
name
,
age
,
ToString
方法)复制到
instance
实例对象。
这样就实现了继承。
1
var
foo
=
function
()
2

3
{
4

5
this
.fooA
=
function
()
{
6

7
this
.fooB.apply(
this
,
new
Array(
"
sorry
"
));
8

9
}
10

11
this
.fooB
=
function
(str)
12

13
{
14

15
alert(str);
16

17
}
18

19
}
20

21
new
foo().fooA();
22
3
、
call+prototype
方式
1
var
BaseClass
=
function
(name,age)
2

3
{
4

5
this
.name
=
name;
6

7
this
.age
=
age;
8

9
this
.ToString
=
function
()
{
10

11
return
this
.name
+
"
"
+
this
.age;
12

13
}
14

15
}
16

17
var
Derived
=
function
()
18

19
{
20

21
BaseClass.call(
this
,
"
3zfp
"
,
100
);
22

23
this
.address
=
"
ShenZhen
"
;
24

25
}
26

27
Derived.prototype
=
new
BaseClass();
28

29
var
instance
=
new
Derived();
30

31
instance.ToString();
32

33
其实,
call
函数和
apply
方式有很类似的作用,都是用
A
方法去替换
B
方法,但是参数传递不一样,
call
方法的第一个参数为
B
方法的对象本身,和面的参数列不用
Array
对象包装,直接依次传递就可以。
为什么作用类似,
call
方式的实现机制却要多一条
Derived.prototype = new BaseClass();
语句呢?那是因为
call
方法只实现了方法的替换而没有作对象属性的复制操作。
例:
1
var
foo
=
function
()
2

3
{
4

5
this
.fooA
=
function
()
{
6

7
this
.fooB.call(
this
,
"
sorry
"
);
8

9
}
10

11
this
.fooB
=
function
(str)
12

13
{
14

15
alert(str);
16

17
}
18

19
}
20

21
new
foo().fooA();
22

23
则 this.fooB.call(this,"sorry")
执行了如下几个操作:
1
this
.temp
=
this
.fooB;
2

3
this
.temp(
"
sorry
"
);
4

5
delete
(
this
.temp);
6
其实,google Map API
的继承就是使用这种方式。大家可以下载的参考参考
(maps.google.com)
。
4
、
prototype.js
中的实现方式
1
Object.extend
=
function
(destination, source)
{
2

3
for
(property
in
source)
{
4

5
destination[property]
=
source[property];
6

7
}
8

9
return
destination;
10

11
}
12

13
var
BaseClass
=
function
(name,age)
{
14

15
this
.name
=
name;
16

17
this
.age
=
age;
18

19
this
.ToString
=
function
()
{
20

21
return
this
.name
+
"
"
+
this
.age;
22

23
}
24

25
}
26

27
var
Derived
=
function
()
28

29
{
30

31
BaseClass.call(
this
,
"
foo
"
,
100
);
32

33
this
.address
=
"
singapore
"
;
34

35
this
.ToString
=
function
()
{
36

37
var
string
=
Derived.prototype.ToString.call(
this
);
38

39
return
string
+
"
"
+
this
.address;
40

41
}
42

43
}
44

45
Object.extend(Derived.prototype,
new
BaseClass());
46

47
var
instance
=
new
Derived();
48

49
document.write(instance.ToString());
该方式,实际上是显式的利用了
apply
的原理来实现继承。先
var temp = new BaseClass()
,再将
temp
的属性遍历复制到
Derived.prototype
中。
for (property in source)
表示遍历某个对象的所有属性。但是私有属性无法遍历。
例
:
1
var
foo
=
function
()
2

3
{
4

5
var
innerString
=
""
;
6

7
this
.name
=
"
3zfp
"
;
8

9
this
.age
=
100
;
10

11
function
innerToString()
12

13
{
14

15
return
innerString;
16

17
}
18

19
}
20

21
var
f
=
new
foo();
22

23
var
eles
=
""
;
24

25
for
(property
in
f)
26

27
{
28

29
eles
+=
"
"
+
property;
30

31
}
32

33
document.write(eles);
34

35
输出为 "name age"
而没有
"innerString"
和
"innerToString()";
具体原理,以后有机会可以解释(包括私有变量,私有函数,私有函数的变量可
访问性等等)。
上面总结了种种继承方式的实现。但是每种方法都有其优缺点。
第一种方式,如何实现如下需求,需要显示
"3zfp__100";
1
var
BaseClass
=
function
(name,age)
2

3
{
4

5
this
.name
=
name;
6

7
this
.age
=
age;
8

9
this
.ToString
=
function
()
{
10

11
return
this
.name
+
"
"
+
this
.age;
12

13
}
14

15
}
16

17
var
Derived
=
function
(name,age)
18

19
{
20

21
this
.address
=
"
ShenZhen
"
;
22

23
}
24

25
Derived.prototype
=
new
BaseClass();
26

27
var
instance
=
new
Derived(
"
3zfp
"
,
100
);
28

29
document.write(instance.ToString());
30

31
我们通过运行可以发现,实际上输出的是 "undefined__undefined"
。也就是说
name
和
age
没有被赋值。
oh,my god!
天无绝人之路。第二和第三种方法可以实现,具体如下:
1
var
BaseClass
=
function
(name,age)
2

3
{
4

5
this
.name
=
name;
6

7
this
.age
=
age;
8

9
this
.ToString
=
function
()
{
10

11
return
this
.name
+
"
"
+
this
.age;
12

13
}
14

15
}
16

17
var
Derived
=
function
(name,age)
18

19
{
20

21
BaseClass.apply(
this
,
new
Array(name,age));
22

23
this
.address
=
"
ShenZhen
"
;
24

25
}
26

27
var
instance
=
new
Derived(
"
3zfp
"
,
100
);
28

29
document.write(instance.ToString());
30

31
______________________________________________
32

33
---------------------------------------------------------------------
34

35
var
BaseClass
=
function
(name,age)
36

37
{
38

39
this
.name
=
name;
40

41
this
.age
=
age;
42

43
this
.ToString
=
function
()
{
44

45
return
this
.name
+
"
"
+
this
.age;
46

47
}
48

49
}
50

51
var
Derived
=
function
(name,age)
52

53
{
54

55
BaseClass.call(
this
,name,age);
56

57
this
.address
=
"
ShenZhen
"
;
58

59
}
60

61
Derived.prototype
=
new
BaseClass();
62

63
var
instance
=
new
Derived(
"
3zfp
"
,
100
);
64

65
66

67
document.write(instance.ToString());
68

69
70
但是用
apply
方法也还是有缺点的,为什么?在
js
中,我们有个非常重要的运算符就是
"instanceof"
,该运算符用来比较某个对向是否为某种类型。
对于继承,我们除了是属于
Derived
类型,也应该是
BaseClass
类型,但是。
apply
方式返回值为
false(
(instance instanceof BaseClass) == false).
由于
prototype.js
使用了类似
apply
的方式,所以也会出现这个问题。
啊,终极方法就是
call+prototype
方式了,还是
google
牛
X
。您可以试一下是否正确
((instance instanceof BaseClass) == true)
。
最后,就是多重继承了,由于
js
中
prototype
只能对应一个对象,因此无法实现真正意义上的多重继承。有一个
js
库模拟了多重继承,
但是该库也额外重写了
instanceOf
方法,用
_instanceOf
和
_subclassOf
函数来模拟判断。该库的名字叫
modello.js
,感兴趣的可以搜索下载。
相关推荐
JavaScript继承机制探讨及其应用 JavaScript是一门弱类型语言,具有函数式编程和面向对象编程的特点。随着近几年JavaScript生态圈的发展和成熟,项目的编码量和复杂度也在呈几何级数增长。JavaScript面向对象编程中...
本文档将探讨JavaScript中的继承实现方式及其优缺点。 首先,我们需要理解JS中的对象与类的区别。在JS中,对象可以直接通过字面量语法创建,例如`var myObj = {...}`,这种对象不能通过`new`关键字实例化,因此它...
### JS继承的实现方式 JavaScript作为一种灵活且功能强大的编程语言,支持多种继承模式。下面将详细介绍几种常见的继承实现方式,并探讨它们的特点与应用场景。 #### 一、原型链继承 **核心思想**: 将父类的实例...
本文将深入探讨JavaScript中的封装和继承,以及它们在实际应用中的实现。 ### 封装(Encapsulation) 封装是面向对象编程中的关键概念,它涉及如何管理和保护数据,防止外部代码直接访问或修改对象的内部状态。在...
在本文中,我们将深入探讨JavaScript继承机制的实现方式,并对基于原型的继承、构造函数方式继承、组合继承、寄生式继承等继承机制进行了总结归纳和分析。 基于原型的继承 JavaScript是一门基于原型的语言,它不像...
接下来,我们将详细探讨这些继承方式。 ### 1. 原型链继承 原型链继承是通过将一个对象设置为另一个对象的原型,从而实现继承的一种方法。这种方式简单直观,但存在一些缺点,比如不能向父类传递初始化参数,且...
本篇文章将深入探讨JavaScript继承的实例,以及如何通过继承来提高代码的可维护性和效率。 首先,我们需要了解JavaScript中的原型(prototype)机制。每个JavaScript对象都有一个内部属性[[Prototype]],通常通过`_...
下面,我们将深入探讨JavaScript继承的各个方面。 1. 原型链继承: JavaScript的继承基于原型链,每个对象都有一个`__proto__`属性,指向创建它的构造函数的原型。通过`Object.create()`方法可以创建一个新对象并...
内容概要:本文详细介绍了 JavaScript 中几种经典的继承方式,重点解析了组合继承和圣杯模式两种常见做法。首先阐述了传统构造函数加原型链的方式来模拟类式的多层继承关系及其潜在问题;接着引入更为优雅且高效的...
本篇文章将深入探讨JavaScript实现继承的七种常见方式,帮助你更好地理解和运用这一概念。 1. 原型链继承(Prototype Chain Inheritance) 原型链是JavaScript实现继承的基础。每个函数都有一个`prototype`属性,这...
本篇将深入探讨一种实现继承的工具函数方法,主要聚焦于`source.js`文件中可能包含的内容。通过阅读这篇博文(链接已提供),我们可以学习如何构建自己的继承工具函数,并理解其工作原理。 在JavaScript中,常见的...
本文将深入探讨JavaScript中的类和继承,并结合`prototype.js`文件中的示例进行解析。 ### 类的概念与模拟 在JavaScript中,我们通常使用函数来模拟类的行为。一个函数可以看作是一个类的定义,通过`new`关键字来...
本文将深入探讨JavaScript继承的实现方式,以及其中的问题和解决方案。 首先,我们来看混合方式的实现,这种方式结合了原型链和对象冒充。在JavaScript中,构造函数是用于创建特定类型对象的函数。例如,`Employee`...
这篇文章将深入探讨这三个概念,以及如何实现类的继承。 首先,让我们理解什么是JavaScript中的对象。在JavaScript中,对象是一种数据结构,它可以存储键值对,其中键是字符串,值可以是任何类型的数据。对象可以...
这里我们将深入探讨JavaScript继承的特性以及实践应用。 首先,JavaScript的继承基于原型链。每个对象都有一个`__proto__`属性,指向创建它的构造函数的原型对象。当试图访问对象的一个属性时,JavaScript会沿着...
这里我们主要探讨三种实现JavaScript继承的方式:原型链继承、构造函数继承和组合继承。 首先,原型链继承是JavaScript最常用的继承方式。在JavaScript中,每个函数都有一个prototype属性,这个属性是一个对象,它...
1. **JavaScript继承** - **原理**:JavaScript的继承主要是通过原型链(prototype chain)来实现的。每个JavaScript对象都有一个内部属性[[Prototype]],通常可以通过`__proto__`访问,或通过`Object....
本篇文章将深入探讨JavaScript中实现继承的几种常见方式。 1. 原型链继承 JavaScript的原型(prototype)机制是实现继承的基础。每个函数都有一个prototype属性,这个属性指向一个对象,这个对象的属性和方法可以被...
在这个主题中,“javascript控件开发之继承关系”主要探讨的是如何利用JavaScript的面向对象特性来构建和组织控件的层次结构,以及如何通过继承来实现代码的复用和模块化。 在JavaScript中,继承是基于原型...
本文主要探讨五种经典的继承方式:原型式继承、原型链式继承、借用构造函数(类式继承)、组合继承以及寄生组合式继承。 1. **原型式继承**: 原型式继承是通过创建一个新对象,使其原型指向另一个对象,从而实现...