Javascript factory pattern variable scoping
我正在按照教程显示工厂模式以在javascript中创建对象。 下面的代码让我难以理解它的工作原理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 6-2.htm </head> <body> <script type="text/javascript"> function createAddress(street, city, state, zip) { var obj = new Object(); obj.street = street; obj.city = city; obj.state = state; obj.zip = zip; obj.showLabel = function() { //alert(this.street +" " + this.city +"," + this.state +"" + this.zip); //var obj; alert(obj.street +" " + obj.city +"," + obj.state +"" + obj.zip); }; return obj; }; var JohnAddr = createAddress("12 A St.","Johnson City","TN", 37614); var JoeAddr = createAddress("10061 Bristol Park","Pensacola","FL", 32503); JohnAddr.showLabel(); JoeAddr.showLabel(); </body> </html> |
第一个注释行似乎对我来说(在showLabel函数中使用
欢迎来到封闭世界。你是正确的感觉到你的行为,就像它是一个全球但不是全球的。这就是闭包的行为方式。
基本上在javascript中,当函数返回时,并非所有局部变量都必须像Java或C那样被垃圾收集/释放。如果存在对该变量的引用,则该变量在定义它的函数范围内存活。
从技术上讲,机制是不同的,有些人试图以这种方式解释它,并最终混淆了许多其他人。对我来说,闭包是一种"私有"全局变量,就像全局变量一样,它们在函数中共享,但它们并未在全局范围内声明。就像你在遇到这个功能时所描述的那样。
这里有一些关于与javascript闭包相关的stackoverflow的其他答案,我认为值得一读:
JavaScript的隐藏功能?
请解释在循环中使用JavaScript闭包
或者你可以谷歌短语"javascript closure"来探索这个主题。
补充答案。
至于为什么
Javascript有后期绑定。很晚,非常晚。
一些时髦的javascript后期绑定动作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | function foo () { alert(this.bar); } var bar ="hello"; var obj = { foo : foo, bar :"hi" }; var second_obj = { bar :"bye" }; foo(); // says hello, 'this' refers to the global object and this.bar // refers to the global variable bar. obj.foo(); // says hi, 'this' refers to the first thing before the last dot // ie, the object foo belongs to // now this is where it gets weird, an object can borrow/steal methods of // another object and have its 'this' re-bound to it obj.foo.call(second_obj); // says bye because call and apply allows 'this' // to be re-bound to a foreign object. In this case // this refers to second_obj |
在你的代码中,
一般而言,原型对象创建优先于此工厂模式。
现在来看看这个原型示例:
1 2 3 4 5 6 7 8 9 10 11 | var Address = function(street, city, state, zip){ this.street = street; this.city = city; this.state = state; this.zip= zip; }; Address.prototype.showLabel = function(){ alert(this.street +" " + this.city +"," + this.state +"" + this.zip); } |
现在,当我使用新关键字创建新地址时:
1 2 3 | // create new address var address = new Address('1', '2', '3', '4'); address.showLabel(); // alert |
代码的行为与您期望的完全一样。但是如果我不在构造函数中使用new关键字
1 2 3 | // create new address var address = Address('1', '2', '3', '4'); // address == undefined window.showLabel(); // address was added to window |
我希望这可以解决一些问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | function Address(street, city, state, zip) { this.street = street; this.city = city; this.state = state; this.zip = zip; this.showLabel = function() { //alert(this.street +" " + this.city +"," + this.state +"" + this.zip); //var obj; alert(this.street +" " + this.city +"," + this.state +"" + this.zip); }; }; var JohnAddr = new Address(...); JohnAddr.showLabel(); |
这是js古怪的一部分,showLabel是一个闭包并且可以访问obj,因为它在创建时在范围内 - 每次调用createAddress时都会创建一个新的闭包。
要按照您期望的方式使用"this",您需要使用new运算符,这样:
var foo = new createAddress(...
并将成员变量分配给'this'。
在没有使用new的情况下,"this"是全局对象。