Node.js设计定制类型

  Node的模块系统能帮助你实现跨应用的共享对象,Node的单例模式对于是一种自然的实现,但是如果你需要某些东西不被分享,比如你创建多个对象,每个都有自己唯一的属性,但是它们共享共同的行为,在大多数语言中这需要一个类来实现,而在Javascript中,只需要一点点不同而已。

  Javacript并没有真正类的概念,但是它有类型,这两个概念大部分时候被使用同样目标,其实大部分开发者认为下面定义一个类,即使User并不是一个真正的对象类型。

function User(n) {
    this.name = n;
}
var bob = new User('Bob');

  这种模式激活了Javascript中许多优雅的东西,User只是一个函数,bob还是一个对象,因为JS的对象如此强大,你能使用它们创建定制类型,这些类型拥有唯一的方法属性,好像类似传统类的定义一样。

User.prototype.sayHi = function() { 
       console.log('Hi, I'm ' + this.name); 
}; 
bob.sayHi(); // "Hi, I'm Bob" 

  通常情况下,将这些代码看成是类的实例是安全的,记住,它们还是只是对象,但能够prototype描述行为时,构造器简化了类型定义。

  回到原始问题,我们如何导出一个定制类型,完全不同于单例的范式,能维持代码更加干净。当我们阅读一个新的模块时,首先我们需要做的是发现什么被导出了,在大型文件中,这并不总是很明显被一下子发现的,这样我们就需要自己让其明确化,为了实现,在你i的Public端顶端捆绑module.exports到构造器。

//Private 
var privateVariable = true; 
//Public 
var User = module.exports = function User(n) { 
    this.name = n; 
} 

User.prototype.foobar = // ... 

  这段代码很容易将私有和公有分离了,还有一个单点源被输出,并且给类型取了一个好名称。现在我们能在应用中导出使用这个构造器,易于创建一个新用户:

var User = require('User'); 
var bob = new User('Bob'); 

  所有对象属性都是公开可访问,把它们加入一个新的实例是容易的,比如调用bob.name将返回'Bob',私有变量则没有这么简单,考虑下面案例,我们为我们的单例创建一个私有变量。

var paid = true; 
User.prototype.togglePaid = function togglePaid() { 
       paid = !paid; 
} 

  确实paid变量现在是私有的,你可以检查bob.paid会得到一个undefined,但是paid再也不是对每个User是唯一的了,任何User每次togglePaid()被调用时,它会为所有用户切换paid的值,require()缓存每个模块,这样那些变量中只有一个存在我们的应用中,这样所有User都引用它。

  我们需要一个私有变量作为实例的属性,但是所有属性都是公开的,我们可以延缓语义分离,我们使用下面取名约束来区别公有和私有:

function User(n) { 
    this.name = n;     // public 
    this._paid = true; // private 
} 
User.prototype.togglePaid = function() { 
       this._paid = !this._paid; 
} 

  上面代码的下划线告诉开发者这个变量是私有的,意味着对象外部不能直接使用,但是其实你每次都可以改变它们,所以并不是真正的私有,取名约束能够帮助你区分这两个,这是Node的最佳实践。

  真正的私有属性反而是反模式,其实有一个能实现真正私有变量的方法,为了定义变量和函数是真正每个实例的私有,你需要在你的构造器私有作用域中定义整个模块。

function User(n) {

    var paid = true; // private (to each User instance)

    this.name = n;     // public

  this.togglePaid = function togglePaid() {
      paid = !paid;
   }

}

  现在paid是每个实例独立的私有变量,每次调用togglPaid()方法时,能正确引用,但是它从来没有放入User对象中,它只是在构造器函数中保持私有。

  这样做其实没有什么错,但是它慢,构造器是每次新User构建时都会运行,那么togglePaid()函数需要会每个实例user创建一次,如果我们使用修改的prototype,如之前的代码,那么tooglepaid()函数只当模块被加载时一次定义。

 

Node.js单例设计

Node.js的require()的工作原理

Node.js教程系列

Node.js编程之道