[英]Dynamic function names in JavaScript
这可能看起来有点奇怪,但在创建动态事件侦听器时会派上用场,我会尽力解释我想要实现的目标。
我有一个变量,我想创建一个以该变量值命名的 function。 这是一个例子:
var functionName = "foo";
// Now I want to create a function named foo. foo is a tring
function [functionName](){
alert('nothing really');
}
foo(); //Should alert "nothing really"
谢谢!
2016年更新的答案:
下面原始答案的“但是,情况正在改变...”部分已更改。 ES2015(“ ES6”)于一年前发布,JavaScript引擎现在终于符合其鲜为人知的方面之一: Function#name
。
从ES2015开始,尽管使用“匿名”函数表达式创建了该函数,但其名称仍为:
var f = function() { };
它的名字叫f
。 这是通过规定的规格 (或为ES2016新在几十个不同的地方)(搜索其中SetFunctionName
使用)。 在这种情况下,这是因为它获得了要分配给它的变量的名称。 (我用var
那里,而不是新的let
,以避免给人的印象是,这是一个特点let
,这是不行,但因为这是ES2015,我将使用let
从现在开始...)
现在,您可能会想“这对我没有帮助,因为f
是硬编码的”,但请坚持我。
该函数也具有f
的名称:
let obj = {
f: function() { }
};
它获取分配给( f
)的属性的名称。 这就是ES2015的另一个便捷功能生效的地方:对象初始化程序中的计算属性名称。 不用从字面上给出名称f
,我们可以使用计算所得的属性名称:
let functionName = "f";
let obj = {
[functionName]: function() { }
};
计算出的属性名称语法对[]
的表达式求值,然后将结果用作属性名称。 而且由于函数是从为其分配的属性中获得真实名称的,因此我们可以使用运行时确定的名称来创建函数。
如果我们不想要任何对象,则不需要保留它:
let functionName = "f";
let f = ({
[functionName]: function() { }
})[functionName];
这将创建带有功能的对象,然后从对象中获取功能并将其扔掉。
当然,如果要使用词法this
,则可以使用箭头函数代替:
let functionName = "f";
let f = ({
[functionName]: () => { }
})[functionName];
这是一个示例,该示例可在Chrome 51及更高版本上运行,但在许多其他版本上尚不可用:
// Get the name let functionName = prompt( "What name for the function?", "func" + Math.floor(Math.random() * 10000) ); // Create the function let f = ({ [functionName]: function() { } })[functionName]; // Check the name if (f.name !== functionName) { console.log("This browser's JavaScript engine doesn't fully support ES2015 yet."); } else { console.log("The function's name is: " + f.name); }
2014年的原始答案:
除非您希望函数为全局函数,否则您不使用eval
就无法实现您真正要求的内容。 如果这样做,则可以执行以下操作:
// Creates global function
window[functionName] = function() { };
请注意,该函数实际上没有名称 (在调用堆栈等中;但是这种情况正在改变,请参阅下面的注释),但是您可以在变量中使用该名称来调用它。 因此,例如:
var functionName = "foo";
window[functionName] = function() {
console.log("I got called");
};
foo(); // Outputs "I got called"
这只是使用对象属性的更通用概念的一个特例。 这是附加到对象属性的非全局函数:
var functionName = "foo";
var obj = {}; // The object
obj[functionName] = function() { }; // The function
obj[functionName] = function() {
console.log("I got called");
};
obj.foo(); // Outputs "I got called"
在这两种情况下,它都有效,因为在JavaScript中,您可以使用点分表示法和文字属性名称( obj.foo
)来引用属性,也可以使用带括号的表示法和字符串属性名称( obj["foo"]
)来引用属性。 当然,在后一种情况下,您可以使用任何计算结果为字符串的表达式。
仅出于完整性考虑,下面是使用eval
:
(function() { // This scoping function is just to emphasize we're not at global scope
var functionName = "foo";
eval("function " + functionName + "() { print('I got called'); }");
foo();
})();
这是有关函数名称的“以下注释”:从当前标准ECMAScript 5版开始,该函数没有名称:
var f = function() { };
那是一个匿名函数定义。 这是另一个:
obj.f = function() { };
首先, 变量有一个名称( f
),但函数没有名称; 第二,对象上的属性有一个名称,但功能却没有。
但是,情况正在改变。 从第6版规范开始(当前仍是草案),即使使用上述表达式,引擎也将为函数命名为f
。 并且它还将从稍微复杂的表达式中推断出名称。 Firefox的引擎至少已经完成了一段时间,Chrome已经开始使用,它将在下一版规范中进行指定。
JavaScript中的“全局”功能只是全局上下文对象(浏览器中的window
)的属性。 因此,您可以通过这种方式完成您要寻找的工作:
var functionName = 'foo';
window[functionName] = function() {
alert('nothing really');
}
此语法有点类似于 MongoDB / Mongoose Schema Virtuals。 您为 object 提供方法名称和执行上下文。
文件:temp-obj.js
const modelInstance = {
name: null,
virtual(name = null) {
if (!name) {
throw new Error("Name is required");
}
this.name = name;
// allows us to chain methods
return this;
},
get(func = false) {
if (!this.name || !func instanceof Function) {
throw new Error("Name and function are required");
}
// Here we attach the dynamic function name to the "this" Object (which represents the current object modelInstance)
this[this.name] = func;
this.name = null;
},
};
module.exports = modelInstance;
文件:index.js
const modelInstance = require("./temp-obj.js");
// This is a two step approach, we name a function and provide it with an execution context
modelInstance.virtual("setMyCount").get((count) => {
return { count: count };
});
const objVal = modelInstance.setMyCount(100);
console.log(objVal);
如果有兴趣,我有一个类似的响应使用JavaScript Class 基于动态 Function 名称
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.