如果我从代码中删除了nothing()的声明 - 一切都很好。但是为什么扩展Array类会破坏MyClass的代码?
Array.prototype.nothing = function()
{
alert('Morning');
}
function MyClass()
{
var methods = ['hello', 'hey'];
for (var i in methods)
{
this[methods[i]] = function()
{
alert('This is method ' + methods[i]);
}
}
}
var c = new MyClass();
c.hello();
它会中断,因为警报未显示:
这是方法嘿
但:
这是方法函数() {
警报('上午'); }
答案 0 :(得分:2)
也许这就是你想要的:
function MyClass()
{
var methods = ['hello', 'hey'];
for (var i in methods)
{
if (methods.hasOwnProperty(i)) {
this[methods[i]] = (function() {
var method = methods[i];
return function() {
alert('This is method ' + method);
};
})();
}
}
}
答案 1 :(得分:1)
请参阅下面的内容,但问题是:您正在绊倒变量“i”在闭包中并由构造函数中创建的所有函数实例共享的事实。
现在,您正在做的是为每个属性名称创建一个函数(包括其名称是“无”函数的文本的属性,但这只是切线相关的类型)。在for ... in
循环中出现的最后一个属性名称是“无”(尽管在语言规范中无法保证循环将以任何特定顺序遍历属性名称)。之后,循环退出,最终值“i”为字符串“nothing”。
现在,稍后,当您调用c.hello()
时,该小函数可以访问从原始调用到构造函数的变量“i”和“method”。 “我”的价值是多少?它仍然是字符串“nothing”,所以hello()
函数给你的是methods["nothing"]
的值,它是该函数的文本。
避免for ... in
循环部分解决问题,但不完全。然而,.forEach()
方法将起作用,因为每个创建的函数都将拥有永远不会更改的私有name
。
将该属性添加到Array原型时,它将作为for ... in
循环中的某个属性名称出现。因此,“i”的值之一将是“nothing”,因为在扩展Array原型之后,字符串“nothing”将是任何数组的属性名称。你的变量“方法”当然是一个数组。因此在循环中,在某些时刻“i”将是“无”,methods["nothing"]
就是那个函数。将函数传递给alert()
会导致其源代码折叠为alert()
文本。
您可以避免测试问题:
for (var i in methods)
{
if (methods.hasOwnProperty(i)) {
this[methods[i]] = function()
{
alert('This is method ' + methods[i]);
}
}
}
更好的是,不要在Array实例上使用for ... in
循环 - 它从来都不是一个好主意(我可能不应该输入上面的内容):
for (var i = 0; i < methods.length; ++i) {
// etc
}
最后有.forEach()
:
var newInstance = this;
methods.forEach(function(name) {
newInstance[name] = function() { alert('This is method ' + name); };
});