JavaScript面向对象编程指南(六) 继承

第6章 继承

6.1 原型链

6.1.1原型链示例

原型链法:Child.prototype=new Parent();

 1     <script>
 2         function Shape(){
 3             this.name='shape';
 4             this.toString=function (){
 5                 return this.name;
 6             };
 7         }
 8         function TwoDShape(){
 9             this.name='2D shape';
10         }
11         function Triangle(side,height){
12             this.name='Triangle';
13             this.side=side;
14             this.height=height;
15             this.getArea=function(){
16                 return this.side*this.height/2;
17             };
18         }
19         TwoDShape.prototype=new Shape();//TwoDShape对象的原型等于Shape对象的实体
20         Triangle.prototype=new TwoDShape();
21         TwoDShape.prototype.constructor=TwoDShape; //确保原型的构造函数没有发生改变
22         Triangle.prototype.constructor=Triangle;
23         
24         var my=new Triangle(5,10);
25         my.getArea();// 25
26         my.toString();//"Triangle"
27     </script>

6.1.2 将共享属性迁移到原型中去

 1 <script>
 2         function Shape(){};
 3         //共享属性放置在原型中
 4             Shape.prototype.name='Shape';
 5             Shape.prototype.toString=function(){
 6                 return this.name;
 7             };
 8 
 9 
10         function TwoDShape(){};
11 
12         //设置继承  在对象原型扩展前完成继承,后续新内容有可能抹掉我们继承的东西
13         TwoDShape.prototype=new Shape();
14         TwoDShape.prototype.constructor=TwoDShape;
15 
16         // 扩展原型
17         TwoDShape.prototype.name='2D Shape';
18 
19 
20         function Triangle(side,height){
21             this.side=side;
22             this.height=height;
23         }
24 
25         //设置继承
26         Triangle.prototype=new TwoDShape();
27         Triangle.prototype.constructor=Triangle;
28 
29         //扩展原型
30         Triangle.prototype.name='Triangle';
31         Triangle.prototype.getArea=function(){
32             return this.side*this.height/2;
33         };
34 
35         var my=new Triangle(5,10);
36         my.getArea();// 25
37         my.toString();//"Triangle"
38     </script>

6.2 只继承于原型

原型继承法:Child.prototype= Parent.prototype;

 1 <script>
 2       function Shape(){};
 3 
 4       //共享属性放在原型中
 5       Shape.prototype.name='shape';
 6       Shape.prototype.toString=function(){
 7         return this.name;
 8       };
 9 
10 
11       //新建构造函数TwoDShape
12       function TwoDShape(){};
13       //设置原型继承
14       TwoDShape.prototype=Shape.prototype;
15       TwoDShape.prototype.constructor=TwoDShape;
16       //扩展原型
17       TwoDShape.prototype.name='2D Shape';
18 
19 
20       /****新建构造函数Triangle****/
21       function Triangle(side,height){
22         this.height=height;
23         this.side=side;
24       };
25       //设置继承
26       Triangle.prototype=TwoDShape.prototype;
27       Triangle.prototype.constructor=Triangle;
28       //扩展原型
29       Triangle.prototype.name='Triangle';
30       Triangle.prototype.getArea=function(){
31         return this.height*this.side/2;
32       }
33 
34         var my=new Triangle(5,10);
35         my.getArea();// 25
36         my.toString();//"Triangle"
37   </script>

临时构造器——new F();

 1         function Shape(){};
 2 
 3       //共享属性放在原型中
 4       Shape.prototype.name='shape';
 5       Shape.prototype.toString=function(){
 6         return this.name;
 7       };
 8 
 9       //新建构造函数TwoDShape
10       function TwoDShape(){};
11       //使用临时构造器设置原型继承
12       var F=function(){};
13       F.prototype=Shape.prototype;
14       TwoDShape.prototype=new F();
15       TwoDShape.prototype.constructor=TwoDShape;
16       //扩展原型
17       TwoDShape.prototype.name='2D Shape';
18 
19 
20        /****新建构造函数Triangle****/
21       function Triangle(side,height){
22         this.height=height;
23         this.side=side;
24       };
25       //使用临时构造器设置原型继承
26       var F=function(){};
27       F.prototype=TwoDShape.prototype;
28       Triangle.prototype=new F();
29       Triangle.prototype.constructor=Triangle;
30       //扩展原型
31       Triangle.prototype.name='Triangle';
32       Triangle.prototype.getArea=function(){
33         return this.height*this.side/2;
34       };

6.3 uber——子对象访问父对象的方式

 1 <script>
 2         function Shape(){};
 3          //共享属性放在原型中
 4         Shape.prototype.name='shape';
 5         //检查对象中是否存在this.constructor.uber方法,如果存在就调用该函数的toString方法。this.constructor.uber指向当前对象父级函数的引用
 6         Shape.prototype.toString=function(){
 7             return this.constructor.uber
 8             ?this.constructor.uber.toString() + ',' + this.name:this.name;
 9         };
10 
11         //新建构造函数TwoDShape
12         function TwoDShape(){};
13         //使用临时构造器设置原型继承
14         var F=function (){};
15         F.prototype=Shape.prototype;
16         TwoDShape.prototype=new F();
17         TwoDShape.prototype.constructor=TwoDShape;
18         //将uber属性设置为指向父级原型的引用
19         TwoDShape.uber=Shape.prototype;
20         //扩展原型
21         TwoDShape.prototype.name='2D shape';
22 
23          /****新建构造函数Triangle****/
24          function Triangle(side,height){
25             this.side=side;
26             this.height=height;
27          };
28          //使用临时构造器设置原型继承
29          var F=function(){};
30          F.prototype=TwoDShape.prototype;
31          Triangle.prototype=new F();
32          Triangle.prototype.constructor=Triangle;
33          //将uber属性设置为指向父级原型的引用
34          Triangle.uber=TwoDShape.prototype;
35          //扩展原型
36          Triangle.prototype.name='Triangle';
37          Triangle.prototype.getArea=function(){
38             return this.side*this.height/2;
39          };
40          var my=new Triangle(5,10);
41          my.getArea();// 25
42          my.toString(); // "shape,2D shape,Triangle"
43    </script>

 6.4 将继承部分封装为函数

临时构造器法:

 1     <script>
 2         //临时构造器法:将继承部分封装为函数
 3         //优点:简洁、重用
 4         function extend(Child,Parent){
 5             var F=function (){};
 6             F.prototype=Parent.prototype;
 7             Child.prototype=new F();
 8             Child.prototype.constructor=Child;
 9             Child.uber=Parent.prototype;
10         }
11         function Shape(){};
12          //共享属性放在原型中
13         Shape.prototype.name='shape';
14         //检查对象中是否存在this.constructor.uber方法,如果存在就调用该函数的toString方法。this.constructor.uber指向当前对象父级函数的引用
15         Shape.prototype.toString=function(){
16             return this.constructor.uber
17             ?this.constructor.uber.toString() + ',' + this.name:this.name;
18         };
19 
20         //新建构造函数TwoDShape
21         function TwoDShape(){};
22         extend(TwoDShape,Shape); //使用封装函数,完成继承
23          //扩展原型
24         TwoDShape.prototype.name='2D shape';
25 
26          /****新建构造函数Triangle****/
27          function Triangle(side,height){
28             this.side=side;
29             this.height=height;
30          };
31          //继承
32          extend(Triangle,TwoDShape);
33          //扩展原型
34          Triangle.prototype.name='Triangle';
35          Triangle.prototype.getArea=function(){
36             return this.side*this.height/2;
37          };
38 
39         // 测试
40         var my=new Triangle();
41         my.toString();  //"shape,2D shape,Triangle"
42     </script>

 6.5 属性拷贝

 1     <script>
 2         //临时构造器法:将继承部分封装为函数
 3         //优点:简洁、重用
 4         function extend(Child,Parent){
 5             var F=function (){};
 6             F.prototype=Parent.prototype;
 7             Child.prototype=new F();
 8             Child.prototype.constructor=Child;
 9             Child.uber=Parent.prototype;
10         }
11         //将父对象的属性拷贝给子对象
12         // 只适用只包含基本数据类型的对象
13         function extend2(Child,Parent){
14             var c=Child.prototype;
15             var p=Parent.prototype;
16             for(var i in p){
17                 c[i]=p[i];
18             };
19             c.uber=p;
20         }
21 
22         function Shape(){};
23         Shape.prototype.name='shape';
24         Shape.prototype.toString=function(){
25             return this.uber
26               ?this.uber.toString()+','+this.name
27                 :this.name;
28         };
29 
30         function TwoDShape(){};
31 
32         extend(TwoDShape,Shape);
33         // 示例
34         var my=new TwoDShape();
35         //通过extend方法获得继承,name属性不会是TwoDShape实例的属性
36         //也不是其原型对象的属性,但仍可以通过继承方式来访问
37         my.name;//"shape"
38         TwoDShape.prototype.name;//"shape"
39         my.hasOwnProperty('name');//false
40         my.__proto__.hasOwnProperty('name');//false
41 
42         extend2(TwoDShape,Shape);
43         // //通过extend方法获得继承
44          var my1=new TwoDShape();
45 
46         my1.__proto__.hasOwnProperty('name'); // true
47         my1.toString();// "shape,shape"
48     </script>

 6.6 小心处理引用拷贝

 1     <script>
 2     //原型属性拷贝
 3     function extend2(Child, Parent){
 4         var c=Child.prototype;
 5         var p=Parent.prototype;
 6         for(var i in p){
 7             c[i]=p[i];
 8         }
 9         c.uber=p;
10     }
11         function F1(){};
12         function F2(){};
13         F1.prototype.name='Alen';
14         F1.prototype.owns=['aa','bb','cc'];
15 
16         //继承
17         extend2(F2,F1);
18         F2.prototype.hasOwnProperty('name'); //true
19         F2.prototype.hasOwnProperty('owns');// true
20         //name是基本类型属性,创建的是全新的拷贝
21         //owns属性是一个数组对象,执行的是引用拷贝
22         F2.prototype.owns;  //["aa", "bb", "cc"]
23         // 改变F2中的name属性,不会对F1产生影响
24         F2.prototype.name+=',liMing';//"Alen,liMing"
25         F1.prototype.name;//"Alen"
26         F2.prototype.owns.pop();//"cc"  移除F2最后一个元素
27         F1.prototype.owns; // ["aa", "bb"]  F1受到影响
28     </script>

 6.7 对象之间的继承

 1 <script>
 2       //浅拷贝  没有使用原型对象
 3       function extendCopy(p){
 4         var c={};
 5         for(var i in p){
 6             c[i]=p[i];
 7         }
 8         c.uber=p;
 9         return c;
10       }
11 
12       //使用对象表达式创建对象
13       var shape={
14         name:'shape',
15         toString:function(){
16             return this.name;
17         }
18       };
19       // 使用extendCopy创建新对象
20       var f1=extendCopy(shape);
21       // 对新对象进行扩展
22       f1.name='2D shape';
23       f1.toString=function (){
24         return this.uber.toString()+', '+this.name;
25       };
26       // 让新对象继承f1
27       var triangle=extendCopy(f1);
28       // 进行扩展
29       triangle.name='Triangle';
30       triangle.getArea=function(){
31         return this.side*this.height/2;
32       };
33       // 初始化对象  缺点:初始化对象较麻烦
34       triangle.side=5;
35       triangle.height=10;
36       triangle.getArea();// 25
37       triangle.toString(); //"shape, 2D shape, Triangle"
38 
39   </script>

 6.8 深拷贝

浅拷贝:当拷贝对象时,实际上只拷贝了该对象在内存中的位置指针。

深拷贝:也通过遍历对象的属性来进行拷贝操作。当遇到对象引用性的操作时,需要再次调用深拷贝函数。

 1     <script>
 2         //浅拷贝
 3         function extendCopy(p){
 4             var c={};
 5             for(var i in p){
 6                 c[i]=p[i];
 7             }
 8             c.uber=p;
 9             return c;
10         }
11 
12         //深拷贝
13         function deepCopy(p,c){
14             c=c || {};
15             for(var i in p){
16                 if(p.hasOwnProperty(i)){
17                     if(typeof p[i] === 'object'){        //判断是否为对象
18                         c[i]=Array.isArray(p[i])? []:{}; //判断是否为数组
19                         deepCopy(p[i],c[i]);
20                     }else{
21                         c[i]=p[i];
22                     }
23                 }
24             }
25             return c;
26         }
27         // 实例
28         var parent={
29             numbers:[1,2,4],
30             letters:['a','b','c'],
31             obj:{
32                 prop:1
33             },
34             bool:true
35         };
36         var mydeep=deepCopy(parent);
37         var myshallow=extendCopy(parent);
38         //深拷贝
39         mydeep.numbers.push(4,5,6);//[1, 2, 4, 4, 5, 6]
40         parent.numbers;// [1, 2, 4]   深拷贝不会对父对象产生影响
41         //浅拷贝
42         myshallow.numbers.push(10);
43         myshallow.numbers;//[1, 2, 4, 10]
44         parent.numbers;// [1, 2, 4, 10]   浅拷贝父对象受影响
45         mydeep.numbers;//[1, 2, 4, 4, 5, 6]
46     </script>

 6.9 object()

原型继承法:

 1    <script>
 2        function object(o){
 3         function F(){};
 4         F.prototype=o;
 5         return new F();
 6        }
 7        //访问uber函数
 8        function object1(o){
 9         var n;
10         function F(){};
11         F.prototype=o;
12         n=new F();
13         n.uber=o;
14         return n;
15        }
16 
17       //浅拷贝  没有使用原型对象
18       function extendCopy(p){
19         var c={};
20         for(var i in p){
21             c[i]=p[i];
22         }
23         c.uber=p;
24         return c;
25       }
26 
27       //使用对象表达式创建对象
28       var shape={
29         name:'shape',
30         toString:function(){
31             return this.name;
32         }
33       };
34       // 使用extendCopy创建新对象
35       var f1=extendCopy(shape);
36       // 对新对象进行扩展
37       f1.name='2D shape';
38       f1.toString=function (){
39         return this.uber.toString()+', '+this.name;
40       };
41 
42       //使用object1()
43       var triangle=object1(f1);
44       // 进行扩展
45       triangle.name='Triangle';
46       triangle.getArea=function(){
47         return this.side*this.height/2;
48       };
49 
50       triangle.toString();//"shape, 2D shape, Triangle"
51 
52      // 使用Object.create()方法
53       var f2=Object.create(triangle);
54       f2.toString(); //"shape, 2D shape, Triangle"
55 
56    </script>

 6.10 原型继承与属性拷贝的混合应用

 1     <script>
 2     // o:用于继承  stuff:用于拷贝方法和属性
 3         function objectPlus(o,stuff){
 4             var n;
 5             function F(){};
 6             F.prototype=o;
 7             n=new F();
 8             n.uber=o;
 9 
10             for(var i in stuff){
11                 n[i]=stuff[i];
12             }
13             return n;
14         }
15     //实例
16     var shape={
17         name:'shape',
18         toString:function (){
19             return this.name;
20         }
21     }
22     //创建继承对象
23     var twoDee=objectPlus(shape,{
24         name:'2D shape',
25         toString:function(){
26             return this.uber.toString()+', '+this.name;
27         }
28     })
29     var triangle=objectPlus(twoDee,{
30         name:'Triangle',
31         getArea:function(){
32             return this.side*this.height/2;
33         },
34         side:0,
35         height:0
36     });
37     var my=objectPlus(triangle,{
38         side:4,height:4
39     });
40     my.getArea(); //8
41     my.toString();//"shape, 2D shape, Triangle, Triangle"
42     //因为在具体化实例时是继承于triangle的,所以多了一层继承关系
43     var my1=objectPlus(triangle,{
44         side:4,
45         height:4,
46         name:'my1'
47     });
48     my1.toString();//"shape, 2D shape, Triangle, my1"
49     </script>

 6.11 多重继承

一个子对象中有不知一个父对象的继承模式。

 1 <script>
 2         function multi(){
 3             var n={};
 4             for (var j = 0; j < arguments.length; j++) {
 5                 stuff=arguments[j];
 6                 for(var i in stuff){
 7                     n[i]=stuff[i];
 8                 }
 9             }
10             return n;
11         }
12         //实例
13        var shape={
14             name:'shape',
15             toString:function (){
16                return this.name;
17            }
18         }
19         var twoDee={
20             name:'2D shape',
21             dimensions:2
22         };
23         var triangle=multi(shape,twoDee,{
24             name:'Triangle',
25             getArea:function(){
26             return this.side*this.height/2;
27             },
28             side:5,
29             height:10
30         });
31         triangle.getArea();//25
32         triangle.dimensions; //2 继承自twoDee
33         triangle.toString(); //"Triangle"
34     </script>

 6.12 寄生式继承

 1     <script>
 2         function object(o){
 3             var n;
 4             function F(){};
 5             F.prototype=o;
 6             n=new F();
 7             n.uber=o;
 8             return n;
 9             }
10         var twoDee={
11             name:'2D shape',
12             dimensions:2
13         };
14         function triangle(s,h){
15             var that=object(twoDee);
16             that.name='Triangle';
17             that.getArea=function(){
18                 return this.side*this.height/2;
19             };
20             that.side=s;
21             that.height=h;
22             return that;
23         }
24         var t=triangle(5,10);
25         t.getArea();//25
26         t.dimensions;//2
27     </script>

 6.13 构造器借用

 

 1     <script>
 2         function Child(){
 3            Parent.apply(this,arguments);
 4         }
 5         //父对象
 6         function Shape(id){
 7             this.id=id;
 8         }
 9         Shape.prototype.name='shape';
10         Shape.prototype.toString=function(){
11             return this.name;
12         }
13         //子对象
14         function Triangle(){
15             Shape.apply(this, arguments);
16         }
17         Triangle.prototype.name='Triangle';
18 
19         var t=new Triangle(12);
20         t.name;//"Triangle"
21         t.id;//12
22         t.toString();//"[object Object]" Shape()函数未实例化
23         //原型函数未用到
24 
25         // 修改1
26         function Triangle1(){
27             Shape.apply(this, arguments);
28         }
29         Triangle.prototype=new Shape(101);
30         Triangle.prototype.name='Triangle';
31         var t1=new Triangle(201);
32         t1.id;//201
33         delete t1.id;//true
34         t1.id;//101
35         //缺点:父对象的构造器被继承调用了两次,一次通过apply、一次通过new
36 
37         // 修改2:借用构造器与原型复制
38         // 原型属性拷贝法
39         function extend2(Child,Parent){
40             var p=Parent.prototype;
41             var c=Child.prototype;
42             for(var i in p){
43                 c[i]=p[i];
44             }
45             c.uber=p;
46             return c;
47         }
48         function Triangle2(){
49             Shape.apply(this, arguments);
50         };
51         extend2(Triangle2,Shape);
52         Triangle2.prototype.name='Triangle';
53         var t2=new Triangle2(101);
54         t2.toString();//"Triangle"
55         t2.id;//101
56         typeof t2.__proto__.id; //"undefined"      ok!
57     </script>

 

posted @ 2017-07-29 09:46  锋aa  阅读(370)  评论(0编辑  收藏  举报