简体   繁体   English

Javascript:向对象动态添加函数

[英]Javascript: Dynamically add functions to object

I have a GeneralWrapper object that calls the statically-defined functions in the Library1 and Library2 objects. 我有一个GeneralWrapper对象,该对象调用Library1Library2对象中的静态定义的函数。

The aim is that by calling GeneralWrapper.someFunc() , this will also call Library1.someFunc() and Library2.someFunc() without me having to explicitly create a function in GeneralWrapper called someFunc . 目的是通过调用GeneralWrapper.someFunc() ,也将调用Library1.someFunc()Library2.someFunc()而无需在GeneralWrapper显式创建一个名为someFunc的函数。

I attempt to implement this in the __preamble method below: 我尝试在下面的__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();

For some reason calls to GeneralWrapper.spoonFunc() and GeneralWrapper.knifeFunc() always defer to the Fork output. 出于某些原因,对GeneralWrapper.spoonFunc()GeneralWrapper.knifeFunc()调用始终会延迟到Fork输出。

I imagine the problem stems from the anonymous function assignment on the GeneralWrapper[mode] = blah line where JS treats it as the same function each time, but I don't know how to get around this. 我想这个问题源于GeneralWrapper[mode] = blah行上的匿名函数分配,其中JS每次都将其视为相同的函数,但是我不知道该如何解决。

Please advise. 请指教。

Solution: 解:

Change this line: 更改此行:

for (var mode in GeneralWrapper.__validmodes)

into this: 到这个:

for (let mode in GeneralWrapper.__validmodes)

Explanation: 说明:

what happens in your code (when binding functions in __preamble 's loop) is that you create an anonymous function, which is totally fine. 在代码中发生的事情(在__preamble循环中绑定函数时)是您创建了一个匿名函数,这完全没问题。 The problem is, your anon function has received the mode as a reference to local variable, so it's value is not automatically cloned but rather accessed at runtime. 问题是,您的anon函数已收到该mode作为对局部变量的引用,因此它的值不会自动克隆,而是在运行时访问。 The main problem is that you've used var keyword, which means "hoisted variable" (it gets declared at the top of the function it was defined inside, even if it's somewhere in the middle of your function's code). 主要问题是您使用了var关键字,这意味着“提升的变量”(它在内部定义的函数的顶部声明,即使它位于函数代码的中间)。 In this scenario, you need a "block-scoped" variable, which will be bound to each loop iteration separately. 在这种情况下,您需要一个“块范围”变量,该变量将分别绑定到每个循环迭代。

You can read more about variables hostings on MDN: 您可以阅读有关MDN上的变量托管的更多信息:
var at MDN MDN的var
let at MDN 在MDN let

One thing you have to know - let was introduced in ES2015, so if you worry about backward compatibility with older browsers, you either have to use Function.prototype.bind or IIFE 有一件事你必须知道- let在ES2015介绍,因此,如果您担心与旧的浏览器向后兼容性,你要么必须使用Function.prototype.bindIIFE

One potential problem here is that you're creating functions inside a loop which can lead to some performance problems or unexpected behavior. 这里的一个潜在问题是,您正在循环内创建函数,这可能导致某些性能问题或意外行为。

I'd replace: 我将替换为:

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

with: 与:

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

Which should solve the problem at hand. 哪个应该解决手头的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM