2015-02-05 62 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