2015-02-05 102 views
0

我正在學習JavaScript中的不同繼承實現,主要遵循Stoyan Stefanov的Javascript Patterns書。繼承在CoffeeScript中的實現

現在我正在檢查Coffescript如何實現它。因此,給予父母和孩子classes或構造函數:

class Animal 
    constructor: (@name) -> 

    move: (meters) -> 
    alert @name + " moved #{meters}m." 

class Snake extends Animal 
    move: -> 
    alert "Slithering..." 
    super 5 

sam = new Snake "Sammy the Python" 
sam.move() 

被編譯成:

var Animal, Horse, Snake, sam, 
    _extends = function(child, parent) { 
     for (var key in parent) { 
      if (_hasProp.call(parent, key)) child[key] = parent[key]; 
     } 

     function ctor() { 
      this.constructor = child; 
     } 
     ctor.prototype = parent.prototype; 
     child.prototype = new ctor(); 
     child.__super__ = parent.prototype; 
     return child; 
    }, 
    _hasProp = {}.hasOwnProperty; 

Animal = (function() { 
    function Animal(_name) { 
     this.name = _name; 
    } 

    Animal.prototype.move = function(meters) { 
     return alert(this.name + (" moved " + meters + "m.")); 
    }; 

    return Animal; 

})(); 

Snake = (function(_super) { 
    _extends(Snake, _super); 

    function Snake() { 
     return Snake.__super__.constructor.apply(this, arguments); 
    } 

    Snake.prototype.move = function() { 
     alert("Slithering..."); 
     return Snake.__super__.move.call(this, 5); 
    }; 

    return Snake; 

})(Animal); 

sam = new Snake("Sammy the Python"); 
sam.move(); 

正如我理解不同圖案的組合coffescript結果繼承的實現:

1.古典代理構造

在這種情況下,我們我們也復位constructor pointer的d存儲超類參考。斯特凡諾夫如何定義'聖盃'。 有了這種模式,孩子只能繼承原型的屬性。

// the proxy function 
function ctor() { 
    this.constructor = child; 
} 
ctor.prototype = parent.prototype; 
child.prototype = new ctor(); 
child.__super__ = parent.prototype; 

2.通過複製屬性

利用這種圖案的繼承我們只是一個對象的屬性複製到另一個

_hasProp = {}.hasOwnProperty; 
for (var key in parent) { 
    if (_hasProp.call(parent, key)) child[key] = parent[key]; 
} 

3.古典模式 - 租賃構造(或借用構造函數)

function Snake() { 
    return Snake.__super__.constructor.apply(this, arguments); 
} 

問題:

  1. 我的假設是否正確? coffescript編譯器是使用1 + 2 + 3嗎?
  2. 通過複製繼承似乎使用淺拷貝,這意味着它不檢查屬性是一個對象/數組,並開始遞歸。即使艱難的結果似乎是一個完美的深拷貝(對象/數組是副本,而不是引用)。爲什麼/怎麼樣?
  3. 是不是rent-a-constructor創建一個繼承的重複?複製屬性,然後再調用父構造函數?
  4. _extends函數是否也可用於對象而不是構造函數?

由於

回答

2
  • 是不是租賃構造創建繼承的重複?複製屬性,然後再調用父構造函數?
  • 的屬性被複制在這裏......

    for (var key in parent) { 
         if (_hasProp.call(parent, key)) child[key] = parent[key]; 
        } 
    

    ...都沒有原型的屬性,它們是「一流水平」的屬性,在函數本身定義的方法。它將屬性從功能Animal複製到功能Horse

    的區別是:

    class Animal 
        # Not part of prototype, part of Animal, must be copied 
        @build: (name) -> 
        new @(name) 
    
        constructor: (name) -> 
        @name = "An animal named #{name}" 
    
        # Part of prototype 
        sayName: -> 
        alert(@name) 
    
    class Bird extends Animal 
        constructor: (name) -> 
        @name = "A bird named #{name}" 
    
    
    # Both Animal and Bird have build because of the copying of properties: 
    a = Animal.build('sam') # an animal named sam 
    b = Bird.build('bob') # a bird named bob 
    

    在編譯的JavaScript的一些註釋:

    var Animal, Bird, a, b, 
        __extends = function(child, parent) { 
         for (var key in parent) { 
          # Copies Animal.build to Bird.build 
          if (__hasProp.call(parent, key)) child[key] = parent[key]; 
         } 
    
         function ctor() { 
          this.constructor = child; 
         } 
         # Makes sayName available to Bird via prototypal inheritance 
         ctor.prototype = parent.prototype; 
         child.prototype = new ctor(); 
         child.__super__ = parent.prototype; 
         return child; 
        }, 
        __hasProp = {}.hasOwnProperty; 
    
    Animal = (function() { 
        Animal.build = function(name) { 
        return new this(name); 
        }; 
    
        function Animal(name) { 
        # This still (theoretically) needs to be invoked, regardless of whether 
        # the properties are copied over, though it isn't invoked in this example 
        this.name = "An animal named " + name; 
        } 
    
        Animal.prototype.sayName = function() { 
        return alert(this.name); 
        }; 
    
        return Animal; 
    
    })(); 
    
    Bird = (function(_super) { 
        __extends(Bird, _super); 
    
        # There is no "Bird.build" defined here, it is copied from Animal 
    
        function Bird(name) { 
        this.name = "A bird named " + name; 
        } 
    
        # There is no "move" defined here, it is provided by our prototyep 
        return Bird; 
    
    })(Animal); 
    
    a = Animal.build('sam'); 
    
    b = Bird.build('bob'); 
    

    無論如何,屬性被複制,然後「被再次調用父類的構造」是不是真的有什麼會發生。

    屬性沒有在父構造函數中定義,父構造函數只是需要運行的可執行的代碼塊。它可能沒有定義任何屬性,也可能定義了一堆屬性,但這些屬性不會由原型或循環設置。

    +0

    我明白了,謝謝。但函數是對象,因爲我知道對象被引用複製。所以如果我們在'b'創建後''build'從'Animal'改變了''''''''''''''''''版本''將會被修改? – Leonardo 2015-02-05 16:58:11

    +1

    不可以。「你不能」改變「Animal的功能'build'。你可以通過'Animal.build = function(){...}'分配一個新函數來替換它,但是這並不會修改仍然附着在Bird上的原始'build'。 – meagar 2015-02-05 16:59:00

    +0

    作爲一個通用對象的屬性呢?我們可以在動物中修改它,不是嗎?在那種情況下會發生什麼事兒 – Leonardo 2015-02-05 17:01:47