JavaScript中的动态函数名称

Ood*_*Ood 1 html javascript dom function dynamic

这可能看起来有点奇怪,但在创建动态事件监听器时会派上用场,我会尽力解释我想要实现的目标.

我有一个变量,我想创建一个以该变量值命名的函数.这是一个例子:

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"
Run Code Online (Sandbox Code Playgroud)

谢谢!

T.J*_*der 8

2016年更新的答案:

"但是,这种情况正在发生变化......"以下原始答案的一部分已经改变.ES2015("ES6")在一年前发布,JavaScript引擎现在终于符合其中一个鲜为人知的方面:Function#name.

从ES2015开始,尽管使用"匿名"函数表达式创建,但此函数仍具有名称:

var f = function() { };
Run Code Online (Sandbox Code Playgroud)

它的名字是f.这是由几十个不同地方的规范(或ES2016规范)决定的(搜索使用的地方SetFunctionName).在这种特殊情况下,它是因为它获取了它所分配的变量的名称.(我已经在var那里使用而不是新的,let以避免给人的印象是这是一个特征let.它不是.但是因为这是ES2015,我let将从现在开始使用...)

现在,你可能会想"这对我没有帮助,因为它f是硬编码的",但坚持我.

这个函数也有这个名字f:

let obj = {
    f: function() { }
};
Run Code Online (Sandbox Code Playgroud)

它获取它被分配给()的属性的名称f.这就是ES2015的另一个便利功能生效的地方:对象初始化器中的计算属性名称.f我们可以使用计算属性名称,而不是字面上给出名称:

let functionName = "f";
let obj = {
    [functionName]: function() { }
};
Run Code Online (Sandbox Code Playgroud)

计算属性名称语法计算表达式[],然后使用结果作为属性名称.并且由于该函数从它所分配的属性中获取了一个真实的名称,我们可以使用运行时确定的名称创建一个函数.

如果我们不想要任何对象,我们不需要保留它:

let functionName = "f";
let f = ({
    [functionName]: function() { }
})[functionName];
Run Code Online (Sandbox Code Playgroud)

这会创建带有函数的对象,然后从对象中获取函数并抛弃对象.

当然,如果你想使用词法this,它可能是一个箭头函数:

let functionName = "f";
let f = ({
    [functionName]: () => { }
})[functionName];
Run Code Online (Sandbox Code Playgroud)

这是一个例子,适用于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);
}
Run Code Online (Sandbox Code Playgroud)


2014年的原始答案:

什么你从字面上要求不使用是不可能的eval,除非你想要的功能是全球性的.如果你这样做,你可以这样做:

// Creates global function
window[functionName] = function() { };
Run Code Online (Sandbox Code Playgroud)

请注意,该函数实际上没有名称(在调用堆栈中等等;但是它正在改变,请参阅下面的注释),但您可以使用变量中的名称来调用它.例如:

var functionName = "foo";
window[functionName] = function() {
    console.log("I got called");
};
foo(); // Outputs "I got called"
Run Code Online (Sandbox Code Playgroud)

这只是使用对象属性的更通用概念的特定情况.这是附加到对象属性的非全局函数:

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"
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,它都可以工作,因为在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();
})();
Run Code Online (Sandbox Code Playgroud)

这是关于函数名称的"下面注释":截至当前标准ECMAScript第5版,此函数没有名称:

var f = function() { };
Run Code Online (Sandbox Code Playgroud)

这是一个匿名函数定义.这是另一个:

obj.f = function() { };
Run Code Online (Sandbox Code Playgroud)

在第一个中,变量有一个名称(f),但函数没有; 第二,该财产的对象上有一个名字,但功能却没有.

但是,这种情况正在改变.从第6版规范(目前仍为草案)开始f,即使使用上面的表达式,引擎也会给函数命名.它还会从稍微复杂的表达式中推断出名称.Firefox的引擎至少已经完成了一段时间,Chrome正在开始,它将在下一版规范中指定.