首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > JavaScript >

js沿袭探讨

2012-09-02 
js继承探讨var?BaseClass?function()?2?3{?4?5????this.name??3zfp?6?7????this.age??100?8?9????t

js继承探讨
var?BaseClass?=function()
?2js沿袭探讨
?3js沿袭探讨{
?4js沿袭探讨
?5js沿袭探讨????this.name?=?"3zfp";
?6js沿袭探讨
?7js沿袭探讨????this.age?=?100;
?8js沿袭探讨
?9js沿袭探讨????this.ToString?=?function(){
10js沿袭探讨
11js沿袭探讨????????return?this.name+"?"?+this.age;
12js沿袭探讨
13js沿袭探讨????}
14js沿袭探讨
15js沿袭探讨}
16js沿袭探讨
17js沿袭探讨var?Derived?=?function()
18js沿袭探讨
19js沿袭探讨{?
20js沿袭探讨
21js沿袭探讨????this.address?=?"ShenZhen";
22js沿袭探讨
23js沿袭探讨}
24js沿袭探讨
25js沿袭探讨Derived.prototype?=?new?BaseClass();
26js沿袭探讨
27js沿袭探讨var?instance?=?new?Derived();
28js沿袭探讨
29js沿袭探讨instance.ToString();
30js沿袭探讨

这种方式最为简单,只需要让一个类的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;如何验证呢?看如下代码:

1js沿袭探讨???????var?foo?=?function(){};
2js沿袭探讨
3js沿袭探讨???????var?result?=?(foo.prototype==Object);

这段代码的result 所得值为 false;

以下几个需要注意:

?1js沿袭探讨????typeof(Object.prototype)?==?"object";
?2js沿袭探讨
?3js沿袭探讨?
?4js沿袭探讨
?5js沿袭探讨???????typeof(Object.prototype.prototype)?==?"undefined";
?6js沿袭探讨
?7js沿袭探讨?
?8js沿袭探讨
?9js沿袭探讨???????var?obj?=?new?Object();
10js沿袭探讨
11js沿袭探讨???????typeof(obj.prototype)?==?"undefined";
12js沿袭探讨
13js沿袭探讨???????
14js沿袭探讨
15js沿袭探讨???????var?obj?=?{};
16js沿袭探讨
17js沿袭探讨???????typeof(obj.prototype)?==?"undefined";
18js沿袭探讨
19js沿袭探讨?
20js沿袭探讨
21js沿袭探讨

2、apply方式

?1js沿袭探讨var?BaseClass?=function()
?2js沿袭探讨
?3js沿袭探讨{
?4js沿袭探讨
?5js沿袭探讨????this.name?=?"3zfp";
?6js沿袭探讨
?7js沿袭探讨????this.age?=?100;
?8js沿袭探讨
?9js沿袭探讨????this.ToString?=?function(){
10js沿袭探讨
11js沿袭探讨????????return?this.name+"?"?+this.age;
12js沿袭探讨
13js沿袭探讨????}
14js沿袭探讨
15js沿袭探讨}
16js沿袭探讨
17js沿袭探讨var?Derived?=?function()
18js沿袭探讨
19js沿袭探讨{?
20js沿袭探讨
21js沿袭探讨???????BaseClass.apply(this,new?Array());
22js沿袭探讨
23js沿袭探讨????this.address?=?"ShenZhen";
24js沿袭探讨
25js沿袭探讨}
26js沿袭探讨
27js沿袭探讨var?instance?=?new?Derived();
28js沿袭探讨
29js沿袭探讨instance.ToString();
30js沿袭探讨
31js沿袭探讨?
32js沿袭探讨

?

在这种方式下,我们最需要理解的就是apply函数的作用。

该方法普遍的解释为用A方法去替换B方法。第一个参数为B方法的对象本身,第二个参数为一个数组,该数组内的值集合为需要传递给A方法对应的参数列表,如果参数为空,即没有参数传递,则通过 new Array() 来传递,null无效。

一般的方式为:

?

但是在本例当中,apply方法执行了两步操作。

?第一:将BaseClass以apply传递的Array数组作为初始化参数进行实例化。

?

第二:将新生成的实例对象的所有属性(name,age,ToString方法)复制到 instance实例对象。这样就实现了继承。

?

?1js沿袭探讨var?foo?=?function()
?2js沿袭探讨
?3js沿袭探讨{
?4js沿袭探讨
?5js沿袭探讨???????this.fooA?=?function(){
?6js沿袭探讨
?7js沿袭探讨??????????????this.fooB.apply(this,new?Array("sorry"));
?8js沿袭探讨
?9js沿袭探讨???????}
10js沿袭探讨
11js沿袭探讨???????this.fooB?=function(str)
12js沿袭探讨
13js沿袭探讨???????{
14js沿袭探讨
15js沿袭探讨??????????????alert(str);
16js沿袭探讨
17js沿袭探讨???????}
18js沿袭探讨
19js沿袭探讨}
20js沿袭探讨
21js沿袭探讨new?foo().fooA();
22js沿袭探讨

?3、call+prototype 方式

?1js沿袭探讨var?BaseClass?=function(name,age)
?2js沿袭探讨
?3js沿袭探讨{
?4js沿袭探讨
?5js沿袭探讨????this.name?=?name;
?6js沿袭探讨
?7js沿袭探讨????this.age?=?age;
?8js沿袭探讨
?9js沿袭探讨????this.ToString?=?function(){
10js沿袭探讨
11js沿袭探讨????????return?this.name+"?"?+this.age;
12js沿袭探讨
13js沿袭探讨????}
14js沿袭探讨
15js沿袭探讨}
16js沿袭探讨
17js沿袭探讨var?Derived?=?function()
18js沿袭探讨
19js沿袭探讨{?
20js沿袭探讨
21js沿袭探讨???????BaseClass.call(this,"3zfp",100);
22js沿袭探讨
23js沿袭探讨????this.address?=?"ShenZhen";
24js沿袭探讨
25js沿袭探讨}
26js沿袭探讨
27js沿袭探讨Derived.prototype?=?new?BaseClass();
28js沿袭探讨
29js沿袭探讨var?instance?=?new?Derived();
30js沿袭探讨
31js沿袭探讨instance.ToString();
32js沿袭探讨
33js沿袭探讨

?

其实,call函数和apply方式有很类似的作用,都是用A方法去替换B方法,但是参数传递不一样,call方法的第一个参数为B方法的对象本身,和面的参数列不用Array对象包装,直接依次传递就可以。

??????为什么作用类似,call方式的实现机制却要多一条 Derived.prototype = new BaseClass(); 语句呢?那是因为call方法只实现了方法的替换而没有作对象属性的复制操作。

?

例:

?1js沿袭探讨var?foo?=?function()
?2js沿袭探讨
?3js沿袭探讨{
?4js沿袭探讨
?5js沿袭探讨???????this.fooA?=?function(){
?6js沿袭探讨
?7js沿袭探讨??????????????this.fooB.call(this,"sorry");
?8js沿袭探讨
?9js沿袭探讨???????}
10js沿袭探讨
11js沿袭探讨???????this.fooB?=function(str)
12js沿袭探讨
13js沿袭探讨???????{
14js沿袭探讨
15js沿袭探讨??????????????alert(str);
16js沿袭探讨
17js沿袭探讨???????}
18js沿袭探讨
19js沿袭探讨}
20js沿袭探讨
21js沿袭探讨new?foo().fooA();
22js沿袭探讨
23js沿袭探讨

?

则 this.fooB.call(this,"sorry")执行了如下几个操作:

?

1js沿袭探讨this.temp?=?this.fooB;
2js沿袭探讨
3js沿袭探讨this.temp("sorry");
4js沿袭探讨
5js沿袭探讨delete?(this.temp);
6js沿袭探讨

?

其实,google Map API 的继承就是使用这种方式。大家可以下载的参考参考(maps.google.com)。

?

?

4、prototype.js中的实现方式

?1js沿袭探讨Object.extend?=?function(destination,?source)?{
?2js沿袭探讨
?3js沿袭探讨?for?(property?in?source)?{
?4js沿袭探讨
?5js沿袭探讨????destination[property]?=?source[property];
?6js沿袭探讨
?7js沿袭探讨?}
?8js沿袭探讨
?9js沿袭探讨???????return?destination;
10js沿袭探讨
11js沿袭探讨}
12js沿袭探讨
13js沿袭探讨var?BaseClass?=function(name,age){
14js沿袭探讨
15js沿袭探讨???????this.name?=?name;
16js沿袭探讨
17js沿袭探讨???????this.age?=?age;
18js沿袭探讨
19js沿袭探讨???????this.ToString?=?function(){
20js沿袭探讨
21js沿袭探讨??????????????return?this.name+"?"?+this.age;
22js沿袭探讨
23js沿袭探讨???????}
24js沿袭探讨
25js沿袭探讨}
26js沿袭探讨
27js沿袭探讨var?Derived?=function()
28js沿袭探讨
29js沿袭探讨{?????
30js沿袭探讨
31js沿袭探讨???????BaseClass.call(this,"foo",100);
32js沿袭探讨
33js沿袭探讨???????this.address?=?"singapore";
34js沿袭探讨
35js沿袭探讨???????this.ToString?=?function(){
36js沿袭探讨
37js沿袭探讨??????????????var?string?=?Derived.prototype.ToString.call(this);
38js沿袭探讨
39js沿袭探讨??????????????return?string?+"?"+?this.address;
40js沿袭探讨
41js沿袭探讨???????}
42js沿袭探讨
43js沿袭探讨}
44js沿袭探讨
45js沿袭探讨Object.extend(Derived.prototype,new?BaseClass());
46js沿袭探讨
47js沿袭探讨var?instance?=?new?Derived();
48js沿袭探讨
49js沿袭探讨document.write(instance.ToString());

?

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

?

?1js沿袭探讨var?foo?=?function()
?2js沿袭探讨
?3js沿袭探讨{
?4js沿袭探讨
?5js沿袭探讨???????var?innerString?=?"";
?6js沿袭探讨
?7js沿袭探讨???????this.name?=?"3zfp";
?8js沿袭探讨
?9js沿袭探讨???????this.age?=?100;
10js沿袭探讨
11js沿袭探讨???????function?innerToString()
12js沿袭探讨
13js沿袭探讨???????{
14js沿袭探讨
15js沿袭探讨??????????????return?innerString;
16js沿袭探讨
17js沿袭探讨???????}
18js沿袭探讨
19js沿袭探讨}
20js沿袭探讨
21js沿袭探讨var?f?=new?foo();
22js沿袭探讨
23js沿袭探讨var?eles?=?"";
24js沿袭探讨
25js沿袭探讨for?(property?in?f)
26js沿袭探讨
27js沿袭探讨{
28js沿袭探讨
29js沿袭探讨???????eles+="?"+property;
30js沿袭探讨
31js沿袭探讨}
32js沿袭探讨
33js沿袭探讨document.write(eles);?
34js沿袭探讨
35js沿袭探讨

?

输出为 "name age"而没有"innerString" 和 "innerToString()";具体原理,以后有机会可以解释(包括私有变量,私有函数,私有函数的变量可访问性等等)。上面总结了种种继承方式的实现。但是每种方法都有其优缺点。

?

第一种方式,如何实现如下需求,需要显示 "3zfp__100";

?1js沿袭探讨var?BaseClass?=function(name,age)
?2js沿袭探讨
?3js沿袭探讨{
?4js沿袭探讨
?5js沿袭探讨????this.name?=?name;
?6js沿袭探讨
?7js沿袭探讨????this.age?=?age;
?8js沿袭探讨
?9js沿袭探讨????this.ToString?=?function(){
10js沿袭探讨
11js沿袭探讨????????return?this.name+"?"?+this.age;
12js沿袭探讨
13js沿袭探讨????}
14js沿袭探讨
15js沿袭探讨}
16js沿袭探讨
17js沿袭探讨var?Derived?=?function(name,age)
18js沿袭探讨
19js沿袭探讨{?
20js沿袭探讨
21js沿袭探讨????this.address?=?"ShenZhen";
22js沿袭探讨
23js沿袭探讨}
24js沿袭探讨
25js沿袭探讨Derived.prototype?=?new?BaseClass();
26js沿袭探讨
27js沿袭探讨var?instance?=?new?Derived("3zfp",100);
28js沿袭探讨
29js沿袭探讨document.write(instance.ToString());
30js沿袭探讨
31js沿袭探讨

?

我们通过运行可以发现,实际上输出的是 "undefined__undefined"。也就是说name和age没有被赋值。

oh,my god!天无绝人之路。第二和第三种方法可以实现,具体如下:

?

?1js沿袭探讨var?BaseClass?=function(name,age)
?2js沿袭探讨
?3js沿袭探讨{
?4js沿袭探讨
?5js沿袭探讨????this.name?=?name;
?6js沿袭探讨
?7js沿袭探讨????this.age?=?age;
?8js沿袭探讨
?9js沿袭探讨????this.ToString?=?function(){
10js沿袭探讨
11js沿袭探讨????????return?this.name+"?"?+this.age;
12js沿袭探讨
13js沿袭探讨????}
14js沿袭探讨
15js沿袭探讨}
16js沿袭探讨
17js沿袭探讨var?Derived?=?function(name,age)
18js沿袭探讨
19js沿袭探讨{?
20js沿袭探讨
21js沿袭探讨???????BaseClass.apply(this,new?Array(name,age));
22js沿袭探讨
23js沿袭探讨????this.address?=?"ShenZhen";
24js沿袭探讨
25js沿袭探讨}
26js沿袭探讨
27js沿袭探讨var?instance?=?new?Derived("3zfp",100);
28js沿袭探讨
29js沿袭探讨document.write(instance.ToString());
30js沿袭探讨
31js沿袭探讨______________________________________________
32js沿袭探讨
33js沿袭探讨---------------------------------
34js沿袭探讨
35js沿袭探讨var?BaseClass?=function(name,age)
36js沿袭探讨
37js沿袭探讨{
38js沿袭探讨
39js沿袭探讨????this.name?=?name;
40js沿袭探讨
41js沿袭探讨????this.age?=?age;
42js沿袭探讨
43js沿袭探讨????this.ToString?=?function(){
44js沿袭探讨
45js沿袭探讨????????return?this.name+"?"?+this.age;
46js沿袭探讨
47js沿袭探讨????}
48js沿袭探讨
49js沿袭探讨}
50js沿袭探讨
51js沿袭探讨var?Derived?=?function(name,age)
52js沿袭探讨
53js沿袭探讨{?
54js沿袭探讨
55js沿袭探讨???????BaseClass.call(this,name,age);
56js沿袭探讨
57js沿袭探讨????this.address?=?"ShenZhen";
58js沿袭探讨
59js沿袭探讨}
60js沿袭探讨
61js沿袭探讨Derived.prototype?=?new?BaseClass();
62js沿袭探讨
63js沿袭探讨var?instance?=?new?Derived("3zfp",100);
64js沿袭探讨
65js沿袭探讨?
66js沿袭探讨
67js沿袭探讨document.write(instance.ToString());
68js沿袭探讨
69js沿袭探讨?
70js沿袭探讨

??????

但是用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,感兴趣的可以搜索下载。

?

热点排行