我有这个:
this.f = function instance(){};
我想要这个:
this.f = function ["instance:" + a](){};
我有这个:
this.f = function instance(){};
我想要这个:
this.f = function ["instance:" + a](){};
this["instance" + a] = function() { }
。我不清楚。
Answers:
正如其他人提到的那样,这不是最快也不推荐的解决方案。Marcosc下面的解决方案是解决之道。
您可以使用eval:
var code = "this.f = function " + instance + "() {...}";
eval(code);
eval()
(Function
构造函数在内部执行此操作)。
基本上,这将在最简单的级别上完成:
"use strict";
var name = "foo";
var func = new Function(
"return function " + name + "(){ alert('sweet!')}"
)();
//call it, to test it
func();
如果您想花更多的钱,我写了一篇有关“ JavaScript中的动态函数名称”的文章。
您可以使用MDN JavaScript参考[1]中所述的Object.defineProperty:
var myName = "myName";
var f = function () { return true; };
Object.defineProperty(f, 'name', {value: myName, writable: false});
function fn()
,fn
是原来的名称。奇怪的。
在最近的引擎中,您可以
function nameFunction(name, body) {
return {[name](...args) {return body(...args)}}[name]
}
const x = nameFunction("wonderful function", (p) => p*2)
console.log(x(9)) // => 18
console.log(x.name) // => "wonderful function"
Object.defineProperty(func, 'name', {value: name})
在自己的代码中使用它,因为我认为它可能更自然,更易于理解。
{[expr]: val}
是一个对象初始化器(就像JSON对象一样),其中expr
是一些表达式;评估结果是关键。{myFn (..){..} }
是的简写{myFn: function myFn(..){..} }
。注意,function myFn(..) {..}
可以像匿名函数一样用作表达式,只有myFn
一个名称。最后[name]
就是访问对象的成员(就像obj.key
或一样obj['key']
)。...
是点差运算符。(主要来源:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…)
this
。例如,obj={x:7,getX(){return this.x}}; obj.getX=nameFunction('name',obj.getX); obj.getX();
将无法正常工作。您可以编辑答案并function nameFunction(name, body) { return {[name](...args) {return body.apply(this, args)}}[name] }
改用它!
我认为,通过使用评估,hacky解决方案或包装程序,此处的大多数建议都不理想。从ES2015开始,从变量和属性的语法位置推断名称。
所以这将很好地工作:
const name = 'myFn';
const fn = {[name]: function() {}}[name];
fn.name // 'myFn'
抵制创建命名函数工厂方法的诱惑,因为您将无法从外部传递函数并将其改型为语法位置以推断其名称。那已经为时已晚。如果确实需要,则必须创建一个包装器。有人在这里这样做,但是该解决方案不适用于类(也是函数)。
此处列出了有关所有变体的更深入的答案:https : //stackoverflow.com/a/9479081/633921
关于什么
this.f = window["instance:" + a] = function(){};
唯一的缺点是其toSource方法中的函数不会指示名称。对于调试器而言,通常这只是一个问题。
该语法function[i](){}
暗含一个对象,该对象的属性值是函数,function[]
由名称索引[i]
。
这样
{"f:1":function(){}, "f:2":function(){}, "f:A":function(){}, ... } ["f:"+i]
。
{"f:1":function f1(){}, "f:2":function f2(){}, "f:A":function fA(){}} ["f:"+i]
将保留功能名称标识。请参阅以下有关的注释:
。
所以,
javascript: alert(
new function(a){
this.f={"instance:1":function(){}, "instance:A":function(){}} ["instance:"+a]
}("A") . toSource()
);
({f:(function () {})})
在FireFox中显示。
(这几乎与该解决方案相同,只是使用了通用对象,不再使用函数直接填充窗口对象。)
此方法使用显式填充环境instance:x
。
javascript: alert(
new function(a){
this.f=eval("instance:"+a+"="+function(){})
}("A") . toSource()
);
alert(eval("instance:A"));
显示
({f:(function () {})})
和
function () {
}
尽管属性函数f
引用了ananonymous function
和not instance:x
,但此方法避免了此解决方案的几个问题。
javascript: alert(
new function(a){
eval("this.f=function instance"+a+"(){}")
}("A") . toSource()
);
alert(instanceA); /* is undefined outside the object context */
仅显示
({f:(function instanceA() {})})
:
使得javascriptfunction instance:a(){}
无效。eval
。以下不一定有问题,
instanceA
功能不能直接用作instanceA()
因此与原始问题的环境更加一致。
考虑到这些因素,
this.f = {"instance:1": function instance1(){},
"instance:2": function instance2(){},
"instance:A": function instanceA(){},
"instance:Z": function instanceZ(){}
} [ "instance:" + a ]
尽可能使用OP示例的语义和语法维护全局计算环境。
(name => ({[name]:function(){}})[name])('test')
作品有效但(name => {var x={}; x[name] = function(){}; return x[name];})('test')
不起作用
投票最多的答案已经定义了[String]函数体。我一直在寻找重命名已经声明的函数名称的解决方案,最后经过一个小时的努力,我已经解决了它。它:
.toString()
方法将其解析为[String]function
(
new Function()
构造函数创建新的重命名函数function nameAppender(name,fun){
const reg = /^(function)(?:\s*|\s+([A-Za-z0-9_$]+)\s*)(\()/;
return (new Function(`return ${fun.toString().replace(reg,`$1 ${name}$3`)}`))();
}
//WORK FOR ALREADY NAMED FUNCTIONS:
function hello(name){
console.log('hello ' + name);
}
//rename the 'hello' function
var greeting = nameAppender('Greeting', hello);
console.log(greeting); //function Greeting(name){...}
//WORK FOR ANONYMOUS FUNCTIONS:
//give the name for the anonymous function
var count = nameAppender('Count',function(x,y){
this.x = x;
this.y = y;
this.area = x*y;
});
console.log(count); //function Count(x,y){...}
可以使用ECMAScript 2015(ES6)提供的对象文字扩展来创建对象的动态方法:
const postfixes = ['foo', 'bar'];
const mainObj = {};
const makeDynamic = (postfix) => {
const newMethodName = 'instance: ' + postfix;
const tempObj = {
[newMethodName]() {
console.log(`called method ${newMethodName}`);
}
}
Object.assign(mainObj, tempObj);
return mainObj[newMethodName]();
}
const processPostfixes = (postfixes) => {
for (const postfix of postfixes) {
makeDynamic(postfix);
}
};
processPostfixes(postfixes);
console.log(mainObj);
运行上面的代码的输出是:
"called method instance: foo"
"called method instance: bar"
Object {
"instance: bar": [Function anonymous],
"instance: foo": [Function anonymous]
}
o={}; o[name]=(()=>{})
而不是function <<name>>(){}
设置现有匿名函数的名称:(
基于@Marcosc的答案)
var anonymous = function() { return true; }
var name = 'someName';
var strFn = anonymous.toString().replace('function ', 'return function ' + name);
var fn = new Function(strFn)();
console.log(fn()); // —> true
演示。
注意:不要这样做; /
有两种方法可以实现此目的,它们各有利弊。
name
属性定义定义函数的不可变name
属性。
() 全 {}/1/얏호/ :D #GO(@*#%! /*
)name
属性值不对应。制作命名函数表达式并使用构造函数对其进行求值Function
。
name
属性值相对应。(){}/1//
,表达式为return function (){}/1//() {}
,给出NaN
而不是函数。)。const demoeval = expr => (new Function(`return ${expr}`))();
// `name` property definition
const method1 = func_name => {
const anon_func = function() {};
Object.defineProperty(anon_func, "name", {value: func_name, writable: false});
return anon_func;
};
const test11 = method1("DEF_PROP"); // No whitespace
console.log("DEF_PROP?", test11.name); // "DEF_PROP"
console.log("DEF_PROP?", demoeval(test11.toString()).name); // ""
const test12 = method1("DEF PROP"); // Whitespace
console.log("DEF PROP?", test12.name); // "DEF PROP"
console.log("DEF PROP?", demoeval(test12.toString()).name); // ""
// Function expression evaluation
const method2 = func_name => demoeval(`function ${func_name}() {}`);
const test21 = method2("EVAL_EXPR"); // No whitespace
console.log("EVAL_EXPR?", test21.name); // "EVAL_EXPR"
console.log("EVAL_EXPR?", demoeval(test21.toString()).name); // "EVAL_EXPR"
const test22 = method2("EVAL EXPR"); // Uncaught SyntaxError: Unexpected identifier
如果您想要具有动态功能(如__call
PHP中的功能),则可以使用Proxies。
const target = {};
const handler = {
get: function (target, name) {
return (myArg) => {
return new Promise(resolve => setTimeout(() => resolve('some' + myArg), 600))
}
}
};
const proxy = new Proxy(target, handler);
(async function() {
const result = await proxy.foo('string')
console.log('result', result) // 'result somestring' after 600 ms
})()
您可以像这样使用动态函数名称和参数。
1)定义函数Separate并调用它
let functionName = "testFunction";
let param = {"param1":1 , "param2":2};
var func = new Function(
"return " + functionName
)();
func(param);
function testFunction(params){
alert(params.param1);
}
2)动态定义功能代码
let functionName = "testFunction(params)";
let param = {"param1":"1" , "param2":"2"};
let functionBody = "{ alert(params.param1)}";
var func = new Function(
"return function " + functionName + functionBody
)();
func(param);
该实用程序功能将多个功能合并为一个(使用自定义名称),仅要求提供的功能在其开始和结束时正确“换行”。
const createFn = function(name, functions, strict=false) {
var cr = `\n`, a = [ 'return function ' + name + '(p) {' ];
for(var i=0, j=functions.length; i<j; i++) {
var str = functions[i].toString();
var s = str.indexOf(cr) + 1;
a.push(str.substr(s, str.lastIndexOf(cr) - s));
}
if(strict == true) {
a.unshift('\"use strict\";' + cr)
}
return new Function(a.join(cr) + cr + '}')();
}
// test
var a = function(p) {
console.log("this is from a");
}
var b = function(p) {
console.log("this is from b");
}
var c = function(p) {
console.log("p == " + p);
}
var abc = createFn('aGreatName', [a,b,c])
console.log(abc) // output: function aGreatName()
abc(123)
// output
this is from a
this is from b
p == 123
我最好把Darren的答案和kyernetikos的答案结合起来。
const nameFunction = function (fn, name) {
return Object.defineProperty(fn, 'name', {value: name, configurable: true});
};
/* __________________________________________________________________________ */
let myFunc = function oldName () {};
console.log(myFunc.name); // oldName
myFunc = nameFunction(myFunc, 'newName');
console.log(myFunc.name); // newName
注意:configurable
设置为true
与Function.name 1的标准ES2015规范匹配
这尤其在获取周围的WebPack类似的错误帮助这一个。
更新:我当时想将其发布为npm软件包,但sindresorhus的此软件包的作用完全相同。
我为这个问题苦苦挣扎。@Albin解决方案在开发过程中像魔咒一样工作,但是当我将其更改为生产环境时却无法工作。经过一些调试后,我意识到了如何实现所需的功能。我将ES6与CRA(create-react-app)结合使用,这意味着它被Webpack捆绑了。
假设您有一个导出所需功能的文件:
myFunctions.js
export function setItem(params) {
// ...
}
export function setUser(params) {
// ...
}
export function setPost(params) {
// ...
}
export function setReply(params) {
// ...
}
您需要在其他地方动态调用这些函数:
myApiCalls.js
import * as myFunctions from 'path_to/myFunctions';
/* note that myFunctions is imported as an array,
* which means its elements can be easily accessed
* using an index. You can console.log(myFunctions).
*/
function accessMyFunctions(res) {
// lets say it receives an API response
if (res.status === 200 && res.data) {
const { data } = res;
// I want to read all properties in data object and
// call a function based on properties names.
for (const key in data) {
if (data.hasOwnProperty(key)) {
// you can skip some properties that are usually embedded in
// a normal response
if (key !== 'success' && key !== 'msg') {
// I'm using a function to capitalize the key, which is
// used to dynamically create the function's name I need.
// Note that it does not create the function, it's just a
// way to access the desired index on myFunctions array.
const name = `set${capitalizeFirstLetter(key)}`;
// surround it with try/catch, otherwise all unexpected properties in
// data object will break your code.
try {
// finally, use it.
myFunctions[name](data[key]);
} catch (error) {
console.log(name, 'does not exist');
console.log(error);
}
}
}
}
}
}
function myFunction() {
console.log('It works!');
}
var name = 'myFunction';
window[name].call();
我可能在这里没有明显的地方,但是仅添加名称又有什么问题呢?不管函数的名称如何,都将调用它们。名称仅用于范围确定的原因。如果将其分配给变量且在范围内,则可以调用它。发生的事情是您正在执行的变量恰好是一个函数。如果在调试时由于识别原因必须有一个名称,请将其插入关键字function和左括号之间。
var namedFunction = function namedFunction (a,b) {return a+b};
alert(namedFunction(1,2));
alert(namedFunction.name);
alert(namedFunction.toString());
另一种方法是将函数包装在重命名的外部填充程序中,如果您不想弄脏周围的名称空间,也可以将其传递到外部包装程序中。如果您实际上想根据字符串动态创建函数(这些示例大多数都这样做),那么将源重命名以执行所需的操作就很简单了。但是,如果您想重命名现有功能而不在其他地方调用时影响其功能,则垫片是实现此功能的唯一方法。
(function(renamedFunction) {
alert(renamedFunction(1,2));
alert(renamedFunction.name);
alert(renamedFunction.toString());
alert(renamedFunction.apply(this,[1,2]));
})(function renamedFunction(){return namedFunction.apply(this,arguments);});
function namedFunction(a,b){return a+b};
name
非常有用,因为现在可以从变量和属性中推断出它。它也用于堆栈跟踪。防爆var fn = function(){}; console.log(fn.name)
。它是不可变的,因此以后不能更改。如果您编写了一个工厂方法来命名所有函数,fn
那么这将使调试更加困难。
this["instance"] = function() { }