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


87

나는 이것을 가지고있다:

this.f = function instance(){};

나는 이것을 갖고 싶다 :

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

10
당신은 할 수 없습니다. 하지만 당신은 가질 수 있습니다this["instance"] = function() { }
Raynos


Raynos가 말한 내용을 명확히하기 위해 this["instance" + a] = function() { }. 그것은 나에게 명확하지 않았습니다.
Andrew

답변:


7

최신 정보

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

eval을 사용할 수 있습니다.

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

1
그것이 내가 요청한 것입니다, 감사합니다! (어쨌든 나는 너무 느리기 때문에이 기능을 사용하지 않을 것입니다)
Totty.js

3
나는 이것이 OP가 요구 한 것이라는 것을 알고 있지만 이것은 끔찍한 아이디어입니다. 할 수 있다고해서 이렇게해야한다는 뜻은 아닙니다. 기능면에서 거의 똑같은 훨씬 더 나은 대안이 있습니다.
Thomas Eding

4
@ sg3s : 다른 솔루션을 제안 할 수 있습니까?

2
@ sg3s : 제 의견에 답 해주셔서 감사합니다! 제가 의미하는 바와 실제로 묻고 싶은 것이 무엇인지 설명하겠습니다. Marcosc의 솔루션이 eval과 정말 크게 다른가요? 무언가를 평가하거나 Function 생성자에 공급하면 실제로 차이가 있습니까? 그렇다면 차이점과 그 결과를 설명해 주시겠습니까? 감사!
Tom

5
@Tom 미래의 독자를 위해 :이 솔루션은 Marcosc의 답변과 실제로 다르지 않으며 둘 다 사용합니다 eval()( Function생성자가 내부에서 수행합니다).
kapa 2015 년

126

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

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

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

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


잘 하셨어요! 나는 방금 이것을 스스로 발견하고이 질문 중 하나에 게시하려고했지만 당신이 나를 이겼습니다. 최근에 backbone.js로 많은 작업을 해왔고 크롬 디버거의 모든 곳에서 '아이'를 보는 것에 지쳤습니다. 이것은 그 문제를 해결합니다. eval 사용과 같은 성능 영향이 있는지 궁금합니다.
webXL

보안과도 관련이 있습니다. jsHint에서 "The Function constructor is eval"을 얻었으므로, 이것이 이것을 사용하는 유일한 이유이기 때문에 디버그 모드 검사에서 이것을 래핑하고 있습니다. 나는 "use strict"가 전역 객체와의 무의미한 짓을 막을 것이라고 생각한다. 그러나 Function 생성자에 대한 어떠한 인자도 수정할 수 있고 'this'가 무엇으로 설정되어 있든 상관 없다.
webXL

예, 즉석에서 무언가를 만들어야하는 극한 상황에 적합합니다.
Marcosc

1
솔직히 stackoverflow.com/a/40918734/2911851 이 더 나은 솔루션 이라고 생각 합니다. 함수 본문을 문자열로 포함 할 필요가 없습니다.
Gian Franco Zabarino

2
AirBnB 는 Function 생성자가 eval자바 스크립트를 평가하는 데 사용할 것이기 때문에 이것대해 강력히 권고 합니다.
필립 헤 버트

42

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

2
의도 한대로 그것은이 세트를 이름 속성을 표시, 아직 내 브라우저의 기능 (최신 파이어 폭스 dev에 버전) 로그인하는 경우는 인쇄 function fn(), fn원래 이름 인. 기묘한.
Kiara Grouwstra

Google 크롬 에버그린에 대한 동일한 의견. 속성이 올바르게 설정되었지만 콘솔의 이름은 함수의 원래 이름입니다. Cf. 2ality.com/2015/09/… 기능의 이름은 생성시 할당되어 변경할 수없는 것 같습니다.
user3743222

2ality.com 페이지에서 MDN Javascript Reference에있는 동일한 기술을 설명하는 다음 단락 "Changing the name of functions"[1]을 참조하십시오. 1. 2ality.com/2015/09/…
Darren

35

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

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 2017 년

3
내 자신의 질문에 답하기 : {[expr]: val}is an object initializer (as is as a JSON object) where expris some expression; 평가되는 것이 무엇이든 핵심입니다. {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, hacky 솔루션 또는 래퍼를 사용하여 차선책이라고 생각합니다. 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 이미 대답했습니다. 상태 저장 함수 ( "this"를 사용하는 함수) 일명 클래스를 깨는 래퍼를 만듭니다.
Albin 2018 년

@Albin FWIW, 귀하의 답변이 어떻게 말하는지 전혀 명확하지 않습니다. 어느 쪽이든 알아두면 좋습니다.
Jason Young

@JasonYoung "함수를 외부에서 전달하고 그 이름을 추론하기 위해 구문 위치로 개조 할 수 없기 때문에 명명 된 함수 팩토리 메서드를 만들려는 유혹에 저항하십시오. 그런 다음 이미 너무 늦었습니다. 정말로 필요한 경우에는 래퍼를 만들어야합니다. 누군가 여기서 그렇게했지만 그 솔루션은 클래스 (함수이기도 함)에 대해 작동하지 않습니다. "
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 () {
}

속성 함수가 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 예제의 의미와 구문으로 글로벌 컴퓨팅 환경을 최대한 유지합니다.


이 해결 방법은 정적 이름 또는 ES6 동적 속성 이름에 대해서만 작동합니다. 예를 들어 (name => ({[name]:function(){}})[name])('test')작동하지만 (name => {var x={}; x[name] = function(){}; return x[name];})('test')하지 않습니다
윌리엄 렁

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

객체의 동적 메서드는 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]
}

:이 더 가깝다 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속성 값 과 일치 합니다.

단점

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

1

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

1

이와 같은 동적 함수 이름 및 매개 변수를 사용할 수 있습니다.

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

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

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

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

여기에 명백한 내용이 없을 수도 있지만 이름을 추가하는 것이 잘못된 것은 무엇입니까? 함수는 이름에 관계없이 호출됩니다. 이름은 범위 지정 목적으로 만 사용됩니다. 변수에 할당하고 범위 내에 있으면 호출 할 수 있습니다. 모자 발생은 함수로 발생하는 변수를 실행하는 것입니다. 디버깅 할 때 식별을 위해 이름이 있어야하는 경우 키워드 함수와 여는 중괄호 사이에 삽입합니다.

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

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

또 다른 방법은 이름이 변경된 외부 shim에 함수를 래핑하는 것입니다. 주변 네임 스페이스를 더럽 히지 않으려는 경우 외부 래퍼로 전달할 수도 있습니다. 실제로 문자열에서 함수를 동적으로 생성하고 싶다면 (대부분의 예제가 수행하는) 소스 이름을 변경하여 원하는 작업을 수행하는 것은 간단합니다. 그러나 다른 곳에서 호출 될 때 기능에 영향을주지 않고 기존 함수의 이름을 바꾸려면 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

-3

근처에있었습니다.

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

{...};


-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.