extends
åºçº¿
广æ³å¯ç¨
èª 2016å¹´3æ èµ·ï¼æ¤ç¹æ§å·²å¨ä¸»æµæµè§å¨ä¸å¾å°æ¯æï¼å¯å¨å¤§å¤æ°è®¾å¤åæµè§å¨çæ¬ä¸æ£å¸¸ä½¿ç¨ã
extends å
³é®åç¨äºç±»å£°ææè
类表达å¼ä¸ï¼ä»¥å建ä¸ä¸ªç±»ï¼è¯¥ç±»æ¯å¦ä¸ä¸ªç±»çåç±»ã
å°è¯ä¸ä¸
class DateFormatter extends Date {
getFormattedDate() {
const months = [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
];
return `${this.getDate()}-${months[this.getMonth()]}-${this.getFullYear()}`;
}
}
console.log(new DateFormatter("August 19, 1975 23:15:30").getFormattedDate());
// Expected output: "19-Aug-1975"
è¯æ³
class ChildClass extends ParentClass { /* ⦠*/ }
ParentClass-
æ±å¼ä¸ºæé 彿°ï¼å æ¬ç±»ï¼æ
nullç表达å¼ã
æè¿°
extends å
³é®åç¨æ¥å建èªå®ä¹ç±»æè
å
置对象çåç±»ã
ä»»ä½å¯ä»¥ç¨ new è°ç¨å¹¶å
·æ prototype 屿§çæé 彿°é½å¯ä»¥ä½ä¸ºåéçç¶ç±»çæé 彿°ãè¿ä¸¤ä¸ªæ¡ä»¶å¿
须忶æç«ââä¾å¦ï¼ç»å®å½æ°å Proxy å¯ä»¥è¢«æé ï¼ä½å®ä»¬æ²¡æ prototype 屿§ï¼å æ¤ä¸è½è¢«åç±»åã
function OldStyleClass() {
this.someProperty = 1;
}
OldStyleClass.prototype.someMethod = function () {};
class ChildClass extends OldStyleClass {}
class ModernClass {
someProperty = 1;
someMethod() {}
}
class AnotherChildClass extends ModernClass {}
ParentClass ç prototype 屿§å¿
é¡»æ¯ Object æ nullï¼ä½å¨å®è·µä¸å¾å°éè¦æ
å¿è¿ä¸ªé®é¢ï¼å 为é对象ç prototype æ 论å¦ä½é½ä¸ä¼æç
§åºæçæ¹å¼è¿è¡ï¼new è¿ç®ç¬¦ä¼å¿½ç¥å®ï¼ã
function ParentClass() {}
ParentClass.prototype = 3;
class ChildClass extends ParentClass {}
// Uncaught TypeError: Class extends value does not have valid prototype property 3
console.log(Object.getPrototypeOf(new ParentClass()));
// [Object: null prototype] {}
// å®é
ä¸å¹¶ä¸æ¯ä¸ä¸ªæ°åï¼
extends 为 ChildClass å ChildClass.prototype 设置äºååã
ChildClass çåå对象 |
ChildClass.prototype çåå对象 |
|
|---|---|---|
ç¼ºå° extends |
Function.prototype |
Object.prototype |
extends null |
Function.prototype |
null |
extends ParentClass |
ParentClass |
ParentClass.prototype |
class ParentClass {}
class ChildClass extends ParentClass {}
// å
许éæå±æ§çç»§æ¿
Object.getPrototypeOf(ChildClass) === ParentClass;
// å
许å®ä¾å±æ§çç»§æ¿
Object.getPrototypeOf(ChildClass.prototype) === ParentClass.prototype;
extend çå³ä¾§ä¸ä¸å®æ¯æ è¯ç¬¦ãä½ å¯ä»¥ä½¿ç¨ä»»ä½æ±å¼ä¸ºæé 彿°ç表达å¼ãè¿é常æå©äºå建混å
¥ï¼mixinï¼ãextends 表达å¼ä¸ç this 弿¯å´ç»ç±»å®ä¹ç this ï¼èå¼ç¨ç±»çåç§°ä¼å¯¼è´ ReferenceErrorï¼å ä¸ºç±»å°æªåå§åã卿¤è¡¨è¾¾å¼ä¸ï¼await å yield æé¢æå·¥ä½ã
class SomeClass extends class {
constructor() {
console.log("åºç±»");
}
} {
constructor() {
super();
console.log("æ´¾çç±»");
}
}
new SomeClass();
// åºç±»
// æ´¾çç±»
åºç±»å¯ä»¥ä»æé 彿°ä¸è¿åä»»ä½å
容ï¼èæ´¾çç±»å¿
é¡»è¿å对象æ undefined ï¼å¦åå°æåº TypeErrorã
class ParentClass {
constructor() {
return 1;
}
}
console.log(new ParentClass()); // ParentClass {}
// è¿åå¼å°è¢«å¿½ç¥ï¼å 为å®ä¸æ¯ä¸ä¸ªå¯¹è±¡
// è¿ä¸å½æ°æé 彿°ä¸è´
class ChildClass extends ParentClass {
constructor() {
super();
return 1;
}
}
console.log(new ChildClass()); // TypeError: Derived constructors may only return object or undefined
妿ç¶ç±»æé 彿°è¿åä¸ä¸ªå¯¹è±¡ï¼åå¨è¿ä¸æ¥åå§åç±»åæ®µæ¶ï¼è¯¥å¯¹è±¡å°è¢«ç¨ä½æ´¾çç±»ç this å¼ãè¿ç§æå·§è¢«ç§°ä¸ºâè¿åè¦çâï¼å®å
è®¸å¨æ å
³å¯¹è±¡ä¸å®ä¹æ´¾çç±»çåæ®µï¼å
æ¬ç§æå段ï¼ã
åç±»åå 置类
è¦åï¼æ åå§åä¼ç®åçç«åºæ¯ï¼ä»¥åçæ¬è§èä¸çå 置类çåç±»åæºå¶è®¾è®¡è¿åº¦ï¼å¯¹æ§è½åå®å ¨æ§é æäºä¸å¯å¿½è§çå½±åãæ°çå ç½®æ¹æ³è¾å°èèåç±»ï¼å¼æå®ç°è æ£å¨ç ç©¶æ¯å¦è¦å 餿äºåç±»æºå¶ãå¨å¢å¼ºå 置类æ¶ï¼è¯·èè使ç¨ç»åèéç»§æ¿ã
ä¸é¢æ¯æ©å±ç±»æ¶å¯è½ä¼éå°çä¸äºé®é¢ï¼
- å¨åç±»ä¸è°ç¨éæå·¥åæ¹æ³ï¼å¦
Promise.resolve()æArray.from()ï¼æ¶ï¼è¿åçå®ä¾å§ç»æ¯åç±»çå®ä¾ã - å¨åç±»ä¸è°ç¨è¿åæ°å®ä¾çå®ä¾æ¹æ³ï¼å¦
Promise.prototype.then()æArray.prototype.map()ï¼æ¶ï¼è¿åçå®ä¾å§ç»æ¯åç±»çå®ä¾ã - å¨å¯è½çæ
åµä¸ï¼å®ä¾æ¹æ³ä¼å°½éå§æç»æå°çåå§æ¹æ³éãä¾å¦ï¼å¯¹äº
Promiseçåç±»ï¼è¦çthen()ä¼èªå¨å¯¼è´catch()çè¡ä¸ºåçååï¼æå¯¹äºMapçåç±»ï¼è¦çset()ä¼èªå¨å¯¼è´Map()æé 彿°çè¡ä¸ºåçååã
ç¶èï¼è¦æ£ç¡®å°å®ç°ä¸è¿°ææï¼éè¦ä»åºä¸å°çåªåã
- 第ä¸ä¸ªè¦æ±éææ¹æ³è¯»å
thisçå¼ï¼ä»¥è·åæé 彿°æ¥æé è¿åçå®ä¾ãè¿æå³ç[p1,p2,p3].map(Promise.resolve)伿åºé误ï¼å 为Promise.resolveä¸çthisæ¯undefinedãè§£å³è¿ä¸ªé®é¢çæ¹æ³æ¯ï¼å¦æthis䏿¯æé 彿°ï¼å°±åéå°åºç±»ï¼å°±åArray.from()æåç飿 ·ï¼ä½è¿ä»ç¶æå³çåºç±»æ¯ç¹ä¾ã - 第äºä¸ªè¦æ±å®ä¾æ¹æ³è¯»å
this.constructor以è·åæé 彿°ã使¯ï¼new this.constructor()å¯è½ä¼ç ´åèæ§ç代ç ï¼å 为constructor屿§æ¯å¯ååå¯é ç½®çï¼èä¸ä¸åä»»ä½ä¿æ¤ãå æ¤ï¼è®¸å¤å¤å¶çå ç½®æ¹æ³é½ä½¿ç¨æé 彿°ç[Symbol.species]屿§ï¼é»è®¤æ åµä¸åªè¿åthisï¼å³æé 彿°æ¬èº«ï¼ãç¶èï¼[Symbol.species]å 许è¿è¡ä»»æä»£ç åå建任æç±»åçå®ä¾ï¼è¿å°±å¸¦æ¥äºå®å ¨é®é¢ï¼å¹¶ä½¿åç±»åè¯ä¹åå¾é叏夿ã - 第ä¸ä¸ªä¼å¯¼è´èªå®ä¹ä»£ç çå¯è§è°ç¨ï¼ä»è使å¾å¤ä¼åæ´é¾å®ç°ãä¾å¦ï¼å¦æä½¿ç¨å
å« x 个å
ç´ çå¯è¿ä»£å
ç´ è°ç¨
Map()æé 彿°ï¼é£ä¹å®å¿ é¡»ææ¾å°è°ç¨set()æ¹æ³ x 次ï¼èä¸ä» ä» æ¯å°å ç´ å¤å¶å°å é¨åå¨ã
è¿äºé®é¢å¹¶éå 置类æç¬æã对äºä½ èªå·±çç±»ï¼ä½ ä¹å¯è½éè¦ååºåæ ·çå³å®ãä¸è¿ï¼å¯¹äºå 置类æ¥è¯´ï¼å¯ä¼åæ§åå®å ¨æ§æ¯æ´å¤§çé®é¢ãæ°çå ç½®æ¹æ³æ»æ¯æé åºç±»ï¼å¹¶å°½å¯è½å°å°è°ç¨èªå®ä¹æ¹æ³ãå¦æä½ æ³å¨å®ç°ä¸è¿°ææç忶坹å 置类è¿è¡åç±»åï¼ä½ éè¦éåææå·²å ·æé»è®¤è¡ä¸ºçæ¹æ³ãå¨åºç±»ä¸æ·»å 任使°æ¹æ³é½å¯è½ä¼ç ´ååç±»çè¯ä¹ï¼å 为è¿äºæ¹æ³æ¯é»è®¤ç»§æ¿çãå æ¤ï¼æ©å±å ç½®ç±»çæ´å¥½æ¹æ³æ¯ä½¿ç¨ç»åã
æå± null
extends null 设计ç¨äºè½»æ¾å建ä¸ç»§æ¿èª Object.prototype ç对象ãç¶èï¼ç±äºå
³äºæ¯å¦åºå¨æé 彿°ä¸è°ç¨ super() çå³å®å°æªç¡®å®ï¼å æ¤å¨å®è·µä¸ä¸å¯è½ä½¿ç¨ä»»ä½ä¸è¿å对象çæé 彿°å®ç°æ¥æé è¿æ ·çç±»ãTC39 å§å伿£å¨åªåéæ°å¯ç¨è¿ä¸ç¹æ§ã
new (class extends null {})();
// TypeError: Super constructor null of anonymous class is not a constructor
new (class extends null {
constructor() {}
})();
// ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
new (class extends null {
constructor() {
super();
}
})();
// TypeError: Super constructor null of anonymous class is not a constructor
ç¸åï¼ä½ éè¦ä»æé 彿°ä¸æç¡®è¿åä¸ä¸ªå®ä¾ã
class NullClass extends null {
constructor() {
// ä½¿ç¨ new.target å
许派çç±»å
·ææ£ç¡®çååé¾
return Object.create(new.target.prototype);
}
}
const proto = Object.getPrototypeOf;
console.log(proto(proto(new NullClass()))); // null
示ä¾
>ä½¿ç¨ extends
第ä¸ä¸ªä¾åæ¯æ ¹æ®å为 Polygon ç±»å建ä¸ä¸ªå为 Square çç±»ãå½åç¤ºä¾æ¯ä»è¿ä¸ªå¨çº¿æ¼ç¤ºä¸æååºæ¥çï¼æºä»£ç ï¼ã
class Square extends Polygon {
constructor(length) {
// å¨è¿éï¼å®ä¼è°ç¨ç¶ç±»çæé 彿°ï¼å¹¶ä¸ºå¤è¾¹å½¢ç宽度åé«åº¦æä¾é¿åº¦
super(length, length);
// 卿´¾çç±»ä¸ï¼å¿
é¡»å
è°ç¨ super() æè½ç¨âthisâãçç¥è¿ä¸ç¹å°å¯¼è´å¼ç¨é误ã
this.name = "Square";
}
get area() {
return this.height * this.width;
}
}
æ©å±æ®é对象
ç±»ä¸è½æ©å±å¸¸è§ï¼ä¸å¯æé ï¼å¯¹è±¡ã妿æ³éè¿å¨ç»§æ¿å®ä¾ä¸ä½¿ç¨å¸¸è§å¯¹è±¡çææå±æ§æ¥ç»§æ¿è¯¥å¯¹è±¡ï¼å¯ä»¥ä½¿ç¨ Object.setPrototypeOf() 代æ¿ï¼
const Animal = {
speak() {
console.log(`${this.name} ååºäºåªé³`);
},
};
class Dog {
constructor(name) {
this.name = name;
}
}
Object.setPrototypeOf(Dog.prototype, Animal);
const d = new Dog("Mitzie");
d.speak(); // Mitzie ååºäºåªé³
æ©å±å 置对象
è¿ä¸ªç¤ºä¾ç»§æ¿äºå
ç½®ç Date 对象ãå½åç¤ºä¾æ¯ä»è¿ä¸ªå¨çº¿æ¼ç¤ºä¸æååºæ¥çï¼æºä»£ç ï¼ã
class MyDate extends Date {
getFormattedDate() {
const months = [
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
];
return `${this.getDate()}-${months[this.getMonth()]}-${this.getFullYear()}`;
}
}
æ©å± Object
ææ JavaScript 对象é»è®¤æ
åµä¸é½ç»§æ¿èª Object.prototypeï¼å æ¤ä¹ä¸çï¼ç¼å extends Object 似乿¯å¤ä½çãä¸å®å
¨ä¸å extends çå¯ä¸åºå«æ¯æé 彿°æ¬èº«ç»§æ¿äº Object çéææ¹æ³ï¼ä¾å¦ Object.keys()ãç¶èï¼ç±äºæ²¡æä»»ä½ Object éææ¹æ³ä¼ä½¿ç¨ this å¼ï¼å æ¤ç»§æ¿è¿äºéææ¹æ³ä»ç¶æ²¡æä»»ä½ä»·å¼ã
Object() æé 彿°ç¹æ®å¤çäºåç±»åæ
åµã妿éè¿ super() éå¼è°ç¨è¯¥æé 彿°ï¼å该æé 彿°å§ç»ä»¥ new.target.prototype 为åååå§åä¸ä¸ªæ°å¯¹è±¡ãä¼ éç» super() çä»»ä½å¼é½å°è¢«å¿½ç¥ã
class C extends Object {
constructor(v) {
super(v);
}
}
console.log(new C(1) instanceof Number); // false
console.log(C.keys({ a: 1, b: 2 })); // [ 'a', 'b' ]
å°è¿ç§è¡ä¸ºä¸ä¸å¯¹åç±»è¿è¡ç¹æ®å¤ççèªå®ä¹å è£ å¨è¿è¡æ¯è¾ï¼
function MyObject(v) {
return new Object(v);
}
class D extends MyObject {
constructor(v) {
super(v);
}
}
console.log(new D(1) instanceof Number); // true
Species
ä½ å¯è½å¸æå¨æ´¾çæ°ç»ç±» MyArray ä¸è¿å Array 对象ãSpecies 模å¼å¯è®©ä½ è¦çé»è®¤æé 彿°ã
ä¾å¦ï¼å¨ä½¿ç¨ Array.prototype.map() çè¿åé»è®¤æé 彿°çæ¹æ³æ¶ï¼ä½ 叿è¿äºæ¹æ³è¿åçæ¯ç¶ Array 对象ï¼è䏿¯ MyArray 对象ãSymbol.species 符å·å¯è®©ä½ åå°è¿ä¸ç¹ï¼
class MyArray extends Array {
// å° Species è¦çå°ç¶ç±» Array çæé 彿°
static get [Symbol.species]() {
return Array;
}
}
const a = new MyArray(1, 2, 3);
const mapped = a.map((x) => x * x);
console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array); // true
许å¤å ç½®å¤å¶æ¹æ³é½å®ç°äºè¿ä¸è¡ä¸ºãæå ³æ¤åè½ç注æäºé¡¹ï¼è¯·åé åç±»åå 置类讨论ã
æ··å ¥
æ½è±¡åç±»ææ··å ¥æ¯ç±»ç模æ¿ãä¸ä¸ªç±»åªè½æä¸ä¸ªç¶ç±»ï¼å æ¤ä¸å¯è½ä»å·¥å ·ç±»çå¤éç»§æ¿ãåè½å¿ é¡»ç±è¶ ç±»æä¾ã
ä¸ä¸ªä»¥ç¶ç±»ä¸ºè¾å ¥ï¼ä»¥æ©å±è¯¥ç¶ç±»çå类为è¾åºç彿°å¯ä»¥ç¨æ¥å®ç°æ··å ¥ï¼
const calculatorMixin = (Base) =>
class extends Base {
calc() {}
};
const randomizerMixin = (Base) =>
class extends Base {
randomize() {}
};
使ç¨è¿äºæ··å ¥çç±»å¯ä»¥è¿æ ·ç¼åï¼
class Foo {}
class Bar extends calculatorMixin(randomizerMixin(Foo)) {}
é¿å ç»§æ¿
å¨é¢å对象ç¼ç¨ä¸ï¼ç»§æ¿æ¯ä¸ç§é常强çè¦åå
³ç³»ã宿å³çåç±»é»è®¤ç»§æ¿åºç±»çææè¡ä¸ºï¼ä½è¿å¹¶ä¸æ»æ¯ä½ æ³è¦çãä¾å¦ï¼è¯·ç ReadOnlyMap çå®ç°ï¼
class ReadOnlyMap extends Map {
set() {
throw new TypeError("A read-only map must be set at construction time.");
}
}
ç»æåç° ReadOnlyMap æ æ³æé ï¼å 为 Map() æé 彿°è°ç¨äºå®ä¾ç set() æ¹æ³ã
const m = new ReadOnlyMap([["a", 1]]); // TypeError: A read-only map must be set at construction time.
æä»¬å¯ä»¥éè¿ä½¿ç¨ä¸ä¸ªç§ææ å¿æ¥æç¤ºæ¯å¦æ£å¨æé å®ä¾æ¥è§£å³è¿ä¸ªé®é¢ãç¶èï¼è¿ç§è®¾è®¡çä¸ä¸ªæ´éè¦çé®é¢æ¯ï¼å®ç ´åäºéæ°æ¿æ¢ååï¼è¯¥ååè§å®åç±»åºè¯¥å¯ä»¥æ¿æ¢å
¶è¶
ç±»ã妿彿°ææä½¿ç¨ä¸ä¸ª Map 对象ï¼é£ä¹å®ä¹åºè¯¥è½å¤ä½¿ç¨ä¸ä¸ª ReadOnlyMap 对象ï¼è¿å¨è¿éå°±ä¼è¢«æç ´ã
ç»§æ¿å¸¸å¸¸ä¼å¯¼è´åââæ¤åé®é¢ï¼å 为两ç§ç±»åè½ç¶æå¾å¤å ±åç¹å¾ï¼ä½é½ä¸è½å®ç¾å°å å«å¦ä¸ç§ç±»åçè¡ä¸ºãä¸è¬æ¥è¯´ï¼é¤éæé常å åççç±ä½¿ç¨ç»§æ¿ï¼å¦åæå¥½ä½¿ç¨ç»åãç»åæ¯æä¸ä¸ªç±»æ¥æå¦ä¸ä¸ªç±»å¯¹è±¡çå¼ç¨ï¼ä½åªå°è¯¥å¯¹è±¡ç¨ä½å®ç°ç»èã
class ReadOnlyMap {
#data;
constructor(values) {
this.#data = new Map(values);
}
get(key) {
return this.#data.get(key);
}
has(key) {
return this.#data.has(key);
}
get size() {
return this.#data.size;
}
*keys() {
yield* this.#data.keys();
}
*values() {
yield* this.#data.values();
}
*entries() {
yield* this.#data.entries();
}
*[Symbol.iterator]() {
yield* this.#data[Symbol.iterator]();
}
}
å¨è¿ç§æ
åµä¸ï¼ReadOnlyMap ç±»ä¸æ¯ Map çåç±»ï¼ä½å®ä»ç¶å®ç°äºå¤§é¨åç¸åçæ¹æ³ãè¿æå³çæ´å¤ç代ç éå¤ï¼ä½ä¹æå³ç ReadOnlyMap ç±»ä¸ Map ç±»ä¸æ¯å¼ºè¦åçï¼å¹¶ä¸å¨ Map ç±»æ´æ¹æ¶ä¸ä¼è½»æä¸æï¼ä»èé¿å
äºåç±»åå
置类çè¯ä¹é®é¢ãä¾å¦ï¼å¦æ Map 类添å äºä¸ä¸ªä¸è°ç¨ set() ç emplace() æ¹æ³ï¼å°±ä¼å¯¼è´ ReadOnlyMap ç±»ä¸åæ¯åªè¯»çï¼é¤éåè
ä¹ç¸åºå°æ´æ°ä»¥è¦ç emplace()ãæ¤å¤ï¼ReadOnlyMap å¯¹è±¡æ ¹æ¬æ²¡æ set æ¹æ³ï¼è¿æ¯å¨è¿è¡æ¶æåºé误æ´åç¡®ã
è§è
| è§è |
|---|
| ECMAScript® 2027 Language Specification> # sec-class-definitions> |
æµè§å¨å ¼å®¹æ§
åè§
- 使ç¨ç±»æå
- ç±»
constructorclasssuper