類
ES6
引入了Class
(類)這個(gè)概念,作為對(duì)象的模板迂苛,通過(guò)class
關(guān)鍵字三热,可以定義類。
class Point {
constructor(x,y) {
this.x = x;
this.y = y;
}
}
- 類的數(shù)據(jù)類型就是函數(shù)三幻,類本身就是指向構(gòu)造函數(shù)就漾。
- 使用的時(shí)候,也是直接對(duì)類使用
new
命令念搬,跟構(gòu)造函數(shù)的用法完全一致抑堡。 - 在
ES6
中,類的所有方法都定義在類的prototype
屬性上面锁蠕。
class Point {
constructor () {
// do sth
}
toValue () {
// do sth
}
}
// 等同于
Point.prototype = {
construcror () {},
toValue () {}
}
- 在類的實(shí)例上面調(diào)用方法夷野,其實(shí)就是調(diào)用原型上的方法。
class B ()
let b = new B();
b.constructor === B.prototype.constructor; // true
-
prototype
對(duì)象的constructor
屬性荣倾,直接指向“類”的本身悯搔。
class MyPoint{
constructor(props){
this.x = props.x;
this.y = props.y;
}
}
var myPoint = new MyPoint({x:1,y:2});
myPoint.constructor === MyPoint; // => true
MyPoint.prototype.constructor === MyPoint; // => true
- 類的內(nèi)部所有定義的方法,都是不可枚舉的。(non-enumerable)
class MyPoint {
constructor(props) {
this.x = props.x;
this.y = props.y;
}
sum() {
console.log(this.x + this.y);
}
}
var myPoint = new MyPoint({
x: 1,
y: 3
});
myPoint.sum(); // => 4
var keys = Object.keys(MyPoint.prototype);
console.log(keys); // => []
constructor 方法
constructor
方法是默認(rèn)方法妒貌,通過(guò)new
命令生成對(duì)象實(shí)例時(shí)通危,自動(dòng)調(diào)用該方法,一個(gè)類必須有constructor
方法灌曙,如果沒(méi)有顯示定義菊碟,一個(gè)空的constructor
方法會(huì)被默認(rèn)添加。
class MyPoint {
}
// 等同于
class MyPoint {
constructor(){}
}
-
js
引擎會(huì)自動(dòng)為它添加一個(gè)空的constructor
方法在刺。 -
constructor
方法默認(rèn)返回實(shí)例對(duì)象(即this
)逆害,完全可以指定返回另外一個(gè)對(duì)象
class Foo{
constructor(){
var p = {x:'scp'};
return Object.create(p); // 返回一個(gè)全新的對(duì)象
}
}
// 實(shí)例對(duì)象不是Foo類的實(shí)例
console.log(new Foo instanceof Foo); // => false
// 查詢實(shí)例對(duì)象的原型對(duì)象是 上邊定義的 p
console.log(Object.getPrototypeOf(new Foo)); // => {x:"scp"}
類的實(shí)例
- 類必須使用
new
調(diào)用,否則會(huì)報(bào)錯(cuò) - 實(shí)例的屬性除非顯式定義在其本身(即定義在
this
對(duì)象上)蚣驼,否則都是定義在原型上(即class
上)
class MyPoint {
constructor(props) {
this.x = props.x;
this.y = props.y;
}
sum() {
console.log(this.x + this.y);
}
}
var myPoint = new MyPoint({
x: 1,
y: 3
});
console.log(myPoint.hasOwnProperty('x')); // => true
console.log(myPoint.hasOwnProperty('sum'));// => false
console.log(myPoint.__proto__.hasOwnProperty('sum')); // => true
如上魄幕,x
是實(shí)例對(duì)象myPoint
自身的屬性,sum
是定義在原型對(duì)象上的屬性
繼承
Class
可以通過(guò) extends
關(guān)鍵字實(shí)現(xiàn)繼承
ChildrenPoint
中的constructor
方法中出現(xiàn)的super
關(guān)鍵字表示父類的構(gòu)造函數(shù)颖杏,用來(lái)新建父類的this
對(duì)象纯陨。子類必須在
constructor
中調(diào)用super
方法,否則新建實(shí)例時(shí)會(huì)報(bào)錯(cuò)留储,這是因?yàn)樽宇愖约旱?code>this對(duì)象翼抠,必須先通過(guò)父類的構(gòu)造函數(shù)完成塑造,得到與父類同樣的實(shí)例屬性和方法获讳,然后再對(duì)其進(jìn)行加工阴颖,加上子類自己的實(shí)例屬性和方法,如果不調(diào)用super
方法赔嚎,子類就得不到this
對(duì)象膘盖。在子類構(gòu)造函數(shù)中,只有調(diào)用
super
之后尤误,才可以使用this
關(guān)鍵字否則報(bào)錯(cuò),這是因?yàn)樽宇悓?shí)例的構(gòu)建结缚,基于父類實(shí)例损晤,只有super
方法才能調(diào)用父類實(shí)例。ES6
的繼承機(jī)制红竭,實(shí)質(zhì)是先將父類實(shí)例對(duì)象的屬性和方法尤勋,加到this
上面(所以必須先調(diào)用super
方法),然后再用子類的構(gòu)造函數(shù)修改this
茵宪。
class MyPoint {
constructor(props) {
this.x = props.x;
this.y = props.y;
}
sum(...values) {
console.log(values);
let summation = values.reduce((prev,cur) => prev + cur,0);
console.log(summation);
}
}
// 繼承
class ChildrenPoint extends MyPoint{
constructor(props,cProps){
super(props); // 調(diào)用父類的constructor(props)
this.w = props.w
this.z = cProps.z;
}
}
var cPoint = new ChildrenPoint({x:1,y:2,w:3},{z:4});
cPoint.sum(...Object.values(cPoint)); // => 10
Object.getPrototypeOf()
該方法可以用來(lái)從子類上獲取父類最冰,可以使用這個(gè)方法判定,一個(gè)類是否繼承了另一個(gè)類
console.log(Object.getPrototypeOf(ChildrenPoint) === MyPoint); // => true
super 關(guān)鍵字
-
super
可以當(dāng)做函數(shù)使用稀火,只能在子類的構(gòu)造函數(shù)中暖哨,使用,其它地方報(bào)錯(cuò) -
super
可以當(dāng)做對(duì)象使用 -
super
作為函數(shù)調(diào)用時(shí)凰狞,代表父類的構(gòu)造函數(shù)篇裁,ES6
要求沛慢,子類的構(gòu)造函數(shù)必須執(zhí)行一次super
函數(shù)。 - 子類的構(gòu)造函數(shù)中的
super()
达布,代表調(diào)用父類的構(gòu)造函數(shù)团甲,但是返回的是子類的實(shí)例,即super
內(nèi)部的this
指的是子類的實(shí)例黍聂。
class A()
class B extends A {
constructor() {
super();
}
}
上面代碼躺苦,super()
在這里相當(dāng)于A.prototype.constructor.call(this)
-
super
作為對(duì)象時(shí),在普通方法中产还,指向父類的原型對(duì)象匹厘,在靜態(tài)方法中,指向父類
class MyPoint {
constructor(props) {
this.x = props.x;
}
sum(...values) {
console.log(values);
let summation = values.reduce((prev,cur) => prev + cur,0);
console.log(summation);
}
}
// 繼承
class ChildrenPoint extends MyPoint{
constructor(props,cProps){
super(props); // 調(diào)用父類的constructor(props)
this.y = cProps.y;
}
csum(...values){
super.sum(...values); // super作為對(duì)象使用雕沉,相當(dāng)于MyPoint.prototype
}
}
var cPoint = new ChildrenPoint({x:1},{y:4});
cPoint.sum(...Object.values(cPoint)); // => 10
cPoint.csum(...Object.values(cPoint)); // => 10
上面代碼中集乔,子類ChildrenPoint
當(dāng)中的super.sum(...values)
,就是將super
當(dāng)做一個(gè)對(duì)象使用坡椒,super
在普通方法中扰路,指向MyPoint.prototype
,所以super.sum(...values)
就相當(dāng)于MyPoint.prototype.sum(...values)
因?yàn)?code>super指向父類的原型對(duì)象倔叼,所以定義在父類實(shí)例上的方法或者屬性汗唱,是無(wú)法通過(guò)super
調(diào)用的,比如super.x
就會(huì)輸出undefined
類的 prototype
屬性和__proto__
屬性
- 子類的
__proto__
屬性丈攒,表示構(gòu)造函數(shù)的繼承哩罪,總是指向父類 - 子類的
prototype
屬性的__proto__
屬性,表示方法的繼承巡验,總是指向父類的prototype
class A {
}
class B extends A {
}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true