JavaScript笔记 - 对象继承的几种方式
2008-08-25 11:16
627 查看
1)对象冒充
2)call方式
3)apply方式
4)原型链
5)混合方式
1)对象冒充
Js代码 var BaseClass =function()
2
3
17var Derived = function()
18
19
25Derived.prototype = new BaseClass();
26
27var instance = new Derived();
28
29instance.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
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
17 typeof(obj.prototype) == "undefined";
18
19
20
21
2、apply方式
1var BaseClass =function()
2
3
17var Derived = function()
18
19
27var instance = new Derived();
28
29instance.ToString();
30
31
32
在这种方式下,我们最需要理解的就是apply函数的作用。
该方法普遍的解释为用A方法去替换B方法。第一个参数为B方法的对象本身,第二个参数为一个数组,该数组内的值集合为需要传递给A方法对应的参数列表,如果参数为空,即没有参数传递,则通过 new Array() 来传递,null无效。
一般的方式为:
但是在本例当中,apply方法执行了两步操作。
第一:将BaseClass以apply传递的Array数组作为初始化参数进行实例化。
第二:将新生成的实例对象的所有属性(name,age,ToString方法)复制到 instance实例对象。这样就实现了继承。
1var foo = function()
2
3
21new foo().fooA();
22
3、call+prototype 方式
1var BaseClass =function(name,age)
2
3
17var Derived = function()
18
19
27Derived.prototype = new BaseClass();
28
29var instance = new Derived();
30
31instance.ToString();
32
33
其实,call函数和apply方式有很类似的作用,都是用A方法去替换B方法,但是参数传递不一样,call方法的第一个参数为B方法的对象本身,和面的参数列不用Array对象包装,直接依次传递就可以。
为什么作用类似,call方式的实现机制却要多一条 Derived.prototype = new BaseClass(); 语句呢?那是因为call方法只实现了方法的替换而没有作对象属性的复制操作。
call方法实际上是做了如下几个操作:
例:
1var foo = function()
2
3
21new foo().fooA();
22
23
则 this.fooB.call(this,"sorry")执行了如下几个操作:
1this.temp = this.fooB;
2
3this.temp("sorry");
4
5delete (this.temp);
6
其实,google Map API 的继承就是使用这种方式。大家可以下载的参考参考(maps.google.com)。
4、prototype.js中的实现方式
1
13
27var Derived =function()
28
29
45Object.extend(Derived.prototype,new BaseClass());
46
47var instance = new Derived();
48
49document.write(instance.ToString());
该方式,实际上是显式的利用了apply的原理来实现继承。先 var temp = new BaseClass(),再将 temp 的属性遍历复制到Derived.prototype中。for (property in source) 表示遍历某个对象的所有属性。但是私有属性无法遍历。例:
1var foo = function()
2
3
21var f =new foo();
22
23var eles = "";
24
25for (property in f)
26
27
33document.write(eles);
34
35
输出为 "name age"而没有"innerString" 和 "innerToString()";具体原理,以后有机会可以解释(包括私有变量,私有函数,私有函数的变量可访问性等等)。上面总结了种种继承方式的实现。但是每种方法都有其优缺点。
第一种方式,如何实现如下需求,需要显示 "3zfp__100";
1var BaseClass =function(name,age)
2
3
17var Derived = function(name,age)
18
19
25Derived.prototype = new BaseClass();
26
27var instance = new Derived("3zfp",100);
28
29document.write(instance.ToString());
30
31
我们通过运行可以发现,实际上输出的是 "undefined__undefined"。也就是说name和age没有被赋值。
oh,my god!天无绝人之路。第二和第三种方法可以实现,具体如下:
1var BaseClass =function(name,age)
2
3
17var Derived = function(name,age)
18
19
27var instance = new Derived("3zfp",100);
28
29document.write(instance.ToString());
30
31______________________________________________
32
33---------------------------------------------------------------------
34
35var BaseClass =function(name,age)
36
37
51var Derived = function(name,age)
52
53
61Derived.prototype = new BaseClass();
62
63var instance = new Derived("3zfp",100);
64
65
66
67document.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,感兴趣的可以搜索下载。
2)call方式
3)apply方式
4)原型链
5)混合方式
1)对象冒充
Js代码 var BaseClass =function()
2
3
17var Derived = function()
18
19
25Derived.prototype = new BaseClass();
26
27var instance = new Derived();
28
29instance.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
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
17 typeof(obj.prototype) == "undefined";
18
19
20
21
2、apply方式
1var BaseClass =function()
2
3
17var Derived = function()
18
19
27var instance = new Derived();
28
29instance.ToString();
30
31
32
在这种方式下,我们最需要理解的就是apply函数的作用。
该方法普遍的解释为用A方法去替换B方法。第一个参数为B方法的对象本身,第二个参数为一个数组,该数组内的值集合为需要传递给A方法对应的参数列表,如果参数为空,即没有参数传递,则通过 new Array() 来传递,null无效。
一般的方式为:
但是在本例当中,apply方法执行了两步操作。
第一:将BaseClass以apply传递的Array数组作为初始化参数进行实例化。
第二:将新生成的实例对象的所有属性(name,age,ToString方法)复制到 instance实例对象。这样就实现了继承。
1var foo = function()
2
3
21new foo().fooA();
22
3、call+prototype 方式
1var BaseClass =function(name,age)
2
3
17var Derived = function()
18
19
27Derived.prototype = new BaseClass();
28
29var instance = new Derived();
30
31instance.ToString();
32
33
其实,call函数和apply方式有很类似的作用,都是用A方法去替换B方法,但是参数传递不一样,call方法的第一个参数为B方法的对象本身,和面的参数列不用Array对象包装,直接依次传递就可以。
为什么作用类似,call方式的实现机制却要多一条 Derived.prototype = new BaseClass(); 语句呢?那是因为call方法只实现了方法的替换而没有作对象属性的复制操作。
call方法实际上是做了如下几个操作:
例:
1var foo = function()
2
3
21new foo().fooA();
22
23
则 this.fooB.call(this,"sorry")执行了如下几个操作:
1this.temp = this.fooB;
2
3this.temp("sorry");
4
5delete (this.temp);
6
其实,google Map API 的继承就是使用这种方式。大家可以下载的参考参考(maps.google.com)。
4、prototype.js中的实现方式
1
13
27var Derived =function()
28
29
45Object.extend(Derived.prototype,new BaseClass());
46
47var instance = new Derived();
48
49document.write(instance.ToString());
该方式,实际上是显式的利用了apply的原理来实现继承。先 var temp = new BaseClass(),再将 temp 的属性遍历复制到Derived.prototype中。for (property in source) 表示遍历某个对象的所有属性。但是私有属性无法遍历。例:
1var foo = function()
2
3
21var f =new foo();
22
23var eles = "";
24
25for (property in f)
26
27
33document.write(eles);
34
35
输出为 "name age"而没有"innerString" 和 "innerToString()";具体原理,以后有机会可以解释(包括私有变量,私有函数,私有函数的变量可访问性等等)。上面总结了种种继承方式的实现。但是每种方法都有其优缺点。
第一种方式,如何实现如下需求,需要显示 "3zfp__100";
1var BaseClass =function(name,age)
2
3
17var Derived = function(name,age)
18
19
25Derived.prototype = new BaseClass();
26
27var instance = new Derived("3zfp",100);
28
29document.write(instance.ToString());
30
31
我们通过运行可以发现,实际上输出的是 "undefined__undefined"。也就是说name和age没有被赋值。
oh,my god!天无绝人之路。第二和第三种方法可以实现,具体如下:
1var BaseClass =function(name,age)
2
3
17var Derived = function(name,age)
18
19
27var instance = new Derived("3zfp",100);
28
29document.write(instance.ToString());
30
31______________________________________________
32
33---------------------------------------------------------------------
34
35var BaseClass =function(name,age)
36
37
51var Derived = function(name,age)
52
53
61Derived.prototype = new BaseClass();
62
63var instance = new Derived("3zfp",100);
64
65
66
67document.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笔记——对象的几种生成方式
- 韩顺平_轻松搞定网页设计(html+css+javascript)_第30讲_类和对象细节_创建对象的几种方式_js对象内存分析_学习笔记_源代码图解_PPT文档整理
- Javascript笔记-定义对象的几种方式
- 韩顺平 javascript教学视频_学习笔记13_类和对象细节_创建对象的几种方式_js对象内存分析
- JavaScript中对象的定义和继承的几种方式
- javascript 对象继承的几种方式
- JavaScript中对象的定义和继承的几种方式
- javascript(js)创建对象的模式与继承的几种方式
- JavaScript学习12 JS中定义对象的几种方式
- javascript继承对象冒充方式
- JavaScript中实现继承的几种方式
- Javascript创建对象的几种方式【转】
- javascript 创建对象的几种方式
- JavaScript中的String对象的常用方法、文本框对象的常用方法和事件、正则表达式的概念、正则表达式的几种构造方式、RegExp对象使用什么方法匹配正则表达式、
- JavaScript的弱类对象及继承实现方式
- JavaScript中创建对象的几种方式
- javascript实现继承的几种方式
- JavaScript中实现继承的几种方式的使用和分析
- JavaScript 创建对象的几种方式?