返回对象的函数是创建类似对象的好方法。
例1
以下代码显示了如何使用此模式创建对象。
function Message() {//from www.ancii.com var message = "hello"; function setMessage(newMessage) { if (!newMessage) throw new Error("cannot set empty message"); message = newMessage; } function getMessage() { return message; } function printMessage() { console.log(message); } return { setMessage: setMessage, getMessage: getMessage, printMessage: printMessage }; } // Pattern in use var hi1 = Message(); hi1.printMessage(); // hello var hi2 = Message(); hi2.setMessage("hi"); hi2.printMessage(); // hi hi1.printMessage(); // hello
了解这一点
Javascript的 this
对象的行为不同取决于我们如何称呼它。this
对象指的是调用上下文。调用上下文是用于调用函数的前缀。
var myData = { myValue: 123, myFunction: function () { console.log("inside this.myValue is:", this.myValue); } } console.log("myData.myValue is: ", myData.myValue); // myData.myValue is: 123 myData.myFunction(); // inside this.myValue is: 123
默认调用上下文是Node.js全局变量。
function myData() { console.log("is this called from globals? : ", this === global); // true } myData();
我们可以附加一个函数到任何对象并改变调用上下文。
var myData = { myValue: 123 /*www.w3cschool.cn*/}; function myFunction() { if (this === global) console.log("called from global"); if (this === myData) console.log("called from myData"); } // global context myFunction(); // called from global // from myData myData.myFunction = myFunction; myData.myFunction(); // called from myData
如果你使用JavaScript运算符new
调用函数,它创建一个新的JavaScript对象,并且这个在函数内引用这个新创建的对象。
function myData() {//www.w3cschool.cn this.myData = 123; console.log("Is this global?: ", this == global); } // without the new operator myData(); // Is this global?: true console.log(global.myData); // 123 // with the new operator var newFoo = new myData(); // Is this global?: false console.log(newFoo.myData); // 123
在上面的代码中,我们在函数中修改了this.myData,并将newFoo.myData设置为该值。
理解原型
JavaScript中的每个对象都有一个指向另一个对象的内部链接,称为原型。当读取对象上的属性时,myData.myValue从myData读取属性myValue,JavaScript检查myData上是否存在此属性。如果没有,JavaScript检查属性是否存在于myData.__ proto__以及__proto__本身。如果在任何级别找到一个值,则返回它。否则,JavaScript返回undefined。
var shape = {}; shape.__proto__.myValue= 123; console.log(shape.myValue); // 123
JavaScript中的“__”前缀不应该由用户代码使用。在函数上使用new运算符创建对象时,__proto__设置为函数的“.prototype”成员。
function shape() { }; shape.prototype.myValue = 123; var bas = new shape(); console.log(bas.__proto__ === shape.prototype); // true console.log(bas.myValue); // 123
注意1
从相同的函数创建的原型在所有对象之间共享。
function shape() { }; //www.w3cschool.cnshape.prototype.myValue = 123; var bas = new shape(); var myItem = new shape(); console.log(bas.myValue); // 123 console.log(myItem.myValue); // 123 shape.prototype.myValue = 456; console.log(bas.myValue); // 456 console.log(myItem.myValue); // 456
上面的代码生成以下结果。
假设我们有1000个实例创建了某个对象,而原型的所有属性和函数都是共享的。因此原型节省了内存。
注意2
原型属性由对象上的属性隐藏。
function shape() { }; //from www.ancii.comshape.prototype.myValue = 123; var bas = new shape(); var myItem = new shape(); bas.myValue = 456; console.log(bas.myValue); console.log(myItem.myValue); // 123
this
对象是一个完美的读取/写入属性(数据)的候选,你应该将其用于所有属性(数据)。但函数一般不会在创建后改变。所以函数是放在 .prototype
上的很好的选择。函数性(函数/方法)在所有实例之间共享,而属性属于单个对象。
例2
以下代码显示了在JavaScript中编写类的模式。
function someClass() { /*from www.ancii.com*/ // Properties go here this.someProperty = "some initial value"; } // Member functions go here: someClass.prototype.someMemberFunction = function () { this.someProperty = "modified value"; console.log("called from prototype"); } // Creation var instance = new someClass(); // Usage console.log(instance.someProperty); // some initial value instance.someMemberFunction(); console.log(instance.someProperty); // modified value
上面的代码生成以下结果。
在成员函数中,我们可以使用this访问当前实例,即使在所有实例之间共享相同的函数体。核心Node.js中的大多数类都是使用此模式编写的。