CoffeeScript 中的继承实现
Inheritance implementation in CoffeeScript
我正在学习 javascript 中的不同继承实现,主要是根据 Stoyan Stefanov 的 Javascript Patterns 书。
现在我正在检查 Coffescript 是如何实现它的。所以给定一个 parent 和一个 child 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
并存储了超类引用。 Stefanov 定义了什么 'Holy Grail'。
使用此模式,child 仅继承原型的属性。
// the proxy function
function ctor() {
this.constructor = child;
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
2。通过复制属性继承
使用这种模式,我们只需将一个 object 的属性复制到另一个
_hasProp = {}.hasOwnProperty;
for (var key in parent) {
if (_hasProp.call(parent, key)) child[key] = parent[key];
}
3。经典模式 - Rent-a-Constructor(或借用构造函数)
function Snake() {
return Snake.__super__.constructor.apply(this, arguments);
}
问题:
- 我的假设是否正确? coffescript 编译器使用 1+2+3 吗?
- 通过复制继承似乎使用了浅拷贝,这意味着它没有检查是否属性 是一个 object/array 并开始递归。即使结果看起来很完美深拷贝(objects/arrays是拷贝,不是参考)。 Why/how?
- rent-a-constructor不就是重复继承吗?复制属性然后再次调用 parent 构造函数?
-
_extends
函数也可以在 object 之间使用而不是构造函数吗?
谢谢
- Isn't the rent-a-constructor creating a repetition of the inheritance? Properties copied and then parent constructor called again?
正在将属性复制到此处...
for (var key in parent) {
if (_hasProp.call(parent, key)) child[key] = parent[key];
}
... 不是原型属性,它们是 "class level" 属性,在函数本身上定义的方法。它将属性从函数 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');
无论如何,复制属性然后 "the parent constructor being called again" 并不是真正会发生的事情。
属性未在父构造函数中定义,父构造函数只是需要 运行 的可执行代码块。它可能不定义任何属性,或者它可能定义一堆属性,但这些属性不会由原型或 _hasOwnProperty
循环设置。
我正在学习 javascript 中的不同继承实现,主要是根据 Stoyan Stefanov 的 Javascript Patterns 书。
现在我正在检查 Coffescript 是如何实现它的。所以给定一个 parent 和一个 child 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
并存储了超类引用。 Stefanov 定义了什么 'Holy Grail'。
使用此模式,child 仅继承原型的属性。
// the proxy function
function ctor() {
this.constructor = child;
}
ctor.prototype = parent.prototype;
child.prototype = new ctor();
child.__super__ = parent.prototype;
2。通过复制属性继承
使用这种模式,我们只需将一个 object 的属性复制到另一个
_hasProp = {}.hasOwnProperty;
for (var key in parent) {
if (_hasProp.call(parent, key)) child[key] = parent[key];
}
3。经典模式 - Rent-a-Constructor(或借用构造函数)
function Snake() {
return Snake.__super__.constructor.apply(this, arguments);
}
问题:
- 我的假设是否正确? coffescript 编译器使用 1+2+3 吗?
- 通过复制继承似乎使用了浅拷贝,这意味着它没有检查是否属性 是一个 object/array 并开始递归。即使结果看起来很完美深拷贝(objects/arrays是拷贝,不是参考)。 Why/how?
- rent-a-constructor不就是重复继承吗?复制属性然后再次调用 parent 构造函数?
-
_extends
函数也可以在 object 之间使用而不是构造函数吗?
谢谢
- Isn't the rent-a-constructor creating a repetition of the inheritance? Properties copied and then parent constructor called again?
正在将属性复制到此处...
for (var key in parent) {
if (_hasProp.call(parent, key)) child[key] = parent[key];
}
... 不是原型属性,它们是 "class level" 属性,在函数本身上定义的方法。它将属性从函数 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');
无论如何,复制属性然后 "the parent constructor being called again" 并不是真正会发生的事情。
属性未在父构造函数中定义,父构造函数只是需要 运行 的可执行代码块。它可能不定义任何属性,或者它可能定义一堆属性,但这些属性不会由原型或 _hasOwnProperty
循环设置。