Node.js 类的创建

返回对象的函数是创建类似对象的好方法。

例1

以下代码显示了如何使用此模式创建对象。

  1. function Message() {
  2. var message = "hello";
  3. function setMessage(newMessage) {
  4. if (!newMessage)
  5. throw new Error("cannot set empty message");
  6. message = newMessage;
  7. }
  8. function getMessage() {
  9. return message;
  10. }
  11. function printMessage() {
  12. console.log(message);
  13. }
  14. return {
  15. setMessage: setMessage,
  16. getMessage: getMessage,
  17. printMessage: printMessage
  18. };
  19. }
  20. // Pattern in use
  21. var hi1 = Message();
  22. hi1.printMessage(); // hello
  23. var hi2 = Message();
  24. hi2.setMessage("hi");
  25. hi2.printMessage(); // hi
  26. hi1.printMessage(); // hello

了解这一点

Javascript的 this对象的行为不同取决于我们如何称呼它。this 对象指的是调用上下文。调用上下文是用于调用函数的前缀。

  1. var myData = {
  2. myValue: 123,
  3. myFunction: function () {
  4. console.log("inside this.myValue is:", this.myValue);
  5. }
  6. }
  7. console.log("myData.myValue is: ", myData.myValue); // myData.myValue is: 123
  8. myData.myFunction(); // inside this.myValue is: 123

默认调用上下文是Node.js全局变量。

  1. function myData() {
  2. console.log("is this called from globals? : ", this === global); // true
  3. }
  4. myData();

我们可以附加一个函数到任何对象并改变调用上下文。

  1. var myData = {
  2. myValue: 123
  3. };
  4. function myFunction() {
  5. if (this === global)
  6. console.log("called from global");
  7. if (this === myData)
  8. console.log("called from myData");
  9. }
  10. // global context
  11. myFunction(); // called from global
  12. // from myData
  13. myData.myFunction = myFunction;
  14. myData.myFunction(); // called from myData

如果你使用JavaScript运算符new 调用函数,它创建一个新的JavaScript对象,并且这个在函数内引用这个新创建的对象。

  1. function myData() {
  2. this.myData = 123;
  3. console.log("Is this global?: ", this == global);
  4. }
  5. // without the new operator
  6. myData(); // Is this global?: true
  7. console.log(global.myData); // 123
  8. // with the new operator
  9. var newFoo = new myData(); // Is this global?: false
  10. console.log(newFoo.myData); // 123

在上面的代码中,我们在函数中修改了this.myData,并将newFoo.myData设置为该值。

理解原型

JavaScript中的每个对象都有一个指向另一个对象的内部链接,称为原型。当读取对象上的属性时,myData.myValue从myData读取属性myValue,JavaScript检查myData上是否存在此属性。如果没有,JavaScript检查属性是否存在于myData. proto以及proto本身。如果在任何级别找到一个值,则返回它。否则,JavaScript返回undefined。

  1. var shape = {};
  2. shape.__proto__.myValue= 123;
  3. console.log(shape.myValue); // 123

JavaScript中的“”前缀不应该由用户代码使用。在函数上使用new运算符创建对象时,proto__设置为函数的“.prototype”成员。

  1. function shape() { };
  2. shape.prototype.myValue = 123;
  3. var bas = new shape();
  4. console.log(bas.__proto__ === shape.prototype); // true
  5. console.log(bas.myValue); // 123

注意1

从相同的函数创建的原型在所有对象之间共享。

  1. function shape() { };
  2. shape.prototype.myValue = 123;
  3. var bas = new shape();
  4. var myItem = new shape();
  5. console.log(bas.myValue); // 123
  6. console.log(myItem.myValue); // 123
  7. shape.prototype.myValue = 456;
  8. console.log(bas.myValue); // 456
  9. console.log(myItem.myValue); // 456

上面的代码生成以下结果。

原型共享结果

假设我们有1000个实例创建了某个对象,而原型的所有属性和函数都是共享的。因此原型节省了内存。

注意2

原型属性由对象上的属性隐藏。

  1. function shape() { };
  2. shape.prototype.myValue = 123;
  3. var bas = new shape();
  4. var myItem = new shape();
  5. bas.myValue = 456;
  6. console.log(bas.myValue);
  7. console.log(myItem.myValue); // 123

this对象是一个完美的读取/写入属性(数据)的候选,你应该将其用于所有属性(数据)。但函数一般不会在创建后改变。所以函数是放在 .prototype 上的很好的选择。函数性(函数/方法)在所有实例之间共享,而属性属于单个对象。

例2

以下代码显示了在JavaScript中编写类的模式。

  1. function someClass() {
  2. // Properties go here
  3. this.someProperty = "some initial value";
  4. }
  5. // Member functions go here:
  6. someClass.prototype.someMemberFunction = function () {
  7. this.someProperty = "modified value";
  8. console.log("called from prototype");
  9. }
  10. // Creation
  11. var instance = new someClass();
  12. // Usage
  13. console.log(instance.someProperty); // some initial value
  14. instance.someMemberFunction();
  15. console.log(instance.someProperty); // modified value

上面的代码生成以下结果。

Node.js 类的创建 - 图2

在成员函数中,我们可以使用this访问当前实例,即使在所有实例之间共享相同的函数体。核心Node.js中的大多数类都是使用此模式编写的。