ชื่อฟังก์ชันไดนามิกในจาวาสคริปต์?


89

ฉันมีสิ่งนี้:

this.f = function instance(){};

ฉันต้องการสิ่งนี้:

this.f = function ["instance:" + a](){};

10
คุณทำไม่ได้ แต่คุณสามารถมีthis["instance"] = function() { }
Raynos


เพื่อชี้แจงสิ่งที่ Raynos this["instance" + a] = function() { }บอกว่าคุณสามารถทำ นั่นไม่ชัดเจนสำหรับฉัน
Andrew

คำตอบ:


8

อัพเดต

ตามที่คนอื่น ๆ กล่าวไว้นี่ไม่ใช่วิธีแก้ปัญหาที่เร็วที่สุดหรือแนะนำมากที่สุด วิธีแก้ปัญหาของ Marcosc ด้านล่างเป็นวิธีที่จะไป

คุณสามารถใช้ eval:

var code = "this.f = function " + instance + "() {...}";
eval(code);

1
นั่นคือสิ่งที่ฉันขอขอบคุณ! (อย่างไรก็ตามฉันจะไม่ใช้คุณสมบัตินี้เนื่องจากช้าเกินไป)
Totty.js

3
ฉันรู้ว่านี่คือสิ่งที่ OP ขอ แต่นี่เป็นความคิดที่น่ากลัว เพียงเพราะคุณไม่สามารถหมายความว่าคุณควรทำสิ่งนี้ มีทางเลือกอื่นที่ดีกว่ามากซึ่งเกือบจะเหมือนกันกับฟังก์ชันการทำงานที่ชาญฉลาด
Thomas Eding

4
@ sg3s: คุณสามารถเสนอทางออกอื่นได้หรือไม่?
ทอม

2
@ sg3s: ขอบคุณที่ตอบความคิดเห็นของฉัน! ให้ฉันอธิบายว่าฉันหมายถึงอะไรและสิ่งที่ฉันต้องการถามจริง ๆ : โซลูชันของ Marcosc แตกต่างจาก eval อย่างมีนัยสำคัญหรือไม่ มันสร้างความแตกต่างได้จริงหรือไม่หากคุณประเมินบางสิ่งหรือป้อนให้กับตัวสร้างฟังก์ชัน? ถ้าเป็นเช่นนั้นคุณสามารถอธิบายความแตกต่างและการแบ่งส่วนได้หรือไม่? ขอบคุณ!
ทอม

5
@ Tom สำหรับผู้อ่านในอนาคต: โซลูชันนี้ไม่แตกต่างจากคำตอบของ Marcosc อย่างแท้จริงทั้งคู่ใช้eval()(ตัวFunctionสร้างทำสิ่งนั้นภายใน)
kapa

128

โดยพื้นฐานแล้วจะทำในระดับที่ง่ายที่สุด:

"use strict";
var name = "foo";
var func = new Function(
     "return function " + name + "(){ alert('sweet!')}"
)();

//call it, to test it
func();

หากคุณต้องการที่จะจินตนาการมากขึ้นฉันมีบทความเกี่ยวกับ " ชื่อฟังก์ชันไดนามิกใน JavaScript "


ทำได้ดีมาก! ฉันเพิ่งค้นพบสิ่งนี้ด้วยตัวเองและกำลังจะโพสต์ไว้ในคำถามเหล่านี้ แต่คุณเอาชนะฉันไปแล้ว เมื่อเร็ว ๆ นี้ฉันทำงานกับ backbone.js มามากและรู้สึกเบื่อที่จะเห็น 'เด็ก' ทุกที่ในตัวดีบัก Chrome วิธีนี้ช่วยแก้ปัญหานั้นได้ ฉันสงสัยว่ามีผลกระทบด้านประสิทธิภาพเช่นการใช้ eval หรือไม่
webXL

มีผลกระทบด้านความปลอดภัยเช่นกัน ฉันได้รับ "ตัวสร้างฟังก์ชันคือ eval" จาก jsHint ดังนั้นฉันจึงตัดสิ่งนี้ในการตรวจสอบโหมดดีบักเนื่องจากนั่นเป็นเหตุผลเดียวที่จะใช้สิ่งนี้ ฉันเดาว่า "ใช้อย่างเข้มงวด" จะป้องกันไม่ให้มีการโกงกับวัตถุส่วนกลาง แต่ข้อโต้แย้งใด ๆ ของตัวสร้างฟังก์ชันสามารถแก้ไขได้และค่าใดก็ตามที่ตั้งค่าเป็น
webXL

ใช่สิ่งนี้สำหรับสถานการณ์ที่รุนแรงที่คุณต้องสร้างบางสิ่งในทันที
Marcosc

1
ฉันคิดตามตรงว่าstackoverflow.com/a/40918734/2911851เป็นทางออกที่ดีกว่าไม่จำเป็นต้องรวมเนื้อหาของฟังก์ชันเป็นสตริง (เว้นแต่ฉันจะพลาดบางอย่าง แต่ฉันเพิ่งลองและใช้งานได้ดี)
Gian Franco Zabarino

2
AirBnB ขอแนะนำอย่างยิ่งต่อสิ่งนี้เนื่องจากตัวสร้างฟังก์ชันจะใช้evalในการประเมินจาวาสคริปต์ซึ่งจะเป็นการเปิดโค้ดของคุณเพื่อเจาะช่องโหว่
Philippe Hebert

43

คุณสามารถใช้ Object.defineProperty ได้ตามที่ระบุไว้ใน MDN JavaScript Reference [1]:

var myName = "myName";
var f = function () { return true; };
Object.defineProperty(f, 'name', {value: myName, writable: false});
  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name#Description

2
ดูเหมือนว่าสิ่งนี้จะตั้งค่าคุณสมบัติชื่อตามที่ตั้งใจไว้ แต่ถ้าฉันล็อกฟังก์ชันในเบราว์เซอร์ของฉัน (Firefox dev edition ล่าสุด) มันจะพิมพ์ออกมาfunction fn()โดยfnเป็นชื่อดั้งเดิม แปลก.
Kiara Grouwstra

ความคิดเห็นเดียวกันใน Google Chrome Evergreen คุณสมบัติได้รับการตั้งค่าอย่างถูกต้อง แต่ชื่อในคอนโซลเป็นชื่อดั้งเดิมของฟังก์ชัน Cf. 2ality.com/2015/09/… ดูเหมือนว่าชื่อของฟังก์ชันจะถูกกำหนดตอนสร้างและไม่สามารถเปลี่ยนแปลงได้?
user3743222

ในหน้า 2ality.com นั้นให้ดูย่อหน้าถัดไป "การเปลี่ยนชื่อของฟังก์ชัน" [1] ซึ่งอธิบายถึงเทคนิคเดียวกันกับที่พบใน MDN Javascript Reference 1. 2ality.com/2015/09/…
Darren

36

ในเอ็นจิ้นล่าสุดคุณสามารถทำได้

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"


1
หลังจากใช้เวลาหลายชั่วโมงในการพยายามหาวิธีแก้ปัญหาฉันไม่คิดที่จะใช้วัตถุที่มีชื่อคุณสมบัติที่คำนวณได้ สิ่งที่ฉันต้องการ ขอบคุณ!
Levi Roberts

7
แม้ว่าจะได้ผล แต่ฉันได้เริ่มใช้Object.defineProperty(func, 'name', {value: name})ในรหัสของตัวเองเพราะฉันคิดว่ามันอาจจะดูเป็นธรรมชาติและเข้าใจได้มากกว่านี้
kybernetikos

มันทำงานกับรหัสที่เกิดขึ้นได้หรือไม่? (เอาต์พุต Babel หรือ typescript)
Hitmands

3
ตอบคำถามของตัวเอง: {[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/… )
Jason Young

1
ขอบคุณสำหรับการละลายของคุณ! หมายเหตุ: สิ่งนี้ไม่ได้รักษาค่าของ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] }แทนได้!
TS

11

ฉันคิดว่าคำแนะนำส่วนใหญ่ที่นี่เป็นเรื่องที่ไม่เหมาะสมโดยใช้ eval, โซลูชันที่แฮ็กหรือ Wrapper ในขณะที่ชื่อ ES2015 อนุมานจากตำแหน่งทางวากยสัมพันธ์สำหรับตัวแปรและคุณสมบัติ

ดังนั้นสิ่งนี้จะใช้ได้ดี:

const name = 'myFn';
const fn = {[name]: function() {}}[name];
fn.name // 'myFn'

ต่อต้านสิ่งล่อใจในการสร้างเมธอดฟังก์ชันโรงงานที่มีชื่อเนื่องจากคุณจะไม่สามารถส่งผ่านฟังก์ชันจากภายนอกและติดตั้งเพิ่มเข้าไปในตำแหน่งไวยากรณ์เพื่ออนุมานชื่อได้ แล้วก็สายเกินไป หากคุณต้องการจริงๆคุณต้องสร้างกระดาษห่อหุ้ม มีคนทำที่นี่ แต่โซลูชันนั้นใช้ไม่ได้กับชั้นเรียน (ซึ่งเป็นฟังก์ชันด้วย)

คำตอบในเชิงลึกมากขึ้นพร้อมกับตัวแปรทั้งหมดที่ระบุไว้ได้เขียนไว้ที่นี่: https://stackoverflow.com/a/9479081/633921


1
คำตอบนี้ปรับปรุงstackoverflow.com/a/41854075/3966682อย่างไร
d4nyll

1
@ d4nyll ฉันตอบไปแล้วว่ามันสร้าง wrapper ซึ่งแบ่งฟังก์ชัน stateful (ฟังก์ชันที่ใช้ "this") aka class
Albin

@Albin FWIW มันไม่ชัดเจนสำหรับฉันเลยว่าคำตอบของคุณพูดอย่างนั้นได้อย่างไร ไม่ว่าจะด้วยวิธีใดก็เป็นสิ่งที่ควรรู้
Jason Young

@JasonYoung "ต่อต้านสิ่งล่อใจในการสร้างเมธอด function factory ที่มีชื่อเนื่องจากคุณไม่สามารถส่งผ่านฟังก์ชันจากภายนอกและติดตั้งมันเข้าไปในตำแหน่ง syntactic เพื่ออนุมานชื่อของมันได้จากนั้นก็สายเกินไปแล้วถ้าคุณต้องการสิ่งนั้นจริงๆคุณ ต้องสร้าง wrapper มีคนทำที่นี่ แต่โซลูชันนั้นใช้ไม่ได้กับคลาส (ซึ่งเป็นฟังก์ชันด้วย) "
Albin

3

เกี่ยวกับ

this.f = window["instance:" + a] = function(){};

ข้อเสียเปรียบเพียงอย่างเดียวคือฟังก์ชันในวิธี toSource จะไม่ระบุชื่อ โดยปกติจะเป็นเพียงปัญหาสำหรับผู้แก้ปัญหาเท่านั้น


นั่นไม่ดีเพราะเหตุผลเดียวที่ฉันต้องการคือดูชื่อชั้นเรียนให้เร็วขึ้น ทุกคลาสในระบบของฉันเป็นฟังก์ชันที่ไม่ระบุชื่อและในดีบักเกอร์แสดงว่าฉันไม่ระบุชื่อ ..
Totty.js

1
ถ้าอย่างนั้นคุณอาจจะพูดในคำถามนั้นก็ได้
entonio

3

ไวยากรณ์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 ให้มากที่สุด


ความละเอียดนี้ใช้ได้กับชื่อคงที่หรือชื่อคุณสมบัติไดนามิก ES6 เท่านั้น ตัวอย่าง(name => ({[name]:function(){}})[name])('test')ใช้ได้ผล แต่(name => {var x={}; x[name] = function(){}; return x[name];})('test')ไม่ได้ผล
William Leung

3

คำตอบที่ได้รับการโหวตมากที่สุดได้กำหนดเนื้อหาฟังก์ชัน [String] ไว้แล้ว ฉันกำลังมองหาวิธีแก้ปัญหาในการเปลี่ยนชื่อฟังก์ชันที่ประกาศไปแล้วและในที่สุดหลังจากผ่านไปหนึ่งชั่วโมงของการดิ้นรนฉันก็จัดการกับมัน มัน:

  • รับฟังก์ชั่นที่ประกาศ alredy
  • แยกวิเคราะห์เป็น [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){...}


2

วิธีการแบบไดนามิกของออบเจ็กต์อาจสร้างขึ้นโดยใช้ 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>>(){}
Sancarn

2

สำหรับการตั้งชื่อของฟังก์ชันนิรนามที่มีอยู่ :
(อ้างอิงจากคำตอบของ @ 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

การสาธิต

หมายเหตุ : อย่าทำ; /


เมื่อคุณลงคะแนนก็โอเค แต่คุณควรให้เหตุผลอย่างมีมารยาทเพื่อที่เราจะได้เรียนรู้จากคุณ OP ขอชื่อฟังก์ชัน "ไดนามิก" นี่เป็นวิธีหนึ่งที่ทำได้ แต่ฉันไม่เคยแนะนำและไม่เคยทำ
Onur Yıldırım

1

มีสองวิธีในการบรรลุเป้าหมายนี้และมีข้อดีข้อเสีย


name นิยามคุณสมบัติ

การกำหนดname คุณสมบัติที่ไม่เปลี่ยนรูปของฟังก์ชัน

ข้อดี

  • ทุกตัวอักษรสามารถใช้ได้สำหรับชื่อ (เช่น() 全 {}/1/얏호/ :D #GO(@*#%! /*)

จุดด้อย

  • ชื่อวากยสัมพันธ์ (“ นิพจน์”)ของฟังก์ชันอาจไม่สอดคล้องกับnameค่าคุณสมบัติของฟังก์ชัน

การประเมินการแสดงออกของฟังก์ชัน

สร้างนิพจน์ฟังก์ชันที่ตั้งชื่อและประเมินด้วยคอนสตรัคเตอร์Function

ข้อดี

  • ชื่อไวยากรณ์ (“ นิพจน์”)ของฟังก์ชันจะสอดคล้องกับnameค่าคุณสมบัติของฟังก์ชันเสมอ

จุดด้อย

  • ไม่มีช่องว่าง (และอื่น ๆ ) สำหรับชื่อนี้
  • Expression-injectionable (เช่นสำหรับอินพุต(){}/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

1

หากคุณต้องการมีฟังก์ชันไดนามิกเช่น__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

คุณสามารถใช้ 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);

0

ขอบคุณ 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)
}

0

ฟังก์ชั่นยูทิลิตี้นี้รวมฟังก์ชันหลายฟังก์ชันเข้าด้วยกัน (โดยใช้ชื่อที่กำหนดเอง) ข้อกำหนดเพียงอย่างเดียวคือฟังก์ชันที่จัดเตรียมให้ "เรียงใหม่" อย่างถูกต้องเมื่อเริ่มต้นและสิ้นสุดของสกู๊ป

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

0

ผมมีโชคที่ดีขึ้นในการรวมคำตอบที่คาร์เรนและคำตอบของ 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ทำสิ่งเดียวกันทุกประการ

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name

0

ฉันต่อสู้กับปัญหานี้มาก โซลูชัน @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);
          }
        }
      }
    }
  }
}


0

วิธีที่ดีที่สุดคือสร้างวัตถุที่มีรายการฟังก์ชันแบบไดนามิกเช่น:

const USER = 'user';

const userModule = {
  [USER + 'Action'] : function () { ... }, 
  [USER + 'OnClickHandler'] : function () { ... }, 
  [USER + 'OnCreateHook'] : function () { ... }, 
}


-2

ฉันอาจจะพลาดตรงนี้ไป แต่เกิดอะไรขึ้นกับการเพิ่มชื่อ? มีการเรียกใช้ฟังก์ชันโดยไม่คำนึงถึงชื่อ ชื่อใช้เพื่อเหตุผลในการกำหนดขอบเขต หากคุณกำหนดให้กับตัวแปรและอยู่ในขอบเขตก็สามารถเรียกใช้ได้ 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นี้จะทำให้การดีบักยากขึ้น
Albin


-9

new Function('return function name(){}')()นี่คือทางออกที่ดีที่สุดดีกว่าแล้ว

Eval เป็นวิธีแก้ปัญหาที่เร็วที่สุด:

ป้อนคำอธิบายภาพที่นี่

var name = 'FuncName'
var func = eval("(function " + name + "(){})")

ใครที่กำลังอ่านอยู่ให้ทำตามคำตอบนี้
Maxmaxmaximus

1
@majidarif ผู้ชายที่ถูกต้องก็คือเร็วที่สุด: jsperf.com/dynamicfunctionnames/1 แม้ว่าจะไม่ปลอดภัยที่สุด
Sancarn
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.