【问题标题】:Extending the Array class breaks my code扩展 Array 类会破坏我的代码
【发布时间】:2014-07-17 13:37:54
【问题描述】:

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

它中断了,因为警报没有显示:

这是方法嘿

但是:

这是方法function() {
警报(“早上”); }

【问题讨论】:

  • 中断...出现什么错误?
  • @tymeJV 抱歉,已按问题更新

标签: javascript oop


【解决方案1】:

也许这就是你想要的:

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);
                };
            })();
        }
    }
}

【讨论】:

  • 仍然无法工作,因为变量“i”仍然来自闭包。
  • 哦,天哪,我错过了return function 部分。是的,这将解决它:)(尽管最好避免for ... in。)
  • @ilyamilosevic 谢谢。它可以满足我的需要,但我认为我会坚持使用 forEach 选项,因为它更短一些。你发布了一个不错的技巧,我一定会记住的:)
  • 是的,我同意使用forEach,但我认为主要问题不在此,所以我没有更改它。
【解决方案2】:

请看下面,但问题是:变量“i”在闭包中并且被构造函数中创建的所有函数实例共享。

现在,您正在为每个属性名称创建一个函数(包括名称是那个“无”函数的文本的属性,但这只是切线相关)。在for ... in 循环中出现的最后一个属性名称是名称“nothing”(尽管语言规范中不保证循环会以任何特定顺序遍历属性名称)。之后,循环退出,“i”的最终值为字符串“nothing”。

现在,稍后,当您调用c.hello() 时,该小函数可以访问来自对构造函数的原始调用的变量“i”和“method”。 “我”的价值是什么?它仍然是字符串“nothing”,所以hello() 函数给你的是methods["nothing"] 的值,也就是那个函数的文本。

避免for ... in 循环将部分解决问题,但不能完全解决。但是.forEach() 方法会起作用,因为每个创建的函数都有自己的私有name,它永远不会改变。


当您将该属性添加到 Array 原型时,它将作为您的 for ... in 循环中的属性名称之一出现。因此,“i”的值之一将是“nothing”,因为在扩展数组原型之后,字符串“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); };
});

【讨论】:

  • 感谢您的建议,我一定会使用它,但在这里没有帮助。我按问题更新 - 警报显示错误的文字。
  • @Tom 是的,它显示了错误的文本,因为您的代码没有充分测试对象属性名称。你真的试过我建议的代码吗?
  • @Tom 我会用更多的解释来扩展答案。
  • 是的,我做到了,但是我的“无”函数没有在 MyClass 中声明,所以没有冲突
  • @Tom 在 Array 原型上声明,“methods”是一个数组!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-15
相关资源
最近更新 更多