Tôi có cái này:
this.f = function instance(){};
Tôi muốn có cái này:
this.f = function ["instance:" + a](){};
Tôi có cái này:
this.f = function instance(){};
Tôi muốn có cái này:
this.f = function ["instance:" + a](){};
this["instance" + a] = function() { }
. Điều đó không rõ ràng với tôi.
Câu trả lời:
Như những người khác đã đề cập, đây không phải là giải pháp nhanh nhất và cũng không được khuyến khích nhất. Giải pháp của Marcosc dưới đây là cách để đi.
Bạn có thể sử dụng eval:
var code = "this.f = function " + instance + "() {...}";
eval(code);
eval()
(hàm Function
tạo thực hiện điều đó bên trong).
Về cơ bản, điều này sẽ thực hiện ở cấp độ đơn giản nhất:
"use strict";
var name = "foo";
var func = new Function(
"return function " + name + "(){ alert('sweet!')}"
)();
//call it, to test it
func();
Nếu bạn muốn lạ mắt hơn, tôi có một bài viết về " Tên hàm động trong JavaScript ".
eval
để đánh giá javascript - do đó mở mã của bạn cho một loạt các lỗ hổng.
Bạn có thể sử dụng Object.defineProperty như được lưu ý trong Tài liệu tham khảo JavaScript MDN [1]:
var myName = "myName";
var f = function () { return true; };
Object.defineProperty(f, 'name', {value: myName, writable: false});
function fn()
, fn
là tên gốc. Kỳ dị.
Trong các công cụ gần đây, bạn có thể làm
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})
mã của riêng mình, vì tôi nghĩ nó có thể tự nhiên và dễ hiểu hơn một chút.
{[expr]: val}
là bộ khởi tạo đối tượng (đối tượng JSON) ở đâu expr
là một số biểu thức; bất cứ điều gì nó đánh giá là chìa khóa. {myFn (..){..} }
là viết tắt của {myFn: function myFn(..){..} }
. Lưu ý rằng function myFn(..) {..}
có thể được sử dụng như một biểu thức giống như một hàm ẩn danh, myFn
sẽ chỉ có tên. Cuối cùng [name]
chỉ là truy cập thành viên của đối tượng (giống như obj.key
hoặc obj['key']
). ...
là toán tử spread. (Nguồn chính: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )
this
. Ví dụ obj={x:7,getX(){return this.x}}; obj.getX=nameFunction('name',obj.getX); obj.getX();
sẽ không hoạt động. Bạn có thể chỉnh sửa câu trả lời của mình và sử dụng function nameFunction(name, body) { return {[name](...args) {return body.apply(this, args)}}[name] }
thay thế!
Tôi nghĩ rằng hầu hết các đề xuất ở đây là không tối ưu, bằng cách sử dụng đánh giá, giải pháp hacky hoặc trình bao bọc. Kể từ ES2015, tên được suy ra từ vị trí cú pháp cho các biến và thuộc tính.
Vì vậy, điều này sẽ hoạt động tốt:
const name = 'myFn';
const fn = {[name]: function() {}}[name];
fn.name // 'myFn'
Hãy chống lại sự cám dỗ tạo ra các phương thức của nhà máy hàm được đặt tên vì bạn sẽ không thể chuyển hàm từ bên ngoài và trang bị thêm nó vào vị trí cú pháp để suy ra tên của nó. Vậy thì đã quá muộn. Nếu bạn thực sự cần điều đó, bạn phải tạo một trình bao bọc. Ai đó đã làm điều đó ở đây, nhưng giải pháp đó không hoạt động đối với các lớp (cũng là các hàm).
Một câu trả lời chuyên sâu hơn với tất cả các biến thể đã nêu đã được viết tại đây: https://stackoverflow.com/a/9479081/633921
Thế còn
this.f = window["instance:" + a] = function(){};
Hạn chế duy nhất là hàm trong phương thức toSource của nó sẽ không chỉ ra tên. Đó thường chỉ là một vấn đề đối với trình gỡ lỗi.
Cú pháp function[i](){}
ngụ ý một đối tượng có các giá trị thuộc tính là các hàm function[]
, được lập chỉ mục bởi tên [i]
,.
Như vậy
{"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]
sẽ duy trì nhận dạng tên hàm. Xem ghi chú bên dưới về :
.
Vì thế,
javascript: alert(
new function(a){
this.f={"instance:1":function(){}, "instance:A":function(){}} ["instance:"+a]
}("A") . toSource()
);
hiển thị ({f:(function () {})})
trong FireFox.
(Đây gần giống ý tưởng với giải pháp này , chỉ khác là nó sử dụng một đối tượng chung và không còn điền trực tiếp vào đối tượng cửa sổ với các chức năng.)
Phương thức này điền rõ ràng môi trường với instance:x
.
javascript: alert(
new function(a){
this.f=eval("instance:"+a+"="+function(){})
}("A") . toSource()
);
alert(eval("instance:A"));
màn hình
({f:(function () {})})
và
function () {
}
Mặc dù hàm thuộc tính f
tham chiếu đến một anonymous function
và không instance:x
, phương pháp này tránh một số vấn đề với giải pháp này .
javascript: alert(
new function(a){
eval("this.f=function instance"+a+"(){}")
}("A") . toSource()
);
alert(instanceA); /* is undefined outside the object context */
chỉ hiển thị
({f:(function instanceA() {})})
:
làm cho javascript function instance:a(){}
không hợp lệ.eval
.Những điều sau đây không nhất thiết phải có vấn đề,
instanceA
chức năng không phải là trực tiếp có sẵn để sử dụng nhưinstanceA()
và do đó phù hợp hơn nhiều với bối cảnh vấn đề ban đầu.
Với những cân nhắc này,
this.f = {"instance:1": function instance1(){},
"instance:2": function instance2(){},
"instance:A": function instanceA(){},
"instance:Z": function instanceZ(){}
} [ "instance:" + a ]
duy trì môi trường điện toán toàn cầu với ngữ nghĩa và cú pháp của ví dụ OP càng nhiều càng tốt.
(name => ({[name]:function(){}})[name])('test')
hoạt động nhưng (name => {var x={}; x[name] = function(){}; return x[name];})('test')
không
Câu trả lời được bình chọn nhiều nhất đã có thân hàm [Chuỗi] được xác định. Tôi đang tìm giải pháp để đổi tên tên của hàm đã được khai báo và cuối cùng sau một giờ vật lộn, tôi đã xử lý được nó. Nó:
.toString()
phương thứcfunction
và(
new Function()
tạofunction 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){...}
Các phương thức động của một đối tượng có thể được tạo bằng Object Literal Extensions do ECMAScript 2015 (ES6) cung cấp:
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);
Kết quả của việc chạy đoạn mã trên là:
"called method instance: foo"
"called method instance: bar"
Object {
"instance: bar": [Function anonymous],
"instance: foo": [Function anonymous]
}
o={}; o[name]=(()=>{})
hơn làfunction <<name>>(){}
Để đặt tên của một hàm ẩn danh hiện có :
(Dựa trên câu trả lời của @ 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
Lưu ý : Đừng làm điều đó; /
Có hai phương pháp để đạt được điều này, và chúng có những ưu và khuyết điểm.
name
định nghĩa tài sảnĐịnh nghĩa thuộc name
tính bất biến của một hàm.
() 全 {}/1/얏호/ :D #GO(@*#%! /*
)name
giá trị thuộc tính của nó .Tạo một biểu thức hàm được đặt tên và đánh giá nó bằng hàm tạo.Function
name
giá trị thuộc tính của nó .(){}/1//
, biểu thức là return function (){}/1//() {}
, cho NaN
thay vì một hàm.).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
Nếu bạn muốn có một hàm động giống như __call
hàm trong PHP, bạn có thể sử dụng Proxy.
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
})()
Bạn có thể sử dụng Tên hàm động và các tham số như thế này.
1) Xác định chức năng Tách biệt và gọi nó
let functionName = "testFunction";
let param = {"param1":1 , "param2":2};
var func = new Function(
"return " + functionName
)();
func(param);
function testFunction(params){
alert(params.param1);
}
2) Xác định mã chức năng động
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);
Cảm ơn bạn Marcosc! Dựa trên câu trả lời của anh ấy, nếu bạn muốn đổi tên bất kỳ hàm nào , hãy sử dụng:
// returns the function named with the passed name
function namedFunction(name, fn) {
return new Function('fn',
"return function " + name + "(){ return fn.apply(this,arguments)}"
)(fn)
}
Chức năng tiện ích này hợp nhất nhiều chức năng thành một (sử dụng tên tùy chỉnh), chỉ yêu cầu là các chức năng được cung cấp phải được "xếp hàng mới" đúng cách ở đầu và cuối của tin sốt dẻo.
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
Tôi đã may mắn hơn khi kết hợp câu trả lời của Darren và câu trả lời của 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
Lưu ý: configurable
được đặt để true
phù hợp với thông số tiêu chuẩn của ES2015 cho Function.name 1
Điều này đặc biệt giúp khắc phục lỗi trong Webpack tương tự như lỗi này .
Cập nhật: Tôi đã nghĩ đến việc xuất bản này dưới dạng gói npm , nhưng gói này từ sindresorhus thực hiện chính xác điều tương tự.
Tôi đã đấu tranh rất nhiều với vấn đề này. Giải pháp @Albin hoạt động như một sự quyến rũ trong khi phát triển, nhưng nó không hoạt động khi tôi thay đổi nó thành sản xuất. Sau một số lần gỡ lỗi, tôi nhận ra cách đạt được những gì tôi cần. Tôi đang sử dụng ES6 với CRA (create-react-app), có nghĩa là nó được bao gồm bởi Webpack.
Giả sử bạn có một tệp xuất các chức năng bạn cần:
myFunctions.js
export function setItem(params) {
// ...
}
export function setUser(params) {
// ...
}
export function setPost(params) {
// ...
}
export function setReply(params) {
// ...
}
Và bạn cần gọi động các hàm này ở nơi khác:
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);
}
}
}
}
}
}
cách tốt nhất là tạo đối tượng với danh sách các hàm động như:
const USER = 'user';
const userModule = {
[USER + 'Action'] : function () { ... },
[USER + 'OnClickHandler'] : function () { ... },
[USER + 'OnCreateHook'] : function () { ... },
}
function myFunction() {
console.log('It works!');
}
var name = 'myFunction';
window[name].call();
Tôi có thể thiếu điều hiển nhiên ở đây, nhưng có gì sai khi chỉ thêm tên? các hàm được gọi bất kể tên của chúng. tên chỉ được sử dụng vì lý do xác định phạm vi. nếu bạn gán nó cho một biến và nó nằm trong phạm vi, nó có thể được gọi. hat xảy ra là bạn đang thực thi một biến có thể là một hàm. nếu bạn phải có tên vì lý do nhận dạng khi gỡ lỗi, hãy chèn tên đó vào giữa hàm từ khóa và dấu ngoặc nhọn mở.
var namedFunction = function namedFunction (a,b) {return a+b};
alert(namedFunction(1,2));
alert(namedFunction.name);
alert(namedFunction.toString());
một cách tiếp cận thay thế là bọc hàm trong một miếng đệm được đổi tên bên ngoài, bạn cũng có thể chuyển hàm này vào một lớp bọc bên ngoài, nếu bạn không muốn làm bẩn vùng tên xung quanh. nếu bạn muốn thực sự tạo động hàm từ các chuỗi (mà hầu hết các ví dụ này đều làm), thì việc đổi tên nguồn để thực hiện những gì bạn muốn là rất nhỏ. Tuy nhiên, nếu bạn muốn đổi tên các chức năng hiện có mà không ảnh hưởng đến chức năng của chúng khi được gọi ở nơi khác, thì một miếng đệm là cách duy nhất để đạt được điều đó.
(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
rất hữu ích vì nó được suy ra từ biến và thuộc tính. Nó cũng được sử dụng trong dấu vết ngăn xếp. Ex var fn = function(){}; console.log(fn.name)
. Nó là bất biến, vì vậy bạn không thể thay đổi nó sau này. Nếu bạn viết một phương thức gốc đặt tên cho tất cả các hàm fn
thì điều này sẽ khiến việc gỡ lỗi trở nên khó khăn hơn.
this["instance"] = function() { }