Object.prototype.constructor
åºçº¿
广æ³å¯ç¨
èª 2015å¹´7æ èµ·ï¼æ¤ç¹æ§å·²å¨ä¸»æµæµè§å¨ä¸å¾å°æ¯æï¼å¯å¨å¤§å¤æ°è®¾å¤åæµè§å¨çæ¬ä¸æ£å¸¸ä½¿ç¨ã
Object å®ä¾ç constructor æ°æ®å±æ§è¿åä¸ä¸ªå¼ç¨ï¼æåå建该å®ä¾å¯¹è±¡çæé 彿°ã注æï¼æ¤å±æ§ç弿¯å¯¹å½æ°æ¬èº«çå¼ç¨ï¼è䏿¯ä¸ä¸ªå
å«å½æ°åç§°çå符串ã
夿³¨ï¼è¿æ¯ JavaScript 对象çä¸ä¸ªå±æ§ãå
³äºç±»ç constructor æ¹æ³ï¼è¯·åè§å
¶åè页é¢ã
å¼
对å建该å®ä¾å¯¹è±¡çæé 彿°çå¼ç¨ã
Object.prototype.constructor ç屿§ç¹æ§ | |
|---|---|
| å¯å | æ¯ |
| 坿䏾 | å¦ |
| å¯é ç½® | æ¯ |
夿³¨ï¼è¿ä¸ªå±æ§é»è®¤ä¼å¨æ¯ä¸ªæé 彿°ç prototype 屿§ä¸å建ï¼å¹¶ç±è¯¥æé 彿°åå»ºçææå¯¹è±¡ç»§æ¿ã
æè¿°
é¤äº null åå对象ä¹å¤ï¼ä»»ä½å¯¹è±¡é½ä¼å¨å
¶ [[Prototype]] 䏿ä¸ä¸ª constructor 屿§ã使ç¨åé¢éå建ç对象ä¹ä¼æä¸ä¸ªæå该对象æé 彿°ç±»åç constructor 屿§ï¼ä¾å¦ï¼æ°ç»åé¢éå建ç Array 对象å对象åé¢éåå»ºçæ®é对象ã
const o1 = {};
o1.constructor === Object; // true
const o2 = new Object();
o2.constructor === Object; // true
const a1 = [];
a1.constructor === Array; // true
const a2 = new Array();
a2.constructor === Array; // true
const n = 3;
n.constructor === Number; // true
请注æï¼constructor 屿§é常æ¥èªæé 彿°ç prototype 屿§ãå¦æä½ æä¸ä¸ªæ´é¿çååé¾ï¼é常å¯ä»¥åå®é¾ä¸çæ¯ä¸ªå¯¹è±¡é½æä¸ä¸ª constructor 屿§ã
const o = new TypeError(); // ç»§æ¿å
³ç³»ï¼TypeError -> Error -> Object
const proto = Object.getPrototypeOf;
proto(o).constructor === TypeError; // true
proto(proto(o)).constructor === Error; // true
proto(proto(proto(o))).constructor === Object; // true
示ä¾
>æå°å¯¹è±¡çæé 彿°
ä¸é¢è¿ä¸ªç¤ºä¾å建ä¸ä¸ªæé 彿°ï¼Treeï¼ï¼ä»¥å该类åç对象ï¼theTreeï¼ãç¶åæå°äº theTree 对象ç constructor 屿§ã
function Tree(name) {
this.name = name;
}
const theTree = new Tree("Redwood");
console.log(`theTree.constructor æ¯ ${theTree.constructor}`);
è¿ä¸ªç¤ºä¾ä¼æå°ä»¥ä¸è¾åºï¼
theTree.constructor æ¯ function Tree(name) {
this.name = name;
}
为对象ç constructor 屿§èµå¼
å¯ä»¥ä¸ºéåºæ¬ç±»å对象ç constructor 屿§èµå¼ã
const arr = [];
arr.constructor = String;
arr.constructor === String; // true
arr instanceof String; // false
arr instanceof Array; // true
const foo = new Foo();
foo.constructor = "bar";
foo.constructor === "bar"; // true
// ççâ¦
è¿ä¸ä¼è¦çæ§ç constructor 屿§ââå®å®é
ä¸åå¨äºå®ä¾ç [[Prototype]] ä¸ï¼è䏿¯ä½ä¸ºå
¶èªæå±æ§ã
const arr = [];
Object.hasOwn(arr, "constructor"); // false
Object.hasOwn(Object.getPrototypeOf(arr), "constructor"); // true
arr.constructor = String;
Object.hasOwn(arr, "constructor"); // trueââå®ä¾å±æ§ä¼è¦çååé¾ä¸çåå屿§
使¯ï¼å³ä½¿å¯¹ Object.getPrototypeOf(a).constructor éæ°èµå¼ï¼å®ä¹ä¸ä¼æ¹å对象çå
¶ä»è¡ä¸ºãä¾å¦ï¼instanceof çè¡ä¸ºç± Symbol.hasInstance æ§å¶ï¼è䏿¯ç± constructor æ§å¶ï¼
const arr = [];
arr.constructor = String;
arr instanceof String; // false
arr instanceof Array; // true
constructor 屿§æ²¡æåå°ä¿æ¤ï¼å¯ä»¥è¢«éæ°èµå¼æè¢«è¦çï¼å æ¤å¨æ£æµåéç±»åæ¶ï¼é常åºé¿å
使ç¨å®ï¼èåºè¯¥ä½¿ç¨æ´ä¸æåºéçæ¹æ³ï¼å¦å¯¹äºå¯¹è±¡ä½¿ç¨ instanceof å Symbol.toStringTagï¼å¯¹äºåºæ¬ç±»åä½¿ç¨ typeofã
æ´æ¹æé 彿°åå对象ç constructor 屿§
æ¯ä¸ªæé 彿°é½æä¸ä¸ª prototype 屿§ï¼å½éè¿ new è¿ç®ç¬¦è°ç¨æ¶ï¼è¯¥å±æ§å°æä¸ºå®ä¾ç [[Prototype]]ãå æ¤ï¼ConstructorFunction.prototype.constructor å°æä¸ºå®ä¾ç [[Prototype]] ä¸ç屿§ï¼å¦åé¢æè¿°ã
ç¶èï¼å¦æå¯¹ ConstructorFunction.prototype éæ°èµå¼ï¼constructor 屿§å°ä¸¢å¤±ãä¾å¦ï¼ä»¥ä¸æ¯åå»ºç»§æ¿æ¨¡å¼çå¸¸è§æ¹å¼ï¼
function Parent() {
// â¦
}
Parent.prototype.parentMethod = function () {};
function Child() {
Parent.call(this); // ç¡®ä¿ææå
容é½å·²æ£ç¡®åå§å
}
// å° Child.prototype ç [[Prototype]] æå Parent.prototype
Child.prototype = Object.create(Parent.prototype);
ç±äºéæ°èµå¼äº Child.prototypeï¼Child å®ä¾ç constructor å°æ¯ Parentã
é常æ
åµä¸ï¼è¿ä¸æ¯ä»ä¹å¤§é®é¢ââJavaScript å ä¹ä»ä¸è¯»å对象ç constructor 屿§ãå¯ä¸çä¾å¤æ¯å¨ä½¿ç¨ [Symbol.species] åå»ºç±»çæ°å®ä¾æ¶ï¼ä½è¿ç§æ
åµå¾å°è§ï¼å¹¶ä¸ä½ åºè¯¥ä½¿ç¨ extends è¯æ³æ¥åç±»åå
置对象ã
ç¶èï¼å¨æäºè°ç¨ä½¿ç¨ constructor ä»å®ä¾ä¸è®¿é®åå§ç±»æ¶ï¼ç¡®ä¿ Child.prototype.constructor æ»æ¯æå Child æ¬èº«é常éè¦ãèèè¿ç§æ
åµï¼å¯¹è±¡å
·æ create() æ¹æ³æ¥å建èªèº«ã
function Parent() {
// â¦
}
function CreatedConstructor() {
Parent.call(this);
}
CreatedConstructor.prototype = Object.create(Parent.prototype);
CreatedConstructor.prototype.create = function () {
return new this.constructor();
};
new CreatedConstructor().create().create(); // TypeError: new CreatedConstructor().create().create is undefinedï¼å 为 constructor === Parent
å¨ä¸é¢ç示ä¾ä¸ï¼ä¼æåºä¸ä¸ªå¼å¸¸ï¼å 为 constructor 龿¥å° Parentã为äºé¿å
è¿ç§æ
åµï¼åªéå°å
¶èµå¼ä¸ºä½ å°è¦ä½¿ç¨çå¿
è¦æé 彿°å³å¯ã
function Parent() {
// â¦
}
function CreatedConstructor() {
// â¦
}
CreatedConstructor.prototype = Object.create(Parent.prototype, {
// å°åå§æé 彿°è¿åç» Child
constructor: {
value: CreatedConstructor,
enumerable: false, // 使å
¶ä¸å¯æä¸¾ï¼è¿æ ·å®å°±ä¸ä¼åºç°å¨ `for...in` 循ç¯ä¸
writable: true,
configurable: true,
},
});
CreatedConstructor.prototype.create = function () {
return new this.constructor();
};
new CreatedConstructor().create().create(); // è·èµ·æ¥æ²¡æ¯ç
请注æï¼å½æå¨æ·»å constructor 屿§æ¶ï¼å°å±æ§è®¾ç½®ä¸ºä¸å¯æä¸¾é常éè¦ï¼è¿å°ç¡®ä¿ constructor å°±ä¸ä¼å¨ for...in 循ç¯ä¸è¢«è®¿é®ââ尽管é常æ
åµä¸ä¸ä¼è¢«è®¿é®ã
妿ä¸é¢ç代ç çèµ·æ¥å¤ªæ»æ¿ï¼ä½ ä¹å¯ä»¥èèä½¿ç¨ Object.setPrototypeOf() æ¥æä½ååé¾ã
function Parent() {
// â¦
}
function CreatedConstructor() {
// â¦
}
Object.setPrototypeOf(CreatedConstructor.prototype, Parent.prototype);
CreatedConstructor.prototype.create = function () {
return new this.constructor();
};
new CreatedConstructor().create().create(); // å¨ä¸éæ°å建 constructor 屿§çæ
åµä¸ä»ç¶ææ
Object.setPrototypeOf() å卿½å¨çæ§è½ç¼ºé·ï¼å 为ææå
ååå»ºçæ¶å该ååé¾ç对象é½å¿
须鿰ç¼è¯ï¼ä½æ¯ï¼å¦æä¸è¿°åå§å代ç åçå¨ Parent æ CreatedConstructor æé ä¹åï¼å
¶å½±ååºè¯¥æ¯å¾å°çã
æ¥ä¸æ¥ï¼çå¦å¤ä¸ä¸ªç¸å ³ç¤ºä¾ã
function ParentWithStatic() {}
ParentWithStatic.startPosition = { x: 0, y: 0 }; // éææå屿§
ParentWithStatic.getStartPosition = function () {
return this.startPosition;
};
function Child(x, y) {
this.position = { x, y };
}
Child.prototype = Object.create(ParentWithStatic.prototype, {
// å°åå§æé 彿°è¿åç» Child
constructor: {
value: Child,
enumerable: false,
writable: true,
configurable: true,
},
});
Child.prototype.getOffsetByInitialPosition = function () {
const position = this.position;
// ä½¿ç¨ `this.constructor`ï¼ä»¥æ `getStartPosition` åå¨äºä¸ä¸ªéææ¹æ³ä¸ã
const startPosition = this.constructor.getStartPosition();
return {
offsetX: startPosition.x - position.x,
offsetY: startPosition.y - position.y,
};
};
new Child(1, 1).getOffsetByInitialPosition();
// Error: this.constructor.getStartPosition is undefinedï¼
// å 为æé 彿°æ¯ Childï¼å®æ²¡æ getStartPosition éææ¹æ³
妿æ³è¦ä¿è¯ç¤ºä¾æ£å¸¸è¿è¡ï¼æä»¬éè¦è®© Parent ä½ä¸ºæé 彿°ï¼æç» Child çæé åé
éæå±æ§ï¼
// â¦
Object.assign(Child, ParentWithStatic); // 注æï¼å¨å建 Child çåååæä»¬å
åé
å®çå¼
Child.prototype = Object.create(ParentWithStatic.prototype, {
// å°åå§æé 彿°è¿åç» Child
constructor: {
value: Child,
enumerable: false,
writable: true,
configurable: true,
},
});
// â¦
使´å¥½çæ¹æ³æ¯ï¼æä»¬å¯ä»¥ä½¿æé 彿°æ¬èº«ç¸äºç»§æ¿ï¼å°±åç±»ç extends 䏿 ·ã
function ParentWithStatic() {}
ParentWithStatic.startPosition = { x: 0, y: 0 }; // éææå屿§
ParentWithStatic.getStartPosition = function () {
return this.startPosition;
};
function Child(x, y) {
this.position = { x, y };
}
// æ£ç¡®å°å建继æ¿å
³ç³»ï¼
Object.setPrototypeOf(Child.prototype, ParentWithStatic.prototype);
Object.setPrototypeOf(Child, ParentWithStatic);
Child.prototype.getOffsetByInitialPosition = function () {
const position = this.position;
const startPosition = this.constructor.getStartPosition();
return {
offsetX: startPosition.x - position.x,
offsetY: startPosition.y - position.y,
};
};
console.log(new Child(1, 1).getOffsetByInitialPosition()); // { offsetX: -1, offsetY: -1 }
忬¡å¼ºè°ï¼ä½¿ç¨ Object.setPrototypeOf() å¯è½ä¼å¯¹æ§è½äº§çä¸å©å½±åï¼å æ¤è¯·ç¡®ä¿å®ä»
å¨å¿
è¦æ¶ä½¿ç¨ï¼å¹¶å¨æé 彿°å£°æåç«å³ä½¿ç¨ï¼å¹¶å¨å建任ä½å®ä¾ä¹å使ç¨ï¼ä»¥é¿å
å¯¹è±¡è¢«âæ±¡æâã
夿³¨ï¼è®¾ç½®ææ´æ°æé 彿°å¯è½ä¼å¯¼è´ç»æä¸åä¸ä»¤äººå°æçç»æã为äºé²æ¢å®ï¼åªéå¨ç¹å®æ
åµä¸å®ä¹ constructorã夿°æ
åµï¼ä¸ä½¿ç¨ constructorï¼å¹¶ä¸ä¸éè¦éæ°å¯¹å
¶èµå¼ã
è§è
| è§è |
|---|
| ECMAScript® 2027 Language Specification> # sec-object.prototype.constructor> |