ฉันมีสิ่งนี้:
this.f = function instance(){};
ฉันต้องการสิ่งนี้:
this.f = function ["instance:" + a](){};
ฉันมีสิ่งนี้:
this.f = function instance(){};
ฉันต้องการสิ่งนี้:
this.f = function ["instance:" + a](){};
this["instance" + a] = function() { }
บอกว่าคุณสามารถทำ นั่นไม่ชัดเจนสำหรับฉัน
คำตอบ:
ตามที่คนอื่น ๆ กล่าวไว้นี่ไม่ใช่วิธีแก้ปัญหาที่เร็วที่สุดหรือแนะนำมากที่สุด วิธีแก้ปัญหาของ 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 "
eval
ในการประเมินจาวาสคริปต์ซึ่งจะเป็นการเปิดโค้ดของคุณเพื่อเจาะช่องโหว่
คุณสามารถใช้ Object.defineProperty ได้ตามที่ระบุไว้ใน MDN JavaScript Reference [1]:
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}
เป็น object initializer (เช่นเดียวกับออบเจ็กต์ 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] }
แทนได้!
ฉันคิดว่าคำแนะนำส่วนใหญ่ที่นี่เป็นเรื่องที่ไม่เหมาะสมโดยใช้ eval, โซลูชันที่แฮ็กหรือ Wrapper ในขณะที่ชื่อ 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
อ้างถึงanonymous function
และไม่ใช่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() {})})
:
ทำให้จาวาสคริปต์function 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()
วิธีการ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){...}
วิธีการแบบไดนามิกของออบเจ็กต์อาจสร้างขึ้นโดยใช้ Object Literal Extensions ที่จัดทำโดย 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
})()
คุณสามารถใช้ Dynamic Function Name และพารามิเตอร์เช่นนี้
1) กำหนดฟังก์ชันแยกและเรียกมันว่า
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);
ขอบคุณ Marcosc! จากคำตอบของเขาหากคุณต้องการเปลี่ยนชื่อฟังก์ชันใด ๆให้ใช้สิ่งนี้:
// 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)
}
ฟังก์ชั่นยูทิลิตี้นี้รวมฟังก์ชันหลายฟังก์ชันเข้าด้วยกัน (โดยใช้ชื่อที่กำหนดเอง) ข้อกำหนดเพียงอย่างเดียวคือฟังก์ชันที่จัดเตรียมให้ "เรียงใหม่" อย่างถูกต้องเมื่อเริ่มต้นและสิ้นสุดของสกู๊ป
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
ผมมีโชคที่ดีขึ้นในการรวมคำตอบที่คาร์เรนและคำตอบของ 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
ตรงกับข้อกำหนด ES2015 มาตรฐานสำหรับ Function.name 1
นี้โดยเฉพาะอย่างยิ่งช่วยในการรับรอบข้อผิดพลาดใน 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);
}
}
}
}
}
}
วิธีที่ดีที่สุดคือสร้างวัตถุที่มีรายการฟังก์ชันแบบไดนามิกเช่น:
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();
ฉันอาจจะพลาดตรงนี้ไป แต่เกิดอะไรขึ้นกับการเพิ่มชื่อ? มีการเรียกใช้ฟังก์ชันโดยไม่คำนึงถึงชื่อ ชื่อใช้เพื่อเหตุผลในการกำหนดขอบเขต หากคุณกำหนดให้กับตัวแปรและอยู่ในขอบเขตก็สามารถเรียกใช้ได้ hat เกิดขึ้นคือคุณกำลังเรียกใช้ตัวแปรซึ่งเป็นฟังก์ชัน หากคุณต้องมีชื่อสำหรับเหตุผลในการระบุตัวตนเมื่อทำการดีบักให้แทรกระหว่างฟังก์ชันคำหลักและวงเล็บปีกกา
var namedFunction = function namedFunction (a,b) {return a+b};
alert(namedFunction(1,2));
alert(namedFunction.name);
alert(namedFunction.toString());
อีกทางเลือกหนึ่งคือการรวมฟังก์ชันไว้ใน shim ที่เปลี่ยนชื่อภายนอกซึ่งคุณสามารถส่งผ่านไปยัง wrapper ด้านนอกได้หากคุณไม่ต้องการทำให้เนมสเปซโดยรอบสกปรก หากคุณต้องการสร้างฟังก์ชันจากสตริงแบบไดนามิกจริง ๆ (ซึ่งตัวอย่างเหล่านี้ส่วนใหญ่ทำ) การเปลี่ยนชื่อแหล่งที่มาเพื่อทำสิ่งที่คุณต้องการเป็นเรื่องเล็กน้อย อย่างไรก็ตามหากคุณต้องการเปลี่ยนชื่อฟังก์ชั่นที่มีอยู่โดยไม่ส่งผลกระทบต่อฟังก์ชันการทำงานเมื่อถูกเรียกใช้ที่อื่น shim เป็นวิธีเดียวที่จะทำให้สำเร็จ
(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_" + a] = function () {...};
{... };
this["instance"] = function() { }