我们如何在 Node.JS 中使用“继承”?听说原型类似于java中的接口。但我不知道如何使用它!
3 回答
尽管在 javascript 中有多种执行继承和 OO 的方法,但在 Node.js 中,您通常会使用内置的util.inherits函数来创建从另一个继承的构造函数。
请参阅http://book.mixu.net/ch6.html以获得有关此主题的良好讨论。
例如:
var util = require("util");
var events = require("events");
function MyOwnClass() {
// ... your code.
}
util.inherits(MyOwnClass, events.EventEmitter);
在纯 JS 中创建对象构造函数:
它们只是与任何其他 JS 函数一样的函数,但使用 new 关键字调用。
function Constructor(){ //constructors are typically capitalized
this.public = function(){ alert(private); }
var private = "Untouchable outside of this func scope.";
}
Constructor.static = function(){ alert('Callable as "Constructor.static()"'); }
var instance = new Constructor();
遗产:
function SubConstructor(){
this.anotherMethod(){ alert('nothing special'); }
}
function SubConstructor.prototype = new Constructor();
var instance = new SubConstructor();
instance.public(); //alerts that private string
关键区别在于原型继承来自对象,而不是构建它们的事物。
一个缺点是没有很好的方法来编写可以继承私有实例变量的东西。
然而,巨大的巨大优势是我们可以在不影响超级构造函数的情况下弄乱原型,即使在它们已经构建之后也可以更改每个对象的方法或属性。这在实践中很少在更高级别的代码中完成,因为它会产生一个非常混乱的 API,但它对于底层类型的东西可能很方便,您可能希望在一组实例之间共享一个不断变化的值,而不仅仅是制作它是全球性的。
我们得到这种后实例化行为的原因是因为 JS 继承实际上是在一个查找过程中运行的,在这个过程中,任何方法调用都会沿着实例链及其构造函数原型属性运行,直到找到调用或退出的方法。如果您对级联继承绝对疯狂(无论如何这被广泛认为是一种反模式),这实际上会变慢。
实际上,我自己并没有专门为继承痤疮打原型,而是更喜欢通过更复合的方法来构建对象,但是当你需要它时它非常方便,并且提供了很多不太明显的实用程序。例如,当您有一个对您有用的对象时,如果只有一个属性不同,但您不想触摸原始对象。
var originInstance = {
originValue:'only on origin',
theOneProperty:'that would make this old object useful if it were different'
}
function Pseudoclone(){
this.theOneProperty = "which is now this value";
}
Pseudoclone.prototype = originInstance;
var newInstance = new Psuedoclone();
//accesses originInstance.originValue but its own theOneProperty
有更现代的便捷方法,如 Object.create,但只有函数构造函数为您提供封装私有/实例变量的选项,所以我倾向于支持它们,因为 10 次中有 9 次不需要封装的任何东西都只是对象文字。
覆盖和调用对象顺序:
( function Constructor(){
var private = "public referencing private";
this.myMethod = function(){ alert(private); }
} ).prototype = { myMethod:function(){ alert('prototype'); };
var instance = new Constructor();
instance.myMethod = function(){ alert(private); }
instance.myMethod();//"undefined"
注意:构造函数周围的括号允许在一个位置定义和评估它,因此我可以将它视为同一行上的对象。
myMethod 警告“未定义”,因为外部覆盖的方法是在构造函数的闭包之外定义的,这有效地使内部变量类似于私有。因此,您可以替换该方法,但您将无法访问它所做的事情。
现在让我们做一些评论。
( function Constructor(){
var private = "public referencing private";
this.myMethod = function(){ alert(private); }
} ).prototype = { myMethod:function(){ alert('prototype'); };
var instance = new Constructor();
//instance.myMethod = function(){ alert(private); }
instance.myMethod();//"public referencing private"
和...
( function Constructor(){
var private = "public referencing private";
//this.myMethod = function(){ alert(private); }
} ).prototype = { myMethod:function(){ alert('prototype'); };
var instance = new Constructor();
//instance.myMethod = function(){ alert(private); }
instance.myMethod();//"prototype"
请注意,出于同样的原因,原型方法也无权访问该内部私有 var。这完全取决于构造函数本身是否定义了某些东西。请注意,传递给构造函数的参数也将有效地成为私有实例变量,它可以方便地执行诸如覆盖一组默认选项之类的操作。
夫妇更多细节
除非您有必需的参数,否则在使用 new 调用时实际上没有必要使用括号,但我倾向于让它们养成习惯(它可以将它们视为触发的函数,然后留下一个表示触发范围的对象)并认为它对 Java 开发人员来说不会那么陌生new Constructor;
此外,对于任何需要参数的构造函数,我喜欢在内部添加默认值,例如:
var param = param || '';
这样,您可以将构造函数传递给 Node 的 util.inherit 等便利方法,而不会为您破坏未定义的值。
参数也是有效的私有持久实例变量,就像在构造函数中定义的任何变量一样。
哦,对象文字(用 定义的对象{ key:'value' }
)可能最好被认为大致相当于:
var instance = new Object();
instance.key = 'value';
在 Coffeescript 的帮助下,我们可以更轻松地实现它。
例如:扩展一个类:
class Animal
constructor: (@name) ->
alive: ->
false
class Parrot extends Animal
constructor: ->
super("Parrot")
dead: ->
not @alive()
静态属性:
class Animal
@find: (name) ->
Animal.find("Parrot")
实例属性:
class Animal
price: 5
sell: (customer) ->
animal = new Animal
animal.sell(new Customer)
我只是在 CoffeeScript 中获取示例代码类。您可以在其官方网站了解更多关于 CoffeeScript 的信息:http: //coffeescript.org/