Javascript';这';值变化,但可以';我不明白为什么
我完全是一个Javascript新手,我正试着把我的头绕到奥尔恩身上。我遇到的是,当从同一对象上的另一个方法调用对象方法时,被调用方法中“this”的局部值的值正在改变。这是我的密码:Javascript';这';值变化,但可以';我不明白为什么,javascript,Javascript,我完全是一个Javascript新手,我正试着把我的头绕到奥尔恩身上。我遇到的是,当从同一对象上的另一个方法调用对象方法时,被调用方法中“this”的局部值的值正在改变。这是我的密码: var generator = { generateForLevelSkillAndCount : function(level, skill, count) { var functionCall = this['generate_' + level + '_' + skill];
var generator = {
generateForLevelSkillAndCount : function(level, skill, count) {
var functionCall = this['generate_' + level + '_' + skill];
return functionCall(count);
},
generate_0_4 : function(count) {
return this.generate_generic_dots(count, 3);
},
generate_generic_dots : function(count, maxDots) {
/* do cool stuff and return it */
}
};
因此,我调用generator.generateForLevelSkillAndCount(0,4,20)
,它可以正常工作,调用generate\u 0\u 4(count)
。然而,这就是它失败的地方,Chrome的Javascript控制台告诉我“UncaughtTypeError:Object[Object DOMWindow]没有“generate\u generic\u dots”方法。”
我知道问题在于generate_0_4
中的this
的值是一个DOMSWindow对象,而不是生成器(这就是this
在generateForSkillLevelAndCount
中所指的),但我不明白为什么会发生这种情况
更新:我根据CMS的建议更新了示例代码,以消除
eval
,但返回了相同的错误,因此这不仅仅是eval
错误。首先,我鼓励您在不需要eval的地方避免eval,例如,在First函数中:
//...
generateForLevelSkillAndCount : function(level, skill, count) {
var functionCall = this['generate_' + level + '_' + skill];
return functionCall(count);
},
//...
function bind(func, obj) {
return function() {
func.apply(obj, arguments);
}
}
您可以使用括号表示法属性访问器来代替eval
,在这种情况下不需要它
现在,我猜您正在Chrome的控制台上尝试您的代码,eval
失败,因为控制台有一个bug,当从FunctionExpression调用eval
(例如generateForLevelSkillAndCount
)时,被评估的代码使用其变量环境和词汇环境的全局上下文
有关此错误的更多信息,请参阅
编辑:重新读取代码后,出现问题的原因是将函数分配给functionCall
变量时丢失了基本对象引用,您可以:
直接调用函数,而不使用该变量:
//...
generateForLevelSkillAndCount : function(level, skill, count) {
this['generate_' + level + '_' + skill](count);
},
//...
或者仍然使用变量,但:
更多信息我和你一样困惑不解,但是你是否考虑过如果你显式地调用
生成\u 0\u 4
而不是通过eval()
解析它会发生什么情况?当你动态地调用生成\u 0\u 4
时(使用隐式来生成字符串()
)它作为一个特殊函数返回到generateForLevelSkillAndCount
。因为它位于窗口的范围而不是对象的范围内,所以它不能引用这个,内部调用失败,因为这个在该上下文中不存在
下面是如何查看正在发生的事情:
generate_0_4 : function(count) {
throw(this);
return this.generate_generic_dots(count, 3);
},
使用generator.generateForLevelSkillAndCount(0,4,1);
您将获得[object Window]
或[object DOMWindow]
使用generator.generate_0_4(1);
您可以得到您所期望的(以及有效的):[object object]
或
您可以使用以下命令控制方法调用的执行上下文:
在JavaScript中,上下文对象(此
)设置为“全局对象”(窗口,在浏览器中),除非该方法作为对象属性访问。因此:
var foo = { bar: function() { alert(this.baz); }, baz: 5 };
var bar = foo.bar;
var baz = 3;
foo.bar(); // alerts 5, from foo
foo["bar"](); // alerts 5, from foo
bar(); // alerts 3, from the global object
请注意,所有三个函数调用都指向完全相同的函数
因此,在您的代码中,您将所需的方法分配给functionCall
并直接调用它,这会导致函数使用window
作为其上下文对象。有两种方法可以解决此问题:将方法作为对象属性访问或使用或:
这是Javascript的一个特性:This
的值取决于调用函数的对象,而不是函数的定义位置。(当函数本身是一级对象时,这是有意义的。)在大多数其他上下文中,This
指的是窗口对象
使用包装器函数有两种常见的解决方法:
//...
generateForLevelSkillAndCount : function(level, skill, count) {
var functionCall = this['generate_' + level + '_' + skill];
return functionCall(count);
},
//...
function bind(func, obj) {
return function() {
func.apply(obj, arguments);
}
}
或使用闭包:
var self = this;
function generate_blah() {
// use self instead of this here
}
但是,在您的情况下,只需更换
var functionCall = this['generate_' + level + '_' + skill];
return functionCall(count);
与
这就可以了。谢谢你提供的信息。我没有意识到我可以使用这种表示法(尽管考虑到Javascript对象的性质,这是有意义的)。不幸的是,更新代码后出现了同样的错误(我也会更新问题中的示例代码)。如果使用括号表示法属性访问器以同样的方式失败,是否有其他方法来执行动态函数调用?@John Biesnecker是的,但您真的需要它们吗?似乎您可以轻松地使用常规函数和/或查找表,而不是将3
硬编码为generate\u 0\u 4()
--除非有很多经过编辑的代码。@banzaimonkey说“做一些很酷的东西并返回它”非常复杂,而且调用了很多次,但我当然可以用查找表来代替。不过,大多数情况下,它是“这必须是可能的!”关于未来的问题。@CMS,非常感谢您提供更多信息的链接。这是一只神秘的野兽……:)当我直接调用生成0\u 4
时,它会工作。但是,在摆脱了CMS的答案后,仍然没有骰子。啊,动态范围界定的乐趣!太好了,这正是我需要的。JS的对象语法的确切工作原理对我来说仍然是个谜,但是你所建议的方法非常有效。谢谢所以foo.bar()相当于bar.call(foo)?@justin-在我的示例中,是的。(实际上,函数在当前作用域中的名称可能与其作为对象属性的名称相匹配,也可能不匹配,但您知道了。)谢谢您的回答,Dave。对不起,我比你先到了本的楼上,他们都在工作。:)
var functionCall = this['generate_' + level + '_' + skill];
return functionCall(count);
this['generate_' + level + '_' + skill](count);