TypeScript 3.8 이상에서 private
키워드를 사용하여 멤버를 비공개로 표시하는 것의 차이점은 무엇입니까?
class PrivateKeywordClass {
private value = 1;
}
그리고 JavaScript를 위해 제안 된#
개인 필드를 사용합니다 :
class PrivateFieldClass {
#value = 1;
}
다른 것을 선호해야합니까?
답변
비공개 키워드
TypeScript 의 개인 키워드 는 컴파일 시간 주석입니다. 컴파일러에게 속성은 해당 클래스 내에서만 액세스 할 수 있어야한다고 알려줍니다.
class PrivateKeywordClass {
private value = 1;
}
const obj = new PrivateKeywordClass();
obj.value // compiler error: Property 'value' is private and only accessible within class 'PrivateKeywordClass'.
그러나 컴파일 시간 검사는 예를 들어 유형 정보를 캐스트하여 쉽게 무시할 수 있습니다.
const obj = new PrivateKeywordClass();
(obj as any).value // no compile error
private
키워드는 런타임에 적용되지 않습니다
방출 된 JavaScript
TypeScript를 JavaScript로 컴파일 할 때 private
키워드는 간단히 제거됩니다.
class PrivateKeywordClass {
private value = 1;
}
된다 :
class PrivateKeywordClass {
constructor() {
this.value = 1;
}
}
이를 통해 private
키워드가 런타임 보호 기능을 제공하지 않는 이유를 확인할 수 있습니다 . 생성 된 JavaScript에서는 일반 JavaScript 특성 일뿐입니다.
개인 분야
개인 필드 는 속성이 런타임에 개인용으로 유지되도록 합니다 .
class PrivateFieldClass {
#value = 1;
getValue() { return this.#value; }
}
const obj = new PrivateFieldClass();
// You can't access '#value' outside of class like this
obj.value === undefined // This is not the field you are looking for.
obj.getValue() === 1 // But the class itself can access the private field!
// Meanwhile, using a private field outside a class is a runtime syntax error:
obj.#value
// While trying to access the private fields of another class is
// a runtime type error:
class Other {
#value;
getValue(obj) {
return obj.#value // TypeError: Read of private field #value from an object which did not contain the field
}
}
new Other().getValue(new PrivateKeywordClass());
클래스 외부의 개인 필드를 사용하려고하면 TypeScript에서 컴파일 시간 오류를 출력합니다.
비공개 필드는 JavaScript 제안서 에서 제공되며 일반 JavaScript에서도 작동합니다.
방출 된 JavaScript
당신이 타이프에서 개인 필드를 사용하고 같은 당신의 출력을위한 자바 스크립트의 이전 버전을 대상으로하는 경우 es6
또는 es2018
, 타이프 라이터는 민간 분야의 런타임 동작을 에뮬레이트 코드를 생성하려고합니다
class PrivateFieldClass {
constructor() {
_x.set(this, 1);
}
}
_x = new WeakMap();
를 타겟팅하는 esnext
경우 TypeScript는 개인 필드를 생성합니다.
class PrivateFieldClass {
constructor() {
this.#x = 1;
}
#x;
}
어느 것을 사용해야합니까?
그것은 당신이 달성하려는 것에 달려 있습니다.
private
키워드는 미세 기본이다. TypeScript 개발자가 수년 동안 달성하도록 설계되었으며 성공적으로 사용되었습니다. 기존 코드베이스가있는 경우 개인 필드를 사용하기 위해 모든 코드를 전환 할 필요는 없습니다. esnext
TS가 개인 필드에 대해 방출하는 JS가 성능에 영향을 줄 수 있으므로 타겟팅하지 않는 경우 특히 그렇습니다 . 또한 비공개 입력란에는 private
키워드 와 다른 미묘하지만 중요한 차이점이 있습니다.
그러나 런타임 개인 정보를 적용해야하거나 esnext
JavaScript 를 출력하는 경우 개인 필드를 사용해야합니다.
또한 JavaScript / TypeScript 에코 시스템 내에서 개인 필드가 더 널리 보급됨에 따라 하나 또는 다른 것을 사용하는 조직 / 커뮤니티 규칙도 발전 할 것입니다.
노트의 다른 차이점
-
개인 필드는
Object.getOwnPropertyNames
비슷한 방법으로 반환되지 않습니다 -
개인 필드는
JSON.stringify
-
상속과 관련하여 중요한 경우가 있습니다.
예를 들어 TypeScript는 수퍼 클래스의 개인 속성과 이름이 같은 서브 클래스에서 개인 속성을 선언하는 것을 금지합니다.
class Base { private value = 1; } class Sub extends Base { private value = 2; // Compile error: }
개인 필드에는 해당되지 않습니다.
class Base { #value = 1; } class Sub extends Base { #value = 2; // Not an error }
-
private
이니셜 라이저가없는 키워드 사유 재산이 방출되는 자바 스크립트의 속성 선언을 생성하지 않습니다 :class PrivateKeywordClass { private value?: string; getValue() { return this.value; } }
컴파일 :
class PrivateKeywordClass { getValue() { return this.value; } }
개인 필드는 항상 속성 선언을 생성하는 반면 :
class PrivateKeywordClass { #value?: string; getValue() { return this.#value; } }
(타겟팅시
esnext
)로 컴파일 :class PrivateKeywordClass { #value; getValue() { return this.#value; } }
더 읽을 거리 :
답변
사용 사례 : #
-비공개 필드
머리말:
- TC39 제안 클래스 필드
- 동의어 용어 :
#
-개인, 강제 개인, 런타임 개인
컴파일 타임 및 런타임 개인 정보
#
-private 필드는 “해킹 가능하지 않은” 컴파일 타임 및 런타임 개인 정보를 제공합니다. 그것은 어떤 방식 으로든 클래스 본문 외부에서 멤버에 액세스하는 것을 방지하는 메커니즘 입니다.
class A {
#a: number;
constructor(a: number) {
this.#a = a;
}
}
let foo: A = new A(42);
foo.#a; // error, not allowed outside class bodies
(foo as any).#bar; // still nope.
안전한 클래스 상속
#
개인 필드는 고유 한 범위를 갖습니다. 클래스 계층은 이름이 같은 개인 속성을 실수로 덮어 쓰지 않고도 구현할 수 있습니다.
class A {
#a = "a";
fnA() { return this.#a; }
}
class B extends A {
#a = "b";
fnB() { return this.#a; }
}
const b = new B();
b.fnA(); // returns "a" ; unique property #a in A is still retained
b.fnB(); // returns "b"
private
속성이 덮어 쓰기 될 위험이있는 경우 TS 컴파일러에서 다행히 오류가 발생합니다 ( 이 예 참조 ). 그러나 컴파일 타임 기능의 특성으로 인해 컴파일 오류가 무시되고 및 / 또는 생성 된 JS 코드가 사용되는 경우 런타임에 모든 것이 여전히 가능합니다.
외부 라이브러리
라이브러리 작성자는 #
클라이언트에 큰 변화를주지 않으면 서 개인 식별자를 리팩터링 할 수 있습니다. 다른 쪽의 라이브러리 사용자는 내부 필드에 액세스하지 못하도록 보호됩니다.
JS API가 개인 #
필드를 생략 함
내장 JS 함수 및 메소드는 개인 #
필드를 무시 합니다. 이로 인해 런타임시보다 예측 가능한 속성을 선택할 수 있습니다. 예 : Object.keys
, Object.entries
, JSON.stringify
, for..in
루프 등 ( 코드 샘플 , 또한 매트 Bierner의 참조 대답을 ) :
class Foo {
#bar = 42;
baz = "huhu";
}
Object.keys(new Foo()); // [ "baz" ]
사용 사례 : private
키워드
머리말:
private
TS 문서의 키워드- 동의어 용어 : TS 개인, 소프트 개인, 컴파일 타임 개인
내부 클래스 API 및 상태에 대한 액세스 (컴파일 타임 전용 프라이버시)
private
클래스의 멤버는 런타임에 일반적인 속성입니다. 이 유연성을 사용하여 클래스 내부 API 또는 외부에서 상태에 액세스 할 수 있습니다. 컴파일러 검사를 만족시키기 위해 형식 어설 션, 동적 속성 액세스 등의 메커니즘을 @ts-ignore
사용할 수 있습니다.
형식 어설 션 ( as
/ <>
) 및 any
형식화 된 변수 할당의 예 :
class A {
constructor(private a: number) { }
}
const a = new A(10);
a.a; // TS compile error
(a as any).a; // works
const casted: any = a; casted.a // works
TS private
는 이스케이프 해치 가있는 멤버 의 동적 속성 액세스를 허용 합니다 .
class C {
private foo = 10;
}
const res = new C()["foo"]; // 10, res has type number
개인 액세스는 어디에서 의미가 있습니까? (1) 단위 테스트, (2) 디버깅 / 로깅 상황 또는 (3) 프로젝트 내부 클래스가있는 기타 고급 사례 시나리오 (오픈 엔드 목록).
내부 변수에 접근하는 것은 약간 모순적입니다. 그렇지 않으면 private
처음 에는 만들지 않았을 것 입니다. 예를 들어, 단위 테스트는 개인 필드가 구현 세부 사항으로 숨겨져있는 검은 색 / 회색 상자 여야합니다. 그러나 실제로는 경우에 따라 유효한 접근 방식이있을 수 있습니다.
모든 ES 환경에서 사용 가능
TS private
수정자는 모든 ES 대상과 함께 사용할 수 있습니다. #
-비공개 필드는 target
ES2015
/ ES6
이상 에서만 사용할 수 있습니다 . ES6 +에서는 WeakMap
내부적으로 하위 구현으로 사용됩니다 ( 여기 참조 ). 기본 개인 #
필드에는 현재 필요합니다 target
esnext
.
일관성과 호환성
팀은 코딩 지침과 린터 규칙을 사용 private
하여 유일한 액세스 수정 자로 사용하도록 할 수 있습니다. 이 제한은 일관성을 유지하는 데 도움이되고 #
이전 버전과 호환되는 방식으로 -private 필드 표기법 과 혼동되지 않습니다.
필요한 경우 매개 변수 속성 (생성자 할당 속기)이 쇼 스토퍼입니다. private
키워드 에만 사용할 수 있으며 아직 개인 필드 에 구현할 계획 이 없습니다#
.
다른 이유들
private
일부 하위 수준의 경우 더 나은 런타임 성능을 제공 할 수 있습니다 ( 여기 참조 ).- 현재까지 TS에는 사용 가능한 하드 프라이빗 클래스 메소드가 없습니다.
- 어떤 사람들은
private
키워드 표기법을 더 좋아합니다 😊.
둘 다 참고
두 가지 방법 모두 컴파일 타임에 일종의 명목 또는 브랜드 유형을 만듭니다.
class A1 { private a = 0; }
class A2 { private a = 42; }
const a: A1 = new A2();
// error: "separate declarations of a private property 'a'"
// same with hard private fields
또한 두 인스턴스 모두 인스턴스 간 액세스를 허용합니다. 클래스 인스턴스 A
는 다른 A
인스턴스의 개인 멤버에 액세스 할 수 있습니다 .
class A {
private a = 0;
method(arg: A) {
console.log(arg.a); // works
}
}
출처