第5章-继承

JavaScript提供了一套丰富的代码重用模式。它可以模拟那些基于类的模式,同时可以支持其他更具表现力的模式。我们下面将研究几种最为直接的模式。

 

伪类 Pseudoclassical

JavaScript的原型存在这许多的矛盾,它不直接让对象从其他对象继承,反而插入了一个多余的间接层:通过构造函数产生对象。
当一个函数对象被创建时,Function构造器产生的函数对象会运行类似这样的一些代码:
this.prototype = {constructor: this};
新函数对象被赋予一个Prototype属性,它的值是一个包含consrtuctor属性且属性值为该新函数的对象。
我们可以定义一个构造器并扩充它的原型

 1     var Mammal = function(name){
 2         this.name = name;
 3     };
 4 
 5     Mammal.prototype.get_name = function(){
 6         return this.name;
 7     };
 8 
 9     Mammal.prototype.says = function(){
10         return this.saying || '';
11     };
12 
13     var mymammal = new Mammal('QQQ');
14     var name = mymammal.get_name();
15 
16     //我们可以构造另一个伪类来继承Mammal,这是通过定义它的constructor函数并替换它的prototype为一个Mammal的实例来实现的:
17 
18     var Cat = function(name){
19         this.name = name;
20         this.saying = 'OW';
21     };
22 
23     Cat.prototype = new Mammal();
24 
25     Cat.prototype.purr = function(n){
26         var i, s = '';
27         for(i = 0;i < n;i++){
28             if(s){
29                 s += '-';
30             }
31             s += 'r';
32         }
33         return s;
34     };
35 
36     Cat.prototype.get_name = function(){
37         return this.says() + ' ' + this.name + ' ' + this.says();
38     };
39 
40     var myCat = new Cat('XMM');
41     var says = myCat.says();    //"OW"
42     var myname = myCat.get_name(); //"OW XMM OW"
43     var pr = myCat.purr(5);    //"r-r-r-r-r"

这种方法没有私有属性,所有的属性都是公开的,无法访问父类的方法。更糟糕的是,使用构造器函数存在一个严重的危害,如果你在调用构造器函数时忘记了在前面加上new前缀,那么this将不会绑定到一个新对象上。而是绑定到全局对象上

 

原型 Prototype

让我们先用对象字面量去构造一个有用的对象

 1     var myMammal = {
 2         name: 'QQQ',
 3         get_name: function(){
 4             return this.name;
 5         },
 6         says: function(){
 7             return this.says || ' ';
 8         }
 9     };
10 
11     //定制新的实例
12     var myCat = Object.create(myMammal);
13     myCat.name = 'XMM';
14     myCat.says = 'OW';
15     myCat.pr = function(n){
16         var i, s = '';
17         for(i = 0;i < n;i++){
18             if(s){
19                 s += '-';
20             }
21             s += 'r';
22         }
23         return s;
24     };
25     myCat.get_name =  function(){
26         return this.says() + ' ' + this.name + ' ' + this.says();
27     };

这是一种“差异化继承”。通过定制一个新的对象,我们指明它与所基于的基本对象的区别。

 

函数化 Function

迄今为止,我们所看到的继承模式的一个弱点就是没办法保护隐私。对象的所有属性都是可见的。我们无法得到私有变量和私有函数。现在,我们有一个更好的选择,那就是应用模块模式
我们从构造一个生成对象的函数开始。我们以小写字母开头,因为它并不需要new前缀。该函数包含4个步骤

【1】创建一个新对象,有很多的方式去创建一个对象,他可以构造一个对象字面量,或者用构造函数,或者使用Object.create(),或者调用一个会返回一个对象的函数。
【2】有选择的定义私有变量和方法
【3】给这个对象扩充方法。这些方法拥有特权去访问参数
【4】返回那个新对象

这里是一个函数化构造器的伪代码模板:

 1     var constructor = function(spec,my){
 2         var that,其他私有变量;
 3         my = my || {};
 4 
 5         把共享的变量和函数添加到my中
 6 
 7         that = 一个新对象
 8 
 9         添加给that的特权方法
10 
11         return that;
12     };

让我们把这个模式应用到mammal例子里。此处不需要my,所以我们先抛开它,但会使用一个spec对象。

 1     var mammal = function (spec){
 2         var that = {};
 3 
 4         that.get_name: function(){
 5             return this.name;
 6         };
 7         that.says: function(){
 8             return this.says || ' ';
 9         };
10 
11         return that;
12     };
13 
14     var myMammal = mammal({name: 'Herb'});

 

posted @ 2016-10-16 20:27  老板丶鱼丸粗面  阅读(155)  评论(0编辑  收藏  举报