ç¹¼æ¿èååé
JavaScript æ¯åæ²æå¯¦å class ééµåçåæ
èªè¨ï¼æä»¥æå°é£äºåºæ¼é¡å¥ï¼class-basedï¼èªè¨ï¼å¦ Java æ C++ï¼èæ¯åºèº«çéç¼è
ä¾èªªææé»å°æãï¼å¨ ES2015 ææä¾ class ééµåï¼ä½é£åªæ¯åèªæ³ç³ï¼JavaScript ä»ç¶æ¯åºæ¼ååï¼prototype-basedï¼çèªè¨ï¼ã
è¬å°ç¹¼æ¿ï¼JavaScript å°±åªæä¸å建æ§åï¼ç©ä»¶ãæ¯åç©ä»¶é½æä¸åé£èå
¶ä»ååï¼prototypeï¼çç§æå±¬æ§ï¼private propertyï¼ç©ä»¶ãååç©ä»¶ä¹æèèªå·±çååï¼æ¼æ¯ååç©ä»¶å°±é樣éçµï¼ç´å°æè¦ null çºæ¢ï¼null å¨å®ç¾©è£¡æ²æååã乿¯ååéï¼prototype chainï¼çæå¾ä¸åéçµã
幾乿æ JavaScript çç©ä»¶ï¼é½æ¯å¨ååéæé 端ç Object 實ä¾ã
éç¶é常被èªçºæ¯ JavaScript çä¸å缺é·ï¼ä½ååç¹¼æ¿æ¨¡å實éä¸ï¼æ¯å³çµ±ç classic æ¨¡åæ´å¼·å¤§ãèä¾ä¾èªªï¼ä½¿ç¨ååç¹¼æ¿æ¨¡å建æ§ä¸å classic æ¨¡åæ¯ç¸ç¶å®¹æçã
使ç¨ååéç¹¼æ¿
>ç¹¼æ¿å±¬æ§
JavaScript ç©ä»¶æ¯ä¸ãå ãåæ ç屬æ§ï¼ä¹å°±æ¯å®èªå·±ç屬æ§ï¼ä¸¦ææä¸åååç©ä»¶çéçµï¼ç¶ç©ä»¶è©¦åååä¸åç©ä»¶çå±¬æ§æï¼å ¶ä¸å æå°æ¾è©²ç©ä»¶ï¼ä¹æå°æ¾è©²ç©ä»¶çååãååçååâ¦â¦ç´å°æ¾å°ç¸ç¬¦åç屬æ§ï¼ææ¯å°éååéç尾端ã
å註ï¼éµç
§ ECMAScript æ¨æºç someObject.[[Prototype]] æ¨è¨ï¼ç¨æ¼ææ´¾ someObject çååãå¾ ECMAScript 2015 éå§ï¼ [[Prototype]] ä½¿ç¨ Object.getPrototypeOf() è Object.setPrototypeOf() éå
©å訪åå¨ï¼accessorsï¼è¨ªåï¼ç忼鿍æºï¼ä½å大ç覽å¨å·²å¯¦åç __proto__ 屬æ§ã
ä¸è¦æ someObject.[[Prototype]] èå½å¼å±¬æ§ func.prototype æ··æ·äºãå®å¨å½å¼è¢«ç¨ä½å»ºæ§åçæåï¼æå® [[Prototype]] è¦åæ´¾å°ææç±çµ¦å®å½å¼å»ºç«çç©ä»¶å¯¦ä¾ï¼instanceï¼ãObject.prototype 屬æ§ä»£è¡¨äºååå±¬æ§ Objectã
以䏿¯å試ååå±¬æ§ææç¼ççäºï¼
// å©ç¨å«æ a è b 屬æ§ç f å½å¼ï¼å»ºç«ä¸å o ç©ä»¶ï¼
let f = function () {
this.a = 1;
this.b = 2;
};
let o = new f(); // {a: 1, b: 2}
// æ¥èéå° f å½å¼çååæ·»å 屬æ§
f.prototype.b = 3;
f.prototype.c = 4;
// ä¸è¦å¯« f.prototype = {b:3,c:4}; å çºå®æç ´å£ååé
// o.[[Prototype]] æ b è c ç屬æ§ï¼{b: 3, c: 4}
// o.[[Prototype]].[[Prototype]] æ¯ Object.prototype.
// æå¾ o.[[Prototype]].[[Prototype]].[[Prototype]] æäº null
// 鿝ååéççµæ«ï¼å çº null æç
§å®ç¾©ä¸¦æ²æ [[Prototype]]ã
// å æ¤ï¼æ´åååéçèµ·ä¾å°±åï¼
// {a: 1, b: 2} ---> {b: 3, c: 4} ---> Object.prototype ---> null
console.log(o.a); // 1
// o æå±¬æ§ãaãåï¼æï¼è©²æ¸å¼çº 1ã
console.log(o.b); // 2
// o æå±¬æ§ãbãåï¼æï¼è©²æ¸å¼çº 2ã
// o éæååå屬æ§ãbãï¼ä½éè£¡æ²æè¢«è¨ªåå°ã
// é稱ä½ãproperty shadowingãã
console.log(o.c); // 4
// o æå±¬æ§ãcãåï¼æ²æï¼é£å°±æ¾ o çååççã
// o å¨ão.[[Prototype]]ãæå±¬æ§ãcãåï¼æï¼è©²æ¸å¼çº 4ã
console.log(o.d); // undefined
// o æå±¬æ§ãdãåï¼æ²æï¼é£å°±æ¾ o çååççã
// o å¨ão.[[Prototype]]ãæå±¬æ§ãdãåï¼æ²æï¼é£å°±æ¾ o.[[Prototype]] çååççã
// o.[[Prototype]].[[Prototype]] æ¯ Object.prototypeï¼é è¨ä¸¦æ²æå±¬æ§ãdãï¼é£åæ¾ä»çååççã
// o å¨ão.[[Prototype]].[[Prototype]].[[Prototype]]ãæ¯ nullï¼åæ¢æå°ã
// æ¾ä¸å°ä»»ä½å±¬æ§ï¼åå³ undefinedã
給ç©ä»¶è¨å®å±¬æ§ï¼æä»¤å ¶å»ºç«èªæç屬æ§ãéåè¡çºè¦åçå¯ä¸ä¾å¤ï¼å°±æ¯ç¢°ä¸ä»¥ getter æ setter ç¹¼æ¿çå±¬æ§æã
ç¹¼æ¿æ¹æ³
Javascript ä¸¦æ²æå ¶ä»åºæ¼é¡å¥èªè¨é£è¬å®ç¾©çæ¹æ³ãå¨ Javascript 裡ï¼ä»»ä½å½å¼é½è½ä»¥å±¬æ§çæ¹å¼å å°ç©ä»¶ä¸ãä¸å被繼æ¿çå½å¼çè¡çºå°±åæ¯å ¶ä»å±¬æ§ä¸æ¨£ï¼å ¶ä¸ä¹å å«äºä¸è¿°ç property shadowingï¼å¨éç¨®æ æ³ä¸å«å method overridingï¼ã
ç¶ç¹¼æ¿å½å¼å·è¡æï¼this 弿åç¹¼æ¿çç©ä»¶ï¼è䏿¯å¨å½å¼å
§ææå±¬æ§çååç©ä»¶ã
var o = {
a: 2,
m: function () {
return this.a + 1;
},
};
console.log(o.m()); // 3
// å¨é裡å¼å« o.m æãthisãæçæ¯ o
var p = Object.create(o);
// p æ¯åå¾ o ç¹¼æ¿çç©ä»¶
p.a = 4; // å¨ p 建ç«å±¬æ§ãaã
console.log(p.m()); // 5
// å¼å« p.m æãthisãæçæ¯ p
// å æ¤å¨ p ç¹¼æ¿ o çå½å¼ m æï¼
// ãthis.aãæçæ¯ p.aï¼ä¹å°±æ¯ p çèªæå±¬æ§ãaã
ç¢çç©ä»¶åååéçå¹¾ç¨®æ¹æ³
>å«æèªæ³çµæ§çç©ä»¶
var o = { a: 1 };
// æ°å»ºç o æåèªå·±ç [[Prototype]] ç¨±çº Object.prototype
// o èªå·±ä¸¦æ²æç¨±çºãhasOwnPropertyãç屬æ§
// è hasOwnProperty æ¯ Object.prototype çèªæå±¬æ§ã
// å æ¤ o å¾ Object.prototype ç¹¼æ¿äº hasOwnProperty
// Object.prototype ä½çºå
¶ååå¤äºå null
// o ---> Object.prototype ---> null
var a = ["yo", "whadup", "?"];
// å¾ Array.prototype ç¹¼æ¿çé£åï¼å«æè«¸å¦ indexOfãforEachâ¦â¦ä¹é¡çæ¹æ³
// ååéçèµ·ä¾å°±åï¼
// a ---> Array.prototype ---> Object.prototype ---> null
function f() {
return 2;
}
// å¾ Function.prototype ç¹¼æ¿çå½å¼ï¼å«æè«¸å¦ callãbindâ¦â¦ä¹é¡çæ¹æ³
// f ---> Function.prototype ---> Object.prototype ---> null
éé建æ§å
JavaScript 建æ§åï¼å°±ãåªãæ¯ãåã被 new éç®åå¼å«çå½å¼ã
function Graph() {
this.vertices = [];
this.edges = [];
}
Graph.prototype = {
addVertex: function (v) {
this.vertices.push(v);
},
};
var g = new Graph();
// g æ¯åæèãverticesãèãedgesã屬æ§çç©ä»¶ã
// å¨å·è¡ new Graph() æ g.[[Prototype]] æ¯ Graph.prototype çå¼ã
ç¨ Object.create
ECMAScript 5 å¼å
¥äºæ°æ¹æ³ï¼Object.create()ãå¼å«éåæ¹æ³å°±å¯ä»¥å»ºç«æ°çç©ä»¶ãéåç©ä»¶çååï¼çºå½å¼ç第ä¸å忏ã
var a = { a: 1 };
// a ---> Object.prototype ---> null
var b = Object.create(a);
// b ---> a ---> Object.prototype ---> null
console.log(b.a); // 1 (inherited)
var c = Object.create(b);
// c ---> b ---> a ---> Object.prototype ---> null
var d = Object.create(null);
// d ---> null
console.log(d.hasOwnProperty);
// undefined, because d doesn't inherit from Object.prototype
使ç¨ééµå class
ECMAScript 2015 å¼å
¥äºæ°çé¡å¥å¯¦åãå管å°é£äºåºæ¼é¡å¥çéç¼è
ä¾èªªï¼éç¨®çµæ§é«ä»¤ä»åæå°çæï¼å®åä¾èä¸ä¸æ¨£ãJavaScript ä¾èæ¯åºæ¼ååçãæ°çééµåå
æ¬ classãconstructorãstaticãextendsãsuperã
"use strict";
class Polygon {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
class Square extends Polygon {
constructor(sideLength) {
super(sideLength, sideLength);
}
get area() {
return this.height * this.width;
}
set sideLength(newLength) {
this.height = newLength;
this.width = newLength;
}
}
var square = new Square(2);
æè½
ååéä¸ç屬æ§çæ¥è©¢æéï¼å¯è½æå°æè½æè² é¢å½±é¿ï¼å°ç¨å¼ç¢¼ä¹å èç¢çæé¡¯åé¡ãå¦å¤ï¼è©¦åå°æ¾ä¸åå¨ç屬æ§ï¼å°±ä¸å®æéæ·æ´åååéã
æ¥èï¼å¨è¿ä»£ç©ä»¶å±¬æ§æï¼æ¯åååéçæè屬æ§é½ææåºä¾ã
è¦æª¢æ¥ç©ä»¶æ¬èº«ææ²ææå®ç屬æ§ãä¹ä¸éè¦æ¥æ¾æ´åååéæï¼ä½ å¿
é 使ç¨ç± Object.prototype ç¹¼æ¿ç hasOwnProperty æ¹æ³ã
console.log(g.hasOwnProperty("vertices"));
// true
console.log(g.hasOwnProperty("nope"));
// false
console.log(g.hasOwnProperty("addVertex"));
// false
console.log(g.__proto__.hasOwnProperty("addVertex"));
// true
å¨ JavaScript è£¡é¢ hasOwnProperty æ¯å¯ä¸è½èçãä¸ä¸éæ·æ´åååéçæ¹æ³ã
註ï¼å¦æåªææª¢æ¥å±¬æ§æ¯å¦çº undefined æ¯ä¸å¤ çã該屬æ§å¯è½åå¨ï¼åªæ¯æ¸å¼è¢«è¨å®çº undefinedã
å£å¯¦åï¼æ´å åççåå
ä¸å常è¦ç誤ç¨ï¼æ¯æ´å
Object.prototype æå
¶ä»å
§å»ºçååã
é種æå·§ç¨±çºç´åè£ä¸ï¼monkey patchingï¼ï¼å®æç ´å£å°è£ï¼encapsulationï¼ãå管æäºåæ¡è¿çæ¡æ¶å¦ Prototype.js æé麼åï¼ä½å®å䏦䏿¯ä»¥é¡å¤ç鿍æºåè½ï¼æäºå §å»ºé¡åç好çç±ã
æ´å
å
§å»ºååçå¯ä¸åççç±ï¼å°±æ¯ååç§»æ¤æ°ç JavaScript 弿çåè½ï¼ä¾å¦ Array.forEachã
示ä¾
B è¦ç¹¼æ¿èª Aï¼
function A(a) {
this.varA = a;
}
// å¨ A.prototype.varA ææ°¸é 被 this.varA 鬼é±ï¼shadowedï¼çæ
æ³ä¸ï¼
// æ varA å
å¨çµ¦å®å½å¼çååå
§ï¼å
¶æç¾©çºä½ï¼
A.prototype = {
varA: null, // é£éä¸è½å çºååå¥é½æ²ä½ï¼å°±æ varA ææ·åï¼
// ä¹è¨±ä»æç®è¦åé
é±èé¡å¥ç空éï¼ä»¥ä¾¿å¯¦è¡æä½³åï¼
// https://developers.google.com/speed/articles/optimizing-javascript#Initializing instance variables
// 妿 varA æ²æéå°æ¯å實ä¾ä½å®ä¸åå§åï¼é£éº¼ä¸å°±è¦è®ææçï¼
doSomething: function () {
// ...
},
};
function B(a, b) {
A.call(this, a);
this.varB = b;
}
B.prototype = Object.create(A.prototype, {
varB: {
value: null,
enumerable: true,
configurable: true,
writable: true,
},
doSomething: {
value: function () {
// override
A.prototype.doSomething.apply(this, arguments); // call super
// ...
},
enumerable: true,
configurable: true,
writable: true,
},
});
B.prototype.constructor = B;
var b = new B();
b.doSomething();
é黿¯ï¼
- åå¥è¢«å®ç¾©å¨
.prototypeã - ä½ ç¨äº
Object.create()ç¹¼æ¿ã
prototype è Object.getPrototypeOf
JavaScript å°é£äºå¾ Java æ C++ å¸éä¾ç人ä¾èªªï¼å¯è½ææé»å°æï¼å çºå®åæ ãæ°¸é æ¯å·è¡çæ ï¼all runtimeï¼ãéå®å ¨æ²æ classãä¸åé½åªæ¯å¯¦ä¾ï¼ç©ä»¶ï¼ãå³ä½¿æ¯ãclassãééµåï¼ä¹åªæ¯å½å¼ç©ä»¶ã
ä½ å¯è½æ©å°±ç¼ç¾æåç function A æååçº prototype çç¹æ®å±¬æ§ãéåç¹æ®å±¬æ§æéé new éç®åéè¡ä¹ãååç©ä»¶çåç
§ï¼æææ°å¯¦ä¾ç [[Prototype]] 屬æ§è¤è£½å°è©²ç©ä»¶å
§é¨ãæ¯æ¹èªªå¨ä½ var a1 = new A() æï¼JavaScript å¨è¨æ¶é«è£¡é¢å»ºç«ç©ä»¶å¾ãéæéè¡å·²ç¶å®ç¾©å¥½ this çå½å¼ A() åï¼æè¨å® a1.[[Prototype]] = A.prototypeã卿¥è訪å實ä¾ç屬æ§åï¼JavaScript é¦å
æç´æ¥æª¢æ¥ç©ä»¶ç實ä¾å±¬æ§æ¯å¦åå¨ãå¦ææ²æï¼å°±æª¢æ¥ [[Prototype]]ãä¹å°±æ¯èªªï¼å¨ prototype å®ç¾©çæ±è¥¿ï¼è½å¤ ææå°å
±äº«çµ¦å實ï¼çè³ï¼å¦ææ³ç話ï¼éå¯ä»¥æ¹è®ä¸¦é¡¯ç¾æ¼ç¾æå¯¦ä¾ä¸ã
å¦ä¸ä¾æç¤ºï¼é¦å
var a1 = new A(); var a2 = new A(); æ¥è a1.doSomething çè©±ï¼æåç
§å° Object.getPrototypeOf(a1).doSomethingï¼ä»æèæ©å°±å®ç¾©å¥½ç A.prototype.doSomething ç¸åï¼ä¾å¦ï¼ Object.getPrototypeOf(a1).doSomething == Object.getPrototypeOf(a2).doSomething == A.prototype.doSomething.
ç°¡èè¨ä¹ï¼prototype éå°åå¥ï¼è Object.getPrototypeOf() åå實ä¾ç¸åã
[[Prototype]] 鿏æ§å°éçµèï¼ä¾å¦èªª a1.doSomething, Object.getPrototypeOf(a1).doSomething, Object.getPrototypeOf(Object.getPrototypeOf(a1)).doSomething 鿍£ï¼ç´å°æ¾åº Object.getPrototypeOf æåå³ nullã
å æ¤ç¶ä½ ï¼
var o = new Foo();
JavaScript å ¶å¯¦æï¼
var o = new Object();
o.[[Prototype]] = Foo.prototype;
Foo.call(o);
æå¶ç¾é樣ï¼
o.someProp;
æï¼å®æª¢æ¥äº o ææ²æ someProp 屬æ§ãå¦ææ²æï¼å°±æª¢æ¥ Object.getPrototypeOf(o).somePropï¼åæ²æå°±æª¢æ¥ Object.getPrototypeOf(Object.getPrototypeOf(o)).somePropï¼ä¾æ¤é¡æ¨ã
çµè«
卿°å¯«è¤éçå¯ç¨ç¨å¼ç¢¼ä¹åï¼çè§£ååç¹¼æ¿æ¨¡åå¾éè¦ãå¦å¤ï¼è«æ³¨æç¨å¼ç¢¼å §ååéçé·åº¦ãå¿ è¦ææç ´å®åï¼ä»¥é¿å æ½å¨çæè½åé¡ãåä¾ï¼é¤éè¦èç JavaScript æ°èªæ³çç¸å®¹æ§ï¼å¦åçµå°ä¸è½æ´å åççååã