Javascript:动态添加函数到对象

时间:2016-09-07 16:26:26

标签: javascript function dynamic

我有一个GeneralWrapper对象,可以调用Library1Library2对象中的静态定义函数。

目的是通过致电GeneralWrapper.someFunc(),这也会调用Library1.someFunc()Library2.someFunc(),而我无需在名为GeneralWrapper的{​​{1}}中明确创建一个功能

我尝试在下面的someFunc方法中实现此功能:

__preamble

出于某种原因,对var GeneralWrapper = { __modespopulated: false, __validmodes: { // All 3 of these spoonFunc: 1, // functions exist knifeFunc: 1, // in Library1 and forkFunc: 1 // Library2 }, __switchMode: function(funcname){ if (funcname in GeneralWrapper.__validmodes){ console.log("calling function", funcname) GeneralWrapper.__preamble() Library1[ funcname ](); // Call mode in Library1 Library2[ funcname ](); // Call mode in Library2 } }, /* Attach valid modes to General Wrapper at runtime */ __preamble: function(){ if (!GeneralWrapper.__modespopulated) { for (var mode in GeneralWrapper.__validmodes) { GeneralWrapper[mode] = function(){ GeneralWrapper.__switchMode(mode) }; } GeneralWrapper.__modespopulated = true } GeneralWrapper.__otherprestuff(); }, __otherprestuff: function(){ // Stuff }, funcThatAlwaysGetsCalled: function(){ GeneralWrapper.__switchMode("forkFunc"); } } var Library1 = { forkFunc(){console.log("Lib1","fork")}, spoonFunc(){console.log("Lib1","spoon")}, knifeFunc(){console.log("Lib1","knife")} } var Library2 = { forkFunc(){console.log("Lib2","FORK")}, spoonFunc(){console.log("Lib2","SPOON")}, knifeFunc(){console.log("Lib2","KNIFE")} } // Okay, let's initialise the object GeneralWrapper.funcThatAlwaysGetsCalled(); GeneralWrapper.spoonFunc()的调用始终遵循Fork输出。

我认为问题源于GeneralWrapper.knifeFunc()行上的匿名函数赋值,JS每次都将它视为相同的函数,但我不知道如何解决这个问题。

请告知。

2 个答案:

答案 0 :(得分:1)

解决方案:

更改此行:

for (var mode in GeneralWrapper.__validmodes)

进入这个:

for (let mode in GeneralWrapper.__validmodes)

说明:

您的代码中发生的事情(在__preamble循环中绑定函数时)是您创建一个匿名函数,这是完全正常的。问题是,你的anon函数已经收到mode作为对局部变量的引用,因此它的值不会被自动克隆,而是在运行时被访问。主要问题是您使用了var关键字,这意味着"提升变量" (它被声明在内部定义的函数的顶部,即使它位于函数代码中间的某个位置)。在这种情况下,您需要一个"块范围的"变量,它将分别绑定到每个循环迭代。

您可以在MDN上阅读有关变量托管的更多信息:
var at MDN
let at MDN

您必须了解的一件事 - let已在ES2015中引入,因此,如果您担心与旧版浏览器的向后兼容性,则必须使用Function.prototype.bindIIFE

答案 1 :(得分:1)

这里的一个潜在问题是你在循环中创建函数会导致一些性能问题或意外行为。

我替换:

for (var mode in GeneralWrapper.__validmodes)
{
    GeneralWrapper[mode] = function(){
        GeneralWrapper.__switchMode(mode)
    };
}

使用:

for (var mode in GeneralWrapper.__validmodes)
{
    GeneralWrapper[mode] = GeneralWrapper.__switchMode.bind(this, mode);
}

哪个应该可以解决手头的问题。