ç§æå ç´
åºçº¿
广æ³å¯ç¨
èª 2021å¹´7æ èµ·ï¼æ¤ç¹æ§å·²å¨ä¸»æµæµè§å¨ä¸å¾å°æ¯æï¼å¯å¨å¤§å¤æ°è®¾å¤åæµè§å¨çæ¬ä¸æ£å¸¸ä½¿ç¨ã
ç§æå
ç´ æ¯å¸¸è§çç±»çå
¬æå±æ§ï¼å
æ¬ç±»å段ãç±»æ¹æ³çï¼ç对åºãç§æå
ç´ éè¿æ·»å # åç¼æ¥å建ï¼å¨ç±»çå¤é¨æ æ³åæ³å°å¼ç¨ãè¿äºç±»å±æ§çç§æå°è£
ç± JavaScript æ¬èº«å¼ºå¶æ§è¡ã
å¨è¿ç§è¯æ³åºç°ä¹åï¼JavaScript è¯è¨æ¬èº«å¹¶æ²¡æåçæ¯æç§æå
ç´ ãå¨ååç»§æ¿ä¸ï¼å¯ä»¥éè¿ä½¿ç¨ WeakMap 对象æè
éå
çæ¹å¼æ¥æ¨¡æç§æå
ç´ çè¡ä¸ºï¼ä½å°±æç¨æ§èè¨ï¼å®ä»¬æ æ³ä¸ # è¯æ³ç¸æå¹¶è®ºã
夿³¨ï¼å¨ MDN ä¸ï¼æä»¬é¿å
ä½¿ç¨æ¯è¯âç§æå±æ§âãJavaScript ä¸ç屿§ä»¥å符串æç¬¦å·ä¸ºé®ï¼ä¸å
·æ writableãenumerable å configurable çç¹æ§ï¼attributeï¼ï¼èç§æå
ç´ åä¸å
·æè¿äºç¹æ§ãè½ç¶ç§æå
ç´ ä½¿ç¨çæçç¹è¡¨ç¤ºæ³æ¥è®¿é®ï¼ä½å®ä»¬ä¸è½è¢«ä»£çãæä¸¾ãå é¤æä½¿ç¨ä»»ä½ Object æ¹æ³è¿è¡äº¤äºã
è¯æ³
class ClassWithPrivate {
#privateField;
#privateFieldWithInitializer = 42;
#privateMethod() {
// â¦
}
static #privateStaticField;
static #privateStaticFieldWithInitializer = 42;
static #privateStaticMethod() {
// â¦
}
}
è¿æä¸äºé¢å¤çè¯æ³éå¶ï¼
- ç±»ä¸ææå£°æçç§ææ è¯ç¬¦é½å¿ é¡»æ¯å¯ä¸çï¼å¹¶ä¸å½å空é´å¨éæå ç´ åå®ä¾å ç´ ä¹é´æ¯å ±äº«çãå¯ä¸çä¾å¤æ¯ï¼ä¸¤ä¸ªå£°æå®ä¹äº getter-setter 对ã
- ç§ææè¿°ç¬¦ä¸è½æ¯
#constructorã
æè¿°
大夿°ç±»å ç´ é½æå ¶å¯¹åºçç§æé¡¹ï¼
- ç§æåæ®µ
- ç§ææ¹æ³
- ç§æéæå段
- ç§æéææ¹æ³
- ç§æ getter
- ç§æ setter
- ç§æéæ getter
- ç§æéæ setter
è¿äºç¹æ§ç»ç§°ä¸ºç§æå ç´ ãç¶èï¼JavaScript 䏿é 彿°ä¸è½æ¯ç§æçã为äºé²æ¢å¨ç±»ä¹å¤æé ç±»ï¼ä½ å¿ é¡»ä½¿ç¨ç§ææ å¿ã
ç§æå
ç´ éè¿â#åç§°âï¼â#â读ä½âhashâï¼æ¥å£°æï¼å®ä»¬æ¯ä»¥ # åç¼å¼å¤´çæ è¯ç¬¦ãè¿ä¸ª # åç¼æ¯å±æ§åç§°çåºæé¨åï¼ä½ å¯ä»¥å°å
¶ä¸æ§çä¸å线åç¼çº¦å® _privateField è¿è¡ç±»æ¯ï¼ä½å®ä¸æ¯æ®éçåç¬¦ä¸²å±æ§ï¼å æ¤æ æ³ä½¿ç¨æ¹æ¬å·è¡¨ç¤ºæ³å¨æè®¿é®å®ã
å¨ç±»å¤é¨å¼ç¨ # åç§°ãå¼ç¨æªå¨ç±»å
é¨å£°æçç§æå
ç´ ï¼æå°è¯ä½¿ç¨ delete ç§»é¤å£°æçå
ç´ é½ä¼æåºè¯æ³é误ã
class ClassWithPrivateField {
#privateField;
constructor() {;
delete this.#privateField; // Syntax error
this.#undeclaredField = 42; // Syntax error
}
}
const instance = new ClassWithPrivateField();
instance.#privateField; // Syntax error
JavaScript ä½ä¸ºå¨æè¯è¨ï¼è½å¤å¨ç¼è¯æ¶æ£æ¥ # æ è¯ç¬¦çè¯æ³ï¼ä½¿å
¶ä¸æ®é屿§çè¯æ³ä¸åã
夿³¨ï¼Chrome æ§å¶å°ä¸è¿è¡ç代ç å¯ä»¥è®¿é®ç±»çç§æå ç´ ãè¿æ¯ JavaScript è¯æ³éå¶å¯¹å¼åè å·¥å ·çä¸ç§æ¾å®½ã
å¦æä½ è®¿é®å¯¹è±¡ä¸ä¸åå¨çç§æå
ç´ ï¼ä¼æåº TypeError é误ï¼è䏿¯åæ®é屿§ä¸æ ·è¿å undefinedã
class C {
#x;
static getX(obj) {
return obj.#x;
}
}
console.log(C.getX(new C())); // undefined
console.log(C.getX({})); // TypeError: Cannot read private member #x from an object whose class did not declare it
è¿ä¸ªç¤ºä¾ä¹æ¼ç¤ºäºä½ å¯ä»¥å¨éæå½æ°ä¸ä»¥åå¨å¤é¨å®ä¹çç±»çå®ä¾ä¸è®¿é®ç§æå ç´ ã
ä½ ä¹å¯ä»¥ä½¿ç¨ in è¿ç®ç¬¦æ¥æ£æ¥ä¸ä¸ªå¤é¨å®ä¹ç对象æ¯å¦æ¥æä¸ä¸ªç§æå
ç´ ã妿坹åºçç§æåæ®µæç§ææ¹æ³åå¨ï¼åè¿å trueï¼å¦åè¿å falseã
class C {
#x;
constructor(x) {
this.#x = x;
}
static getX(obj) {
if (#x in obj) return obj.#x;
return "obj å¿
é¡»æ¯ C çå®ä¾";
}
}
console.log(C.getX(new C("foo"))); // "foo"
console.log(C.getX(new C(0.196))); // 0.196
console.log(C.getX(new C(new Date()))); // å½åçæ¥æåæ¶é´
console.log(C.getX({})); // "obj å¿
é¡»æ¯ C çå®ä¾"
请注æï¼ç§æåç§°å§ç»éè¦æå声æå¹¶ä¸ä¸å¯å é¤ï¼å¦æä½ åç°ä¸ä¸ªå¯¹è±¡å
·æå½åç±»çä¸ä¸ªç§æå
ç´ ï¼æ 论æ¯éè¿ try...catch è¿æ¯ in æ£æ¥ï¼ï¼é£ä¹å®ä¸å®å
·æå
¶ä»ææçç§æå
ç´ ãé常æ
åµä¸ï¼ä¸ä¸ªå¯¹è±¡å
·æä¸ä¸ªç±»çç§æå
ç´ æå³ç宿¯ç±è¯¥ç±»æé çï¼å°½ç®¡å¹¶éæ»æ¯å¦æ¤ï¼ã
ç§æå
ç´ ä¸æ¯ååç»§æ¿æ¨¡åçä¸é¨åï¼å 为å®ä»¬åªè½å¨å½åç±»å
é¨è¢«è®¿é®ï¼èä¸ä¸è½è¢«å类继æ¿ãä¸åç±»çç§æå
ç´ åç§°ä¹é´æ²¡æä»»ä½äº¤äºãå®ä»¬æ¯éå 卿¯ä¸ªå®ä¾ä¸çå¤é¨å
æ°æ®ï¼ç±ç±»æ¬èº«ç®¡çãå æ¤ï¼Object.freeze() å Object.seal() å¯¹ç§æå
ç´ æ²¡æå½±åã
å ³äºå¦ä½ä»¥å使¶åå§åç§æåæ®µçæ´å¤ä¿¡æ¯ï¼è¯·åé å ¬æç±»å段ã
示ä¾
>ç§æåæ®µ
ç§æåæ®µå æ¬ç§æå®ä¾å段åç§æéæå段ãç§æåæ®µåªè½å¨ç±»å£°æå é¨è¢«è®¿é®ã
ç§æå®ä¾å段
类似äºå¯¹åºçå ¬æå段ï¼ç§æå®ä¾å段ï¼
- å¨åºç±»ä¸çæé 彿°è¿è¡ä¹åæ·»å ï¼æè
å¨åç±»ä¸è°ç¨
super()ä¹åç«å³æ·»å ï¼å¹¶ä¸ - åªå¨ç±»çå®ä¾ä¸å¯ç¨ã
class ClassWithPrivateField {
#privateField;
constructor() {
this.#privateField = 42;
}
}
class Subclass extends ClassWithPrivateField {
#subPrivateField;
constructor() {
super();
this.#subPrivateField = 23;
}
}
new Subclass(); // å¨ä¸äºå¼åå·¥å
·ä¸ä¼æ¾ç¤ºï¼Subclass {#privateField: 42, #subPrivateField: 23}
夿³¨ï¼ClassWithPrivateField åºç±»ç #privateField æ¯ ClassWithPrivateField ç§æçï¼ä¸è½ä»æ´¾çç Subclass ç±»ä¸è®¿é®ã
è¿åéå对象
ç±»çæé 彿°å¯ä»¥è¿åä¸ä¸ªä¸åç对象ï¼è¿ä¸ªå¯¹è±¡å°è¢«ç¨ä½æ´¾çç±»çæé 彿°ç thisãæ´¾çç±»å¯ä»¥å¨è¿ä¸ªè¿åç对象ä¸å®ä¹ç§æå段ââè¿æå³çå¯ä»¥å°ç§æå段âéå âå°ä¸ç¸å
³ç对象ä¸ã
class Stamper extends class {
// åºç±»ï¼å
¶æé 彿°è¿åç»å®ç对象
constructor(obj) {
return obj;
}
} {
// è¿ä¸ªå£°æä¼å°ç§æå段âéå âå°åºç±»æé 彿°è¿åç对象ä¸
#stamp = 42;
static getStamp(obj) {
return obj.#stamp;
}
}
const obj = {};
new Stamper(obj);
// `Stamper` è°ç¨è¿å `obj` ç `Base`ï¼æä»¥ `obj` ç°å¨æ¯ `this` å¼ãç¶å `Stamper` å¨ `obj` ä¸å®ä¹ `#stamp`
console.log(obj); // å¨ä¸äºå¼åå·¥å
·ä¸ä¼æ¾ç¤ºï¼{#stamp: 42}
console.log(Stamper.getStamp(obj)); // 42
console.log(obj instanceof Stamper); // false
// ä½ æ æ³å°ç§æå
ç´ éå å°åä¸ä¸ªå¯¹è±¡ä¸¤æ¬¡
new Stamper(obj); // Error: Initializing an object twice is an error with private fields
è¦åï¼è¿å¯è½æ¯ä¸ç§éå¸¸ä»¤äººå°æçåæ³ãä½ åºè¯¥é¿å
仿é 彿°è¿åä»»ä½ä¸è¥¿ââå°¤å
¶æ¯ä¸ this æ å
³çä¸è¥¿ã
ç§æéæå段
类似äºå ¬æéæå段ï¼ç§æéæå段ï¼
- å¨ç±»å®ä¾åå被添å å°ç±»çæé 彿°ä¸ï¼å¹¶ä¸
- åªè½å¨ç±»æ¬èº«ä¸å¯ç¨ã
class ClassWithPrivateStaticField {
static #privateStaticField = 42;
static publicStaticMethod() {
return ClassWithPrivateStaticField.#privateStaticField;
}
}
console.log(ClassWithPrivateStaticField.publicStaticMethod()); // 42
ç§æéæå段æä¸äºéå¶ï¼åªæå®ä¹ç§æéæå段çç±»æè½è®¿é®è¯¥å段ãè¿å¯è½å¯¼è´ä½¿ç¨ this æ¶åºç°ææ³ä¸å°çè¡ä¸ºãå¨ä¸é¢çä¾åä¸ï¼this æå Subclass ç±»ï¼è䏿¯ ClassWithPrivateStaticField ç±»ï¼ï¼å¯¼è´å°è¯è°ç¨ Subclass.publicStaticMethod() æ¶æåº TypeErrorã
class ClassWithPrivateStaticField {
static #privateStaticField = 42;
static publicStaticMethod() {
return this.#privateStaticField;
}
}
class Subclass extends ClassWithPrivateStaticField {}
Subclass.publicStaticMethod(); // TypeError: Cannot read private member #privateStaticField from an object whose class did not declare it
å¦æä½ ä½¿ç¨ super æ¥è°ç¨è¯¥æ¹æ³ï¼ä¹æ¯å¦æ¤ï¼å 为 super æ¹æ³è¢«è°ç¨æ¶ä¸ä¼å°åºç±»ä½ä¸º this å¼ã
class ClassWithPrivateStaticField {
static #privateStaticField = 42;
static publicStaticMethod() {
// å½éè¿ super è°ç¨æ¶ï¼`this` ä»ç¶æå Subclass
return this.#privateStaticField;
}
}
class Subclass extends ClassWithPrivateStaticField {
static callSuperMethod() {
return super.publicStaticMethod();
}
}
Subclass.callSuperMethod(); // TypeError: Cannot read private member #privateStaticField from an object whose class did not declare it
å»ºè®®ä½ å§ç»éè¿ç±»åæ¥è®¿é®ç§æéæå段ï¼è䏿¯éè¿ thisï¼ä»¥é¿å
ç»§æ¿ç ´åæ¹æ³ã
ç§ææ¹æ³
ç§ææ¹æ³å æ¬ç§æå®ä¾æ¹æ³åç§æéææ¹æ³ãç§ææ¹æ³åªè½å¨ç±»å£°æå é¨è¢«è®¿é®ã
ç§æå®ä¾æ¹æ³
ä¸å ¬æå®ä¾æ¹æ³ä¸åï¼ç§æå®ä¾æ¹æ³ï¼
- å¨å®ä¾å段å®è£ ä¹åç«å³å®è£ ï¼å¹¶ä¸
- åªè½å¨ç±»çå®ä¾ä¸å¯ç¨ï¼ä¸è½å¨ç±»ç
.prototype屿§ä¸è®¿é®ã
class ClassWithPrivateMethod {
#privateMethod() {
return 42;
}
publicMethod() {
return this.#privateMethod();
}
}
const instance = new ClassWithPrivateMethod();
console.log(instance.publicMethod()); // 42
ç§æå®ä¾æ¹æ³å¯ä»¥æ¯çæå¨æ¹æ³ã弿¥æ¹æ³æå¼æ¥çæå¨æ¹æ³ãç§æ getter å setter æ¹æ³ä¹åæ ·éç¨ï¼å¹¶ä¸ä¸å ¬æ getter å setter æ¹æ³çè¯æ³ç¸åã
class ClassWithPrivateAccessor {
#message;
get #decoratedMessage() {
return `ð¬${this.#message}ð`;
}
set #decoratedMessage(msg) {
this.#message = msg;
}
constructor() {
this.#decoratedMessage = "hello world";
console.log(this.#decoratedMessage);
}
}
new ClassWithPrivateAccessor(); // ð¬hello worldð
ä¸å
¬ææ¹æ³ä¸åï¼ç§ææ¹æ³ä¸è½å¨ç±»ç .prototype 屿§ä¸è®¿é®ã
class C {
#method() {}
static getMethod(x) {
return x.#method;
}
}
console.log(C.getMethod(new C())); // [Function: #method]
console.log(C.getMethod(C.prototype)); // TypeError: Receiver must be an instance of class C
ç§æéææ¹æ³
ä¸å ¬æéææ¹æ³ç±»ä¼¼ï¼ç§æéææ¹æ³ï¼
- å¨ç±»è¢«è§£ææ¶è¢«æ·»å å°ç±»çæé 彿°ä¸ï¼å¹¶ä¸
- åªè½å¨ç±»æ¬èº«ä¸å¯ç¨ã
class ClassWithPrivateStaticMethod {
static #privateStaticMethod() {
return 42;
}
static publicStaticMethod() {
return ClassWithPrivateStaticMethod.#privateStaticMethod();
}
}
console.log(ClassWithPrivateStaticMethod.publicStaticMethod()); // 42
ç§æéææ¹æ³å¯ä»¥æ¯çæå¨æ¹æ³ï¼å¼æ¥æ¹æ³æå¼æ¥çæå¨æ¹æ³ã
å颿å°çç§æéæå段çéå¶åæ ·éç¨äºç§æéææ¹æ³ãåæ ·å°ï¼ä½¿ç¨ this å¯è½ä¼åºç°ææ³ä¸å°çè¡ä¸ºãå¨ä¸é¢çä¾åä¸ï¼å½æä»¬å°è¯è°ç¨ Subclass.publicStaticMethod() æ¶ï¼this æå Subclass ç±»ï¼è䏿¯ ClassWithPrivateStaticMethod ç±»ï¼ï¼å¯¼è´æåº TypeErrorã
class ClassWithPrivateStaticMethod {
static #privateStaticMethod() {
return 42;
}
static publicStaticMethod() {
return this.#privateStaticMethod();
}
}
class Subclass extends ClassWithPrivateStaticMethod {}
console.log(Subclass.publicStaticMethod()); // TypeError: Cannot read private member #privateStaticMethod from an object whose class did not declare it
模æç§ææé 彿°
许å¤å ¶ä»è¯è¨é½æä¾äºå°æé 彿°æ è®°ä¸ºç§æçè½åï¼è¿å°é»æ¢ç±»å¨ç±»å é¨å¤è¢«å®ä¾åââåªè½ä½¿ç¨å建å®ä¾çéæå·¥åæ¹æ³ï¼æè æ ¹æ¬ä¸è½å建å®ä¾ãJavaScript 没æåççç§ææé 彿°çè¯æ³ï¼ä½å¯ä»¥éè¿ç§æéææ å¿æ¥å®ç°ã
class PrivateConstructor {
static #isInternalConstructing = false;
constructor() {
if (!PrivateConstructor.#isInternalConstructing) {
throw new TypeError("PrivateConstructor is not constructable");
}
PrivateConstructor.#isInternalConstructing = false;
// æ·»å æ´å¤çåå§åé»è¾
}
static create() {
PrivateConstructor.#isInternalConstructing = true;
const instance = new PrivateConstructor();
return instance;
}
}
new PrivateConstructor(); // TypeError: PrivateConstructor is not constructable
PrivateConstructor.create(); // PrivateConstructor {}
è§è
| è§è |
|---|
| ECMAScript® 2027 Language Specification> # prod-PrivateIdentifier> |
| ECMAScript® 2027 Language Specification> # prod-00OK517S> |
æµè§å¨å ¼å®¹æ§
>javascript.classes.private_class_fields
javascript.classes.private_class_fields_in
javascript.classes.private_class_methods
åè§
- 使ç¨ç±»æå
- ç±»
- å ¬æç±»å段
class- TC39 ç class-fields ææ¡ä¸å ³äºç§æåè¯æ³ç FAQ
- ææ JS ç±»å ç´ çè¯ä¹ï¼æ¥èª Shu-yu Guoï¼2018ï¼
- v8.dev ç«ç¹ä¸å ³äºå ¬æåç§æç±»åæ®µçæç« ï¼2018ï¼