Javascript 工厂模式变量作用域

发布于 2024-10-07 04:51:55 字数 1198 浏览 8 评论 0原文

我正在遵循一个教程,该教程展示了在 javascript 中创建对象的工厂模式。下面的代码让我很困惑为什么它会起作用。

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>6-2.htm</title>
</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 + "\n" + this.city + ", " + this.state + " " + this.zip);
    //var obj;
    alert(obj.street + "\n" + 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();
</script>
</body>
</html>

第一个注释行对我来说似乎是正确的(在 showLabel 函数中使用 this 关键字)。我不确定在其位置使用 obj 是如何工作的。 obj 必须在某处引用全局变量,因为在该函数运行时没有定义 obj,对吗?由于我制作了 2 个对象,在这种情况下,这两个对象都显示得很好,这不仅仅是运气,obj 内容的旧值也被正确存储和引用。但如何呢?如果我取消第二条评论的注释,那么它就会中断,我明白为什么,现在我明确告诉 js 我正在谈论一个局部变量,但没有。

I am following a tutorial that is showing the factory pattern to create objects in javascript. The following code has me stumped as to why it works.

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>6-2.htm</title>
</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 + "\n" + this.city + ", " + this.state + " " + this.zip);
    //var obj;
    alert(obj.street + "\n" + 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();
</script>
</body>
</html>

the first commented line seems proper to me (using the this keyword in the showLabel function). i'm not sure how using obj in its place is working. obj would have to reference a global variable somewhere because within that function when its run there is no obj defined, right? since i make 2 objects, its not just luck in this case that both get displayed fine, the older values for obj's contents are stored and referenced properly. but how? if i uncomment the second comment then it breaks and i understand why, now im explicitly telling js that i'm talking about a local variable and there is none.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

甜是你 2024-10-14 04:51:55

欢迎来到闭包的世界。你的感觉是正确的,你的行为方式就好像它是一个全球性的,但又不完全是全球性的。这就是闭包的行为方式。

基本上在 javascript 中,当函数返回时,并非所有局部变量都必须像 Java 或 C 中那样被垃圾收集/释放。如果存在对该变量的引用,则该变量将在定义它的函数范围内生存。

从技术上讲,机制是不同的,有些人试图以这种方式解释它,但最终却让很多其他人感到困惑。对我来说,闭包是一种“私有”全局变量,就像全局变量一样,它们在函数之间共享,但它们不在全局范围内声明。就像你描述的遇到这个功能时的感受一样。

以下是我在 stackoverflow 上与 javascript 闭包相关的一些其他答案,我认为值得一读:

JavaScript 的隐藏功能?

请解释 JavaScript 闭包在循环中的使用

或者您可以通过谷歌搜索“javascript 闭包”来探索该主题。


补充答案。

至于为什么 this 在您的代码中起作用的解释(而不是 *咳嗽* 尝试更正您的代码,以便 this 即使在未更正的版本中也能起作用*咳嗽* ;-):

Javascript 具有后期绑定。很晚了,非常非常晚了。 this 不仅在编译时不绑定,甚至在运行时也不绑定。它在执行时被绑定 - 也就是说,在调用函数之前,您无法知道 this 真正指向什么。调用者基本上决定 this 的值是什么,而不是使用 this 的函数。

一些时髦的 javascript 后期绑定操作:

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

在您的代码中,this 方便地将调用该函数的对象作为其方法,这就是为什么它可以工作,即使您显然使用所谓的正确构造函数语法。

Welcome to the world of closures. You are right to sense what you feel to behave as if it's a global but not quite global. That's how closures behave.

Basically in javascript when a function returns not all local variables are necessarily garbage collected/freed like in Java or C. If there is a reference to that variable then that variable survives in the scope of the function where it is defined.

Technically the mechanics are different and some people try to explain it that way and end up confusing a lot of other people. To me, closures are a sort of 'private' global variables in that like globals, they are shared accross functions but they are not declared in the global scope. It's just like what you describe feeling upon encountering this feature.

Here are some of my other answers here on stackoverflow related to javascript closures which I believe are worth reading:

Hidden Features of JavaScript?

Please explain the use of JavaScript closures in loops

Or you can just google the phrase "javascript closure" to explore the subject.


Additional answer.

As for the explanation of why this works in your code (as opposed to *cough* attempting to correct your code so that this would work even though it works in the uncorrected version *cough* ;-):

Javascript has late bindings. Very late, very-very late. Not only is this not bound during compile time, it is not even bound during run time. It is bound at execution time - that is, until a function is called you can't know what this really points to. The caller basically gets to decide what the value of this is, not the function where this is used.

Some funky javascript late binding maneuvers:

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

In your code, this conveniently refers to the object invoking the function as its method which is why it works even though you are apparently not using supposedly correct constructor syntax.

破晓 2024-10-14 04:51:55

objshowLabel 函数内部工作的原因是因为 obj 是一个局部变量。每次调用 create address 时都会声明该函数。在 JavaScript 中,我们称之为闭包。

一般来说,原型对象创建优于工厂模式。

现在看一下这个原型示例:

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 + "\n" + this.city + ", " + this.state + " " + this.zip);
}

现在,当我使用 new 关键字创建新地址时:

// create new address
var address = new Address('1', '2', '3', '4');
address.showLabel(); // alert

代码的行为将与您期望的完全一样。但是,如果我在构造函数中不使用 new 关键字 this 实际上是 window 对象。

// create new address
var address = Address('1', '2', '3', '4'); // address == undefined
window.showLabel(); // address was added to window

我希望这能让事情澄清一点。

The reason obj works inside the showLabel function is because obj is a local variable. The function is declared every time create address is called. In JavaScript we call this a closure.

Generally speaking the prototype object creation is preferred over this factory pattern.

Now have a look at this prototype example:

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 + "\n" + this.city + ", " + this.state + " " + this.zip);
}

Now when I create a new address with new keyword:

// create new address
var address = new Address('1', '2', '3', '4');
address.showLabel(); // alert

The code will behave exactly like you expect. However if I do not use the new keyword this inside the constructor is actually the window object.

// create new address
var address = Address('1', '2', '3', '4'); // address == undefined
window.showLabel(); // address was added to window

I hope this clears things up a little bit.

弄潮 2024-10-14 04:51:55
function Address(street, city, state, zip) {

  this.street = street;
  this.city = city;
  this.state = state;
  this.zip = zip;
  this.showLabel = function() {
    //alert(this.street + "\n" + this.city + ", " + this.state + " " + this.zip);
    //var obj;
    alert(this.street + "\n" + this.city + ", " + this.state + " " + this.zip);
  };
};

var JohnAddr = new Address(...);
JohnAddr.showLabel();
function Address(street, city, state, zip) {

  this.street = street;
  this.city = city;
  this.state = state;
  this.zip = zip;
  this.showLabel = function() {
    //alert(this.street + "\n" + this.city + ", " + this.state + " " + this.zip);
    //var obj;
    alert(this.street + "\n" + this.city + ", " + this.state + " " + this.zip);
  };
};

var JohnAddr = new Address(...);
JohnAddr.showLabel();
人│生佛魔见 2024-10-14 04:51:55

这是 js 怪异之处的一部分,showLabel 是一个闭包,并且可以访问 obj,因为它在创建时就在范围内 - 每次调用 createAddress 时都会创建一个新的闭包。

要以您期望的方式使用“this”,您需要使用 new 运算符,如下所示:

var foo = new createAddress(...

并将成员变量分配给“this”。

在本例中,new 是“ t 使用的“this”是全局对象。

This is part of the weirdness of js, showLabel is a closure and has access to obj because it was in scope when created - a new closure is created each time createAddress is called.

To use 'this' in the way you're expecting you'd need to use the new operator so:

var foo = new createAddress(...

And be assigning the member variables to 'this'.

In this case where new isn't used 'this' is the global object.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文