Javascript类和变量引用
我正试图解决这个思维混乱的Javascript OOP问题 因此,我有以下课程:Javascript类和变量引用,javascript,Javascript,我正试图解决这个思维混乱的Javascript OOP问题 因此,我有以下课程: var ClassA = function() { this.initialize(); } ClassA.prototype = { methods : ['alpha','beta','gama'], initialize : function() { for ( var i in this.methods ) { this[this.met
var ClassA = function() {
this.initialize();
}
ClassA.prototype = {
methods : ['alpha','beta','gama'],
initialize : function() {
for ( var i in this.methods ) {
this[this.methods[i]] = function() {
console.log(this.methods[i]);
}
}
}
}
var a = new ClassA();
当我调用每个方法时,我希望打印它的名称,对吗?但我得到的是:
a.alpha(); // returns gama ?!?
a.beta(); // returns gama ?!?
a.gama(); // returns gama
但是当我的班级看起来像这样的时候:
var ClassB = function() {
this.initialize();
}
ClassB.prototype = {
methods : ['alpha', 'beta', 'gama'],
initialize: function() {
for ( var i in this.methods ) {
this.addMethod(this.methods[i]);
}
},
addMethod: function(method) {
this[method] = function() {
console.log(method);
}
}
}
var b = new ClassB();
b.alpha(); // returns alpha
b.beta(); // returns beta
b.gama(); // returns gama
为什么会这样
for ( var i in this.methods ) {
this[this.methods[i]] = function() {
console.log(this.methods[i]);
}
}
你的问题就在这里。当此循环结束时,i
是最后一个元素。每个函数使用相同的i
,因此它们都是最后一个元素
当您使用addMethod
时,您正在进行闭包以“捕获”正确的值
编辑:当您调用addMethod
时,您是在“复制”该值,而不是使用i
值,该值随每次循环迭代而变化。在您的第一个版本中:
initialize : function() {
for ( var i in this.methods ) {
this[this.methods[i]] = function() {
console.log(this.methods[i]);
}
}
}
在initialize
中创建的方法都引用来自initialize
的同一i
变量,并且在initialize
运行后i
具有值“gama”
,因此无论调用哪种方法,它们都将登录到控制台。在创建方法时,JS不存储i
的当前值
JS为每个函数创建一个“闭包”-在初始化
函数(即i
)中声明的变量即使在初始化
完成后仍然在嵌套函数的范围内
第二个版本调用addMethod
来添加每个方法:
addMethod: function(method) {
this[method] = function() {
console.log(method);
}
}
…因此,当它们运行时,它们将引用自己的方法
参数的“副本”,因为每个方法都有一个单独的闭包
编辑:另请参见此问题:(这里有几个答案比我解释得更清楚)。您可以通过添加匿名闭包修复第一个示例:
initialize : function() {
for ( var i in this.methods ) {
(function (i) { // anonymous closure
this[this.methods[i]] = function() {
console.log(this.methods[i]);
}
}).call(this, i); // use .call() if you need "this" inside
}
}
现在,它将以与第二个示例相同的方式工作。“匿名”意味着闭包是由没有名称的函数完成的,并且在“创建”时立即被调用
侧面注意:使用.call(this,…)
将this
保存在被调用函数中,或者您可以执行var that=this
,使用that
而不是this
并正常调用函数:
for ( var i in this.methods ) {
var that = this;
(function (i) { // anonymous closure
that[that.methods[i]] = function() {
console.log(that.methods[i]);
}
})(i); // Called normally so use "that" instead of "this"!
}
首先,停止在数组上使用for(对象中的属性)循环。这一切都是有趣的游戏,直到有人原型阵列对象,这是一个非常合理和非常有用/流行的事情做。这将导致将自定义方法添加到for x in数组循环中
至于这个问题,它正在做你在版本1中告诉它要做的事情。问题是,当你准备发射它时,我是最后一个我是“伽马”的东西。当您将引用作为参数传递到函数中时,函数会在传递时保持值的状态。我几乎每天都回答这样的问题。。。我很困惑。。。console.log不是另一个函数吗?通过addMethod,我只是将它包装到另一个函数中?@drinchev:
console.log
在这里并不重要。这里重要的是,当您调用addMethod
时,您将值复制到每个函数中,但当您不使用它时,您使用的是相同的值。(如果我没有很好地解释的话,很抱歉。)第一个例子是闭包,因为它创建了一个引用其封闭范围中某个内容的新范围。第二个函数在函数调用期间复制值,因此它不是闭包@dtanders:但是addMethod
函数内部有一个闭包:-这不是通过JS中的数组进行循环的闭包吗?@RepWhoringPeeHaa-是的,应该使用普通的for循环,但这不是问题所在。@nnnnnn我知道这就是为什么它是注释而不是答案:-)他已经解决了问题,他首先想知道为什么这是一个问题。是的,但这种解决方法更直接、更简单。我同意,但它仍然不能回答最初的问题。