扩展Array类会破坏我的代码

时间:2014-07-17 13:37:54

标签: javascript oop

如果我从代码中删除了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();

它会中断,因为警报未显示:

  

这是方法嘿

但:

  

这是方法函数()   {
  警报('上午');   }

2 个答案:

答案 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); };
});