Programing

자바 스크립트의 동적 함수 이름?

lottogame 2020. 10. 21. 07:37
반응형

자바 스크립트의 동적 함수 이름?


나는 이것을 가지고있다:

this.f = function instance(){};

나는 이것을 갖고 싶다 :

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

최신 정보

다른 사람들이 언급했듯이 이것은 가장 빠르거나 가장 권장되는 솔루션이 아닙니다. 아래 Marcosc의 해결책 은 갈 길입니다.

eval을 사용할 수 있습니다.

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

이것은 기본적으로 가장 간단한 수준에서 수행합니다.

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

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

좀 더 멋지게 만들고 싶다면 " JavaScript의 동적 함수 이름 "에 대한 기사를 작성했습니다 .


MDN JavaScript Reference [1]에 명시된대로 Object.defineProperty를 사용할 수 있습니다.

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

최근 엔진에서는 다음을 수행 할 수 있습니다.

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"


여기에서 대부분의 제안은 eval, hacky 솔루션 또는 래퍼를 사용하여 차선책이라고 생각합니다. ES2015에서 이름은 변수 및 속성의 구문 위치에서 유추됩니다.

따라서 이것은 잘 작동합니다.

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

이름을 추론하기 위해 외부에서 함수를 전달하고 구문 위치로 개조 할 수 없기 때문에 명명 된 함수 팩토리 메서드를 만들려는 유혹에 저항하십시오. 그럼 벌써 너무 늦었어요. 정말로 필요하다면 래퍼를 만들어야합니다. 누군가 여기서 그렇게했지만 그 솔루션은 클래스 (함수이기도 함)에서는 작동하지 않습니다.

설명 된 모든 변형에 대한 훨씬 더 자세한 답변이 여기에 작성되었습니다 : https://stackoverflow.com/a/9479081/633921


구문 은 이름으로 인덱싱 된 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 () {
}

속성 함수가 fan anonymous 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() {})})
  • 임베디드 :는 자바 스크립트를 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 예제의 의미와 구문으로 글로벌 컴퓨팅 환경을 최대한 유지합니다.


가장 많이 득표 한 답변은 이미 정의 된 [String] 함수 본문입니다. 이미 선언 된 함수 이름의 이름을 바꾸는 솔루션을 찾고 있었고 마침내 한 시간 동안 고생 한 후 처리했습니다. 그것:

  • alredy 선언 된 함수를받습니다.
  • .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){...}


이건 어떤가요

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

유일한 단점은 toSource 메서드의 함수가 이름을 나타내지 않는다는 것입니다. 이는 일반적으로 디버거의 문제 일뿐입니다.


객체의 동적 메서드는 ECMAScript 2015 (ES6)에서 제공하는 Object Literal Extensions를 사용하여 만들 수 있습니다.

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]
}

기존 익명 함수 의 이름을 설정하려면 :
(@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

데모 .

참고 :하지 마십시오; /


__callPHP의 함수와 같은 동적 함수를 원한다면 프록시를 사용할 수 있습니다.

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
})()

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

이를 달성하는 데는 두 가지 방법이 있으며 장단점이 있습니다.


name 속성 정의

함수의 불변 name 속성 정의 .

장점

  • 이름에 모든 문자를 사용할 수 있습니다. (예. () 全 {}/1/얏호/ :D #GO(@*#%! /*)

단점

  • 함수의 구문 ( "표현식") 이름 이 해당 name속성 값 과 일치하지 않을 수 있습니다 .

함수 표현 평가

메이킹 라는 이름의 기능 발현평가 와 함께 Function생성자.

장점

  • 함수의 구문 ( "표현식") 이름은 항상 해당 name속성 값 과 일치 합니다.

단점

  • 이름에 공백 (등)을 사용할 수 없습니다.
  • 식 주입 가능 (예 : input (){}/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

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

참고 : Function.name 1에 대한 표준 ES2015 사양과 일치하도록 configurable설정됩니다.true

특히 유사 웹팩에 오류 하는것에 도움 이 하나 .

업데이트 : 나는 이것을 npm 패키지로 게시하려고 생각했지만 sindresorhus의이 패키지 는 똑같은 일을합니다.

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

I struggled a lot with this issue. @Albin solution worked like a charm while developing, but it did not work when I changed it to production. After some debugging I realized how to achieve what I needed. I'm using ES6 with CRA (create-react-app), which means it's bundled by Webpack.

Lets say you have a file that exports the functions you need:

myFunctions.js

export function setItem(params) {
  // ...
}

export function setUser(params) {
  // ...
}

export function setPost(params) {
  // ...
}

export function setReply(params) {
  // ...
}

And you need to dynamically call these functions elsewhere:

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();

You was near:

this["instance_" + a] = function () {...};

{...};


I might be missing the obvious here, but what's wrong with just adding the name? functions are invoked regardless of their name. names are just used for scoping reasons. if you assign it to a variable, and it's in scope, it can be called. hat happens is your are executing a variable which happens to be a function. if you must have a name for identification reasons when debugging, insert it between the keyword function and the opening brace.

var namedFunction = function namedFunction (a,b) {return a+b};

alert(namedFunction(1,2));
alert(namedFunction.name);
alert(namedFunction.toString());

an alternative approach is to wrap the function in an outer renamed shim, which you can also pass into an outer wrapper, if you don't want to dirty the surrounding namespace. if you are wanting to actually dynamically create the function from strings (which most of these examples do), it's trivial to rename the source to do what you want. if however you want to rename existing functions without affecting their functionality when called elsewhere, a shim is the only way to achieve it.

(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};


This is BEST solution, better then new Function('return function name(){}')().

Eval is fastest solution:

enter image description here

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

참고URL : https://stackoverflow.com/questions/5905492/dynamic-function-name-in-javascript

반응형