ES6 클래스 인스턴스의 클래스 이름을 가져옵니다.


157

ES6 클래스 인스턴스에서 클래스 이름을 얻는 '조화로운'방법이 있습니까? 이것 말고도

someClassInstance.constructor.name

현재 나는 Traceur 구현에 의존하고 있습니다. 그리고 Function.name트레이서 (Traceur)는 그렇지 않은 동안 바벨 (Babel)은 폴리 필을 가지고있는 것 같습니다 .

요약하면 ES6 / ES2015 / Harmony에는 다른 방법이 없었으며 ES에서는 ATM이 예상되지 않습니다.

서버 측 응용 프로그램에는 유용한 패턴을 제공 할 수 있지만 브라우저 / 데스크톱 / 모바일 용 응용 프로그램에서는 필요하지 않습니다.

Babel core-js polyfill에 사용하므로Function.name Traceur 및 TypeScript 응용 프로그램에 적합하게 수동으로로드해야합니다.


2
나는 같은 문제를 겪었다. Traceur의 유일한 해결책은 실제 클래스 코드 자체를 구문 분석하여 이름을 추출하는 것이 었습니다. 나는 막약을 삼켜 바벨로 바꿨다. Traceur의 개발은 다소 정체 된 것으로 보이며 많은 ES6 기능이 제대로 구현되지 않았습니다. 당신이 언급 한 것처럼 instance.constructor.nameclass.name적절한 ES6에서 클래스 이름을 반환합니다.
Andrew Odri

유일한 방법 인 것 같습니다.
Frederik Krautwald

이것이 ES6 표준입니까?
drudru

12
그 언급이의 가치는 someClassInstance.constructor.name당신이 당신의 코드를 추하게 경우 엉망 얻을 것이다.
JamesB

stackoverflow.com/questions/2648293/… 이것을보고 싶을 수도 .constructor있습니다.
Florrie

답변:


206

someClassInstance.constructor.name이 작업을 수행하는 올바른 방법입니다. 트랜스 파일러는이를 지원하지 않을 수 있지만 사양에 따라 표준 방식입니다. ( nameClassDeclaration 프로덕션을 통해 선언 된 함수 의 특성은 6 단계 14.5.15 에서 설정됩니다 .)


2
그것이 내가 두려워했던 것입니다. 당신은 그것에 대한 합리적인 polyfill을 알고 있습니까? 나는 바벨이 어떻게하는지 알아 내려고 노력했지만 거의 성공하지 못했습니다.
Estus Flask

언어 기능 (클래스)에 대한 polyfill이 무엇을 의미하는지 잘 모르겠습니다.
Domenic

나는 constructor.name에 대한 polyfill을 의미합니다. 바벨이 구현 한 것처럼 보이지만 어떻게 그렇게하는지 이해하지 못했습니다.
Estus Flask 2016 년

2
@estus someClassInstance.constructor는 함수입니다. 모든 함수에는 name이름으로 설정된 속성이 있습니다. 그것이 babel이 아무것도 할 필요가없는 이유입니다. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…를
Esteban

2
@Esteban Babel은 Core-js 폴리 필 (Function.name의 폴리 필 포함)을 지속적으로 홍보하는 것으로 보이며, 따라서 일부 Babel 빌드는 모든 브라우저에서 기본적으로 작동 할 수 있습니다.
Estus Flask

52

@Domenic이 말했듯이을 사용하십시오 someClassInstance.constructor.name. @Esteban은 주석에서 언급합니다.

someClassInstance.constructor함수입니다. 모든 함수에는 name속성이 있습니다 ...

따라서 클래스 이름을 정적으로 액세스하려면 다음을 수행하십시오 (이것은 내 Babel 버전 BTW에서 작동합니다. @Domenic에 대한 의견에 따르면 마일리지가 다를 수 있습니다).

class SomeClass {
  constructor() {}
}

var someClassInstance = new SomeClass();
someClassInstance.constructor.name;      // === 'SomeClass'
SomeClass.name                           // === 'SomeClass'

최신 정보

바벨은 괜찮 았지만, 어설픈 / 최소화로 인해 문제가 발생했습니다. 게임을 만들고 있으며 풀링 된 Sprite 리소스의 해시 (키가 함수 이름 임)를 만들고 있습니다. 축소 후 모든 함수 / 클래스의 이름이로 지정되었습니다 t. 해시가 종료됩니다. 나는 Gulp이 프로젝트에서 사용하고 있으며 gulp-uglify 문서를 읽은 후이 로컬 변수 / 함수 이름이 엉망이되는 것을 막는 매개 변수가 있음을 발견했습니다. 그래서 내 gulpfile에서 변경했습니다

.pipe($.uglify()).pipe($.uglify({ mangle: false }))

여기에는 성능과 가독성의 균형이 있습니다. 이름을 조작하지 않으면 (약간) 더 큰 빌드 파일 (더 많은 네트워크 리소스)과 잠재적으로 코드 실행 속도가 느려질 수 있습니다 (인용 필요-BS 일 수 있음). 반면에 동일하게 유지하면 getClassName모든 ES6 클래스에서 정적 및 인스턴스 수준 으로 수동으로 정의해야 합니다. 고맙지 만 사양 할게!

최신 정보

의견에 대한 토론 후에는 .name그러한 기능을 정의하는 데 유리한 관례를 피하는 것이 좋은 패러다임입니다. 몇 줄의 코드 만 필요하며 라이브러리에서 사용하는 경우 코드의 전체 축소 및 일반성을 허용합니다. 그래서 나는 내 마음을 바꾸고 getClassName수업에 수동으로 정의 할 것 같아요 . 감사합니다 @estus! . Getter / Setter는 일반적으로 특히 클라이언트 기반 응용 프로그램에서 직접 가변 액세스에 비해 좋은 아이디어입니다.

class SomeClass {
  constructor() {}
  static getClassName(){ return 'SomeClass'; }
  getClassName(){ return SomeClass.getClassName(); }
}
var someClassInstance = new SomeClass();
someClassInstance.constructor.getClassName();      // === 'SomeClass' (static fn)
someClassInstance.getClassName();                  // === 'SomeClass' (instance fn)
SomeClass.getClassName()                           // === 'SomeClass' (static fn)

3
맹 글링이 최소화에 크게 기여하기 때문에 맹 글링을 완전히 비활성화하는 것은 좋은 생각이 아닙니다. 우선 클라이언트 측 코드에서 주제를 사용하는 것은 좋지 않지만 reservedUglify 옵션으로 클래스를 관리 할 수는 없습니다 (클래스 목록은 정규 표현식 또는 기타로 얻을 수 있음).
Estus Flask

매우 사실입니다. 파일 크기가 더 크다는 단점이 있습니다. 이 방법은 RegEx를 사용하여 선택한 항목에 대해서만 조작을 방지하는 방법 입니다. "클라이언트 측 코드에서 주제를 사용하는 것이 좋지 않다"는 것은 무엇을 의미합니까? 일부 시나리오에서 보안 위험이 발생합니까?
James L.

1
아니요, 이미 말한 것입니다. 클라이언트 쪽 JS가 축소되는 것은 정상적인 일이므로이 패턴으로 인해 앱에 문제가 발생하는 것으로 이미 알려져 있습니다. 깔끔한 name패턴 대신 클래스 문자열 식별자에 대한 한 줄의 코드 만 있으면 윈윈 일 수 있습니다. 같은 것이 노드에도 적용될 수 있지만, 더 적은 범위 (예 : 난독 화 된 Electron 앱)입니다. 일반적으로 name서버 코드에는 의존 하지만 브라우저 코드에는 의존 하지 않으며 공통 라이브러리에는 의존 하지 않습니다.
Estus Flask

그렇기 때문에 2 개의 getClassName 함수 (정적 및 인스턴스)를 수동으로 정의하여 지옥을 극복하고 성가신 RegEx없이 전체 축소를 허용하는 것이 좋습니다. 도서관에 대한 그 점은 많은 의미가 있습니다. 많은 의미가 있습니다. 저에게있어, 내 프로젝트는 자체 제작 한 작은 Cordova 앱이므로 실제로 문제가되지는 않습니다. 그 이상으로도 이러한 문제가 발생하는 것을 볼 수 있습니다. 토론 주셔서 감사합니다! 게시물의 개선 사항을 생각할 수 있으면 언제든지 수정하십시오.
James L.

1
예, 처음에는 name클래스 이름에서 클래스 (서비스, 플러그인 등)를 사용하는 엔티티의 이름을 추출 하기 위해 DRYer 코드에 사용되었지만 결국 정적 소품 ( id, _name) 으로 명시 적으로 중복되는 것을 발견했습니다 가장 확실한 접근 방식입니다. 좋은 대안은 클래스 이름을 신경 쓰지 않고 클래스 자체 (함수 객체)를이 클래스에 매핑 된 엔티티와 import필요한 곳 ​​(앵귤러 2 DI에서 사용 된 접근 방식 )의 식별자 로 사용하는 것입니다.
Estus Flask

8

클래스에서 직접 클래스 이름 가져 오기

이전 답변 someClassInstance.constructor.name에서는 잘 작동하지만 프로그래밍 방식으로 클래스 이름을 문자열로 변환해야하고 인스턴스를 만들고 싶지 않은 경우 다음을 기억하십시오.

typeof YourClass === "function"

그리고 모든 함수에는 name속성 이 있으므로 클래스 이름으로 문자열을 얻는 또 다른 좋은 방법은 다음과 같습니다.

YourClass.name

다음은 이것이 왜 유용한 지에 대한 좋은 예입니다.

웹 구성 요소로드

MDN 설명서에서 알 수 있듯이 웹 구성 요소를로드하는 방법은 다음과 같습니다.

customElements.define("your-component", YourComponent);

YourComponent에서 확장되는 클래스는 어디 입니까 HTMLElement? 컴포넌트 태그 자체 다음에 컴포넌트 클래스 이름을 지정하는 것이 좋은 방법으로 간주되므로 모든 컴포넌트가 자신을 등록하는 데 사용할 수있는 도우미 함수를 작성하는 것이 좋습니다. 그 기능은 다음과 같습니다.

function registerComponent(componentClass) {
    const componentName = upperCamelCaseToSnakeCase(componentClass.name);
    customElements.define(componentName, componentClass);
}

따라서 필요한 것은 다음과 같습니다.

registerComponent(YourComponent);

구성 요소 태그를 직접 작성하는 것보다 오류가 덜 발생하기 때문에 좋습니다. 요약하면 다음과 같은 upperCamelCaseToSnakeCase()기능입니다.

// converts `YourString` into `your-string`
function upperCamelCaseToSnakeCase(value) {
    return value
        // first char to lower case
        .replace(/^([A-Z])/, $1 => $1.toLowerCase())
        // following upper chars get preceded with a dash
        .replace(/([A-Z])/g, $1 => "-" + $1.toLowerCase());
}

감사. 예는 클라이언트 측입니다. 이미 언급했듯이 브라우저에서 함수 이름을 사용하는 데 몇 가지 문제가 있습니다. 거의 모든 브라우저 코드가 축소 될 것으로 예상되지만 함수 이름에 의존하는 코드가 손상됩니다.
Estus Flask

네, 당신 말이 맞아요 축소 기는이 접근 방식이 작동하려면 클래스 이름을 건드리지 않도록 구성해야합니다.
Lucio Paiva

1

바벨 트랜스 필 레이션 (최소화 전)

와 함께 Babel을 사용하는 경우 @babel/preset-env클래스 정의를 함수로 변환하지 않고 클래스 정의를 유지할 수 있습니다 ( constructor속성 제거 ).

이 구성에 대한 오래된 브라우저 호환성을 다음에서 제거 할 수 있습니다 babel.config / babelrc.

{
  "presets": [
    ["@babel/preset-env", {"targets": {"browsers": ["> 2%"]}}]
  ]
}

다음에 대한 추가 정보 targets: https://babeljs.io/docs/en/babel-preset-env#targets

바벨 축소 (트랜스 필 레이션 후)

지금은 쉬운 해결책이없는 것 같습니다 ... 우리는 배제를 다루어야합니다.


이것이 어떻게 축소에 도움이되는지 더 설명 할 수 있습니까? 대상 class Foo {}과 같은 것으로 축소됩니다 class a{}. Foo축소 된 소스 코드 에는 단어 가 없습니다 .
Estus Flask

솔직히 나는 문서 와이 구성을 사용하는 데 도움이되었다는 사실 이상을 파헤 치지 않았다 ... ECSY를 바벨 번역 프로젝트에 사용하고 있으며 유효한 클래스 이름을 얻으려면이 매개 변수가 필요합니다 : github.com/MozillaReality/ecsy/issues/ 119
Ifnot

내가 참조. 이것은 당신이 다루는 코드에 매우 구체적입니다. 예를 들어 export class Foo{}더 효율적으로 추론 할 수 없기 때문에 ES 모듈 및 ES6에 대해 이름이 보존 될 수 있지만 다른 곳에서는 다를 수 있습니다. 빌드시 특정 코드 조각으로 어떤 일이 발생하는지 잘 알지 못하면 정확히 알 수 없습니다. 어쨌든 이것은 2015 년 이후로 바뀌지 않았습니다. 일부 컴파일 구성 및 코드에서 항상 가능했습니다. 그리고이 가능성은 여전히 ​​앱 로직에 클래스 이름을 사용하기에는 너무 취약하다고 말합니다. 소스 코드를 실수로 변경 한 후 클래스 이름이 잘못 될 수 있습니다.
Estus Flask

1
좋아, 나는 코드를 보면서 괴롭힘을 발견했다. 내 솔루션은 클래스의 변환을 함수로 수정합니다. 따라서 축소하기 전에 도움이됩니다. 그러나 축소 문제는 아닙니다. 내가 사용하는 모든 내 코드를 어떻게 이해할 수 없었다 때문에 파고 계속해야 constructor.name/ : 여전히이 축소 된 버전 ... 비논리적 인 작동
Ifnot
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.