一、類與實(shí)例
1. 類的聲明
- 傳統(tǒng)function類的聲明
function Animal() {
this.name = 'name';
}
- ES6中的class聲明
class Animal2 {
//構(gòu)造函數(shù)
constructor (){
this.name = name;
}
}
1.1 ES6 class與ES5 function的區(qū)別:
Class的特點(diǎn):
Class在語法上更加貼合面向?qū)ο蟮膶懛?br> Class實(shí)現(xiàn)繼承更加易讀俺孙,更加容易理解
更易于寫Java等后端語言的使用
本質(zhì)還是是語法糖,使用prototype
- 重復(fù)定義
- function會覆蓋之前定義的方法
- class會報(bào)錯
- 構(gòu)造器 constructor
- 在function定義的構(gòu)造函數(shù)中疏橄,其prototype.constructor屬性指向構(gòu)造器自身
- 在class定義的類中负饲,constructor也相當(dāng)于定義在prototype屬性上
- 原型或者類中方法的枚舉
-
class
中定義的方法不可用Object.keys(Point.prototype)
枚舉到 -
function
構(gòu)造器原型方法可被Object.keys(Point.prototype)
枚舉到呼股,除了constructor
- 所有原型方法屬性都可用
Object.getOwnPropertyNames(Point.prototype)
訪問到 - 不管是
class
還是function
,constructor
屬性默認(rèn)不可枚舉
2. 生成實(shí)例
如何通過類實(shí)例類的對象
console.log(new Animal(), new Animal2());
注:如果構(gòu)造函數(shù)沒有聲明的話晨川,new函數(shù)名后面的括號可以省略
二证九、類與繼承
2.1 如何實(shí)現(xiàn)繼承
2.2 繼承的幾種方式
- 借助構(gòu)造函數(shù)實(shí)現(xiàn)繼承
原理:在子類的函數(shù)體內(nèi)執(zhí)行父類,用call和apply都可以改變函數(shù)運(yùn)行的上下文共虑,導(dǎo)致父類執(zhí)行的實(shí)例都會掛載到子類上面愧怜。
function Parent1 () {
this.name = 'parent1';
}
Parent1.prototype.say = function () {};/*new Child1().say() 報(bào)錯*/
function Child1 () {
Parent1.call(this);/*apply也可以改變函數(shù)運(yùn)行的上下文*/
this.type = 'child1';
}
控制臺輸出:
console.log(new Child1);
缺點(diǎn):構(gòu)造函數(shù)除了函數(shù)體里面的內(nèi)容,還可能有原型鏈上的妈拌,但是這種方式中構(gòu)造函數(shù)原型鏈上的東西并沒有被繼承拥坛。
擴(kuò)展學(xué)習(xí):javascript中apply、call和bind方法的區(qū)別
- 借助原型鏈實(shí)現(xiàn)繼承(彌補(bǔ)構(gòu)造函數(shù)繼承不足)
function Parent2() {
this.name = 'parent2';
this.play = [1, 2, 3];
}
function Child2() {
this.type = 'child2';
}
Child2.prototype = new Parent2();
//缺點(diǎn)
console.log(new Child2());
var o1 = new Child2();
var o2 = new Child2();
console.log(o1.play, o2.play);//都為1,2,3
o1.play.push(4);//將o1重新復(fù)制
console.log(o1.play, o2.play);//都為1,2,3,4
實(shí)現(xiàn)原理:低級構(gòu)造函數(shù)的原型是高級構(gòu)造函數(shù)的實(shí)例尘分,new Child2().__proto__
就是Parent2
父類的一個實(shí)例對象猜惋。即new Child2().__proto__ === Parent2.prototype
為true
。new Child2().__proto__.name
的值為parent2
培愁。
缺點(diǎn):因?yàn)樵玩溨械脑褪?strong>共用的著摔,所以兩個對象不隔離。改變一個影響另一個定续。o1.__proto__ = o2.__proto__
谍咆。
- 組合繼承方式(構(gòu)造函數(shù)+原型鏈)
function Parent3() {
this.name = 'Parent3';
this.play = [1, 2, 3];
}
function Child3() {
Parent3.call(this);
this.type = 'Child3';
}
Child3.prototype = new Parent3();
//檢驗(yàn)
console.log(new Child3());
var o1 = new Child3();
var o2 = new Child3();
o1.play.push(4);
console.log(o1.play, o2.play);//這時候結(jié)果就不一樣了 分別是 [1,2,3,4] [1,2,3]
缺點(diǎn):實(shí)例化子類的時候父類構(gòu)造函數(shù)執(zhí)行兩次。是沒有必要的私股。
- 組合繼承優(yōu)化一
function Parent4() {
this.name = 'Parent4';
this.play = [1, 2, 3];
}
function Child4() {
Parent4.call(this);
this.type = 'Child4';
}
Child4.prototype = Parent4.prototype;
console.log(new Child4());
var o1 = new Child4();
var o2 = new Child4();
o1.play.push(4);
console.log(o1.play, o2.play);
console.log(o1 instanceof Child4, s5 instanceof Parent4);//true, true
console.log(o1.constructor);
怎么區(qū)分摹察,是否是直接實(shí)例化的?
直接拿的父類實(shí)例
- 組合繼承優(yōu)化二
function Parent5() {
this.name = 'Parent5';
this.play = [1, 2, 3];
}
function Child5() {
Parent5.call(this);
this.type = 'Child5';
}
Child5.prototype = Object.create(Parent5.prototype);
創(chuàng)建中間對象倡鲸,完美~
2.3 Class和普通構(gòu)造函數(shù)實(shí)現(xiàn)繼承對比
Class實(shí)現(xiàn)(ES6)
class Animal {
constructor(name) {
this.name = name
}
eat() {
console.log(`${this.name} eat`)
}
}
class Dog extends Animal {
constructor(name) {
super(name)
this.name = name
}
say() {
console.log(`${this.name} say`)
}
}
const dog = new Dog('husky')
dog.say()
dog.eat()
普通構(gòu)造函數(shù)實(shí)現(xiàn)
function Animal() {
this.eat = function () {
alert('Animal eat')
}
}
function Dog() {
this.bark = function () {
alert('Dog bark')
}
}
Dog.prototype = new Animal()
var husky = new Dog()
husky.bark()
husky.eat()