TypeScript 3.8 이상에서 private
키워드를 사용하여 멤버를 비공개로 표시하는 것의 차이점은 무엇입니까?
class PrivateKeywordClass {
private value = 1;
}
그리고 JavaScript를 위해 제안 된#
개인 필드를 사용합니다 :
class PrivateFieldClass {
#value = 1;
}
다른 것을 선호해야합니까?
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
키워드는 런타임에 적용되지 않습니다
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에서도 작동합니다.
당신이 타이프에서 개인 필드를 사용하고 같은 당신의 출력을위한 자바 스크립트의 이전 버전을 대상으로하는 경우 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; }
}
#
-비공개 필드머리말:
#
-개인, 강제 개인, 런타임 개인#
-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 함수 및 메소드는 개인 #
필드를 무시 합니다. 이로 인해 런타임시보다 예측 가능한 속성을 선택할 수 있습니다. 예 : Object.keys
, Object.entries
, JSON.stringify
, for..in
루프 등 ( 코드 샘플 , 또한 매트 Bierner의 참조 대답을 ) :
class Foo {
#bar = 42;
baz = "huhu";
}
Object.keys(new Foo()); // [ "baz" ]
private
키워드머리말:
private
TS 문서의 키워드 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
처음 에는 만들지 않았을 것 입니다. 예를 들어, 단위 테스트는 개인 필드가 구현 세부 사항으로 숨겨져있는 검은 색 / 회색 상자 여야합니다. 그러나 실제로는 경우에 따라 유효한 접근 방식이있을 수 있습니다.
TS private
수정자는 모든 ES 대상과 함께 사용할 수 있습니다. #
-비공개 필드는 target
ES2015
/ ES6
이상 에서만 사용할 수 있습니다 . ES6 +에서는 WeakMap
내부적으로 하위 구현으로 사용됩니다 ( 여기 참조 ). 기본 개인 #
필드에는 현재 필요합니다 target
esnext
.
팀은 코딩 지침과 린터 규칙을 사용 private
하여 유일한 액세스 수정 자로 사용하도록 할 수 있습니다. 이 제한은 일관성을 유지하는 데 도움이되고 #
이전 버전과 호환되는 방식으로 -private 필드 표기법 과 혼동되지 않습니다.
필요한 경우 매개 변수 속성 (생성자 할당 속기)이 쇼 스토퍼입니다. private
키워드 에만 사용할 수 있으며 아직 개인 필드 에 구현할 계획 이 없습니다#
.
private
일부 하위 수준의 경우 더 나은 런타임 성능을 제공 할 수 있습니다 ( 여기 참조 ).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
}
}
출처