深入理解JavaScript 中的class | IT人
文章推薦指數: 80 %
深入理解JavaScript 中的class(類) 學習內容: 1、 掌握ES6中建立類和物件的方式2、 掌握ES6中類的繼承3、 掌握ES6中靜態方法的使用和呼叫4、 ...
Togglenavigation
IT人
IT人
深入理解JavaScript中的class
w.rogue發表於
2020-12-26
JavaScript
深入理解JavaScript中的class(類)
學習內容:
1、掌握ES6中建立類和物件的方式2、掌握ES6中類的繼承3、掌握ES6中靜態方法的使用和呼叫4、理解ES6中例項化物件的原理
一、ES5:function
1、建構函式
封裝、繼承、多型是大多OOP語言都支援的特性,而JavaScript在ES5中沒有提出真正意義上的類、繼承的概念。
它通過函式首字母大寫的方式告知開發者這是一個建構函式或者類(有些人會將它理解為類),但從嚴格意義上來講,它是建構函式。
這對於初學者來說,看起來是非常腦溢血的。
比如下方code:
//建構函式
functionPerson(name,age){
//例項屬性
this.name=name;
this.age=age;
//例項方法
this.speak=function(){
console.log(`你好,我的名字叫${this.name},今年${this.age}歲了。
`)
}
}
//例項化物件,並傳入引數
letfather=newPerson("張三",20);
//呼叫例項屬性
console.log(father.name);
//呼叫例項方法
father.speak();
如同上方code所示,我們通過function關鍵字+首字母大寫的方式告知開發者,這不是普通的函式,而是一個特殊的函式—建構函式。
如果首字母小寫則將變成一個普通函式,意義就立馬改變了。
並且它們的呼叫方式也不同,普通函式就是以函式的方式呼叫函式名();,而建構函式可以以這樣的方式呼叫,同時也可以使用new關鍵字來例項化物件。
2、靜態方法
在大多數OOP語言中,靜態基本上都是為了共享資料,以減少例項物件所造成的記憶體消耗。
但是ES5中並沒有提出相對明確的靜態方法。
但是,我們可以通過原型物件來實現靜態方法。
比如下方code:
//建構函式
functionFather(name){
//例項屬性
this.name=name;
//例項方法
this.run=function(){
console.log(`我叫${this.name},我會跑!`)
}
}
//靜態屬性
Father.age=20;
//給Father建構函式的原型中新增方法
Father.prototype={
//重新指向建構函式
constructor:Father,
//原型方法
speak:function(){
console.log("我會說話!");
},
run:function(){
console.log("我會跑!");
}
};
//例項化物件
varfather=newFather("張三");
//呼叫靜態屬性
consloe.log(Father.age);
//呼叫原型方法
father.speak();
在上述code中,我們通過給建構函式的原型以物件的賦值,並將指標重新指向建構函式的方式來給建構函式新增靜態方法,而靜態屬性我們使用建構函式名.屬性名=屬性值;的方式實現,呼叫的時候使用建構函式名.屬性名;的方式呼叫。
3、繼承
在大多數OOP語言中,繼承基本上都是為了減少code冗餘,提高code的可讀性和靈活性以及可維護性而存在的。
但是JavaScript在ES5中並沒有提出相對明確的繼承概念。
但是在ES5中,我們可以通過原型鏈和一些方法來實現真正意義上的繼承。
比如下方code:
//基類建構函式
functionFather(name,age){
//例項屬性定義在建構函式內部
this.name=name;
this.age=age;
//判斷原型中的該屬性是否是函式型別的,也就是判斷原型中是否有該方法
if((typeofFather.prototype.speak)!=="function"){
//方法定義在原型中
Father.prototype.speak=function(){
console.log(`我叫${this.name},今年${this.age}歲了`)
}
}
}
//派生類建構函式
functionSon(name,age,sex){
//呼叫基類的建構函式,相當於把基類中的屬性新增到未來的派生來例項物件中
//將Father基類中的this指向改變為son的例項,並將基類所需要的引數傳遞
Father.call(this,name,age);
//例項物件屬性
this.sex=sex;
}
//修改派生類的原型,這樣就可以繼承基類原型中的方法
Son.prototype=newFather();
//例項化son,並將基類所需要的引數一併傳遞
varson=newSon("小明",20,"男");
console.log(son.name);
console.log(son.age)
son.speak();
在上述code中,我們可以看出派生類通過Son.prototype=newFather();更改派生類原型為基類例項的方式來繼承基類中的屬性和方法,而通過Father.call(this,name,age);修改this指向來呼叫基類的例項屬性和方法,將其變成派生類例項的屬性和方法,假如例項物件中有與原型同名的屬性和方法則預設替換。
在ES5中它是以這樣的原理來實現繼承的。
但是在實際開發中,以這樣的方式實現靜態、繼承確實是有些麻煩,於是乎JavaScript在ES6中正式提出了class(類)、constructor(建構函式)、extends(繼承)、static(靜態)的概念。
二、ES6:class
2015年6月JavaScript正式釋出ES6版本,並且最重要的特點之一就是,引入了class的概念,使全球js開發者收益,使得js開發者終於告別了,直接使用原型物件模仿物件導向中的類和類繼承的時代。
但是js中並沒有一個真正的class原始型別,class僅僅只是對原型物件運用的語法糖。
所以,只有理解如何使用原型物件實現類和類繼承,才能真正地用好class。
那麼先上code讓大家體驗一下:
classPerson{
//建構函式
constructor(age){
this.age=age;
};
//靜態方法
staticspeak=function(age){
console.log(`我的名字叫${Person.uName},今年${age}歲了`)
};
}
//靜態屬性
Person.uName="你好";
//例項化物件
varfather=newPerson(20);
//呼叫屬性和方法
console.log(Person.uName);
Person.speak(father.age);
//試圖修改靜態屬性,但是不可以
Person.name="小明";
console.log(Person.uName);
我們看到出現了一個個新的關鍵字,關鍵字class用於宣告一個類,關鍵字constructor用於宣告建構函式,關鍵字static用於宣告靜態方法,而靜態屬性則於ES5中一樣,同樣只能寫在類的外邊。
並且靜態屬性和方法不能被例項物件所呼叫,只能被類所呼叫。
ES6的語法很簡單,並且也很容易理解。
但是在例項化的背後,究竟是什麼在起作用呢?
三、class例項化背後的原理
使用class的語法,讓開發者告別了使用prototype原型物件模仿物件導向的時代。
但是,class並不是ES6引入的全新概念,它的原理依舊是原型物件和原型鏈。
我們前邊不是學習了測試資料型別的知識嘛,那麼我們是不是就可以使用typeof來檢測類的型別,請看下方code:
//宣告一個類
classPerson{
//建構函式
constructor(age){
this.age=age;
};
//靜態方法
staticspeak=function(age){
console.log(`我的名字叫${Person.uName},今年${age}歲了`)
};
}
//靜態屬性
Person.uName="你好";
//例項化物件
varfather=newPerson(20);
//測試Person的型別
console.log(typeofPerson);
通過typeof資料型別測試,我們驚奇的發現,class並非什麼全新的資料型別,它實際上只是function函式型別。
為了能夠更加直觀的瞭解Person類,我們可以將它的例項物件在控制檯上輸出,結果如下:
我們發現Person例項物件的屬性並不多,除去內建屬性外,大部分屬性根據名字都能明白它的作用。
其中需要我們關注的兩個屬性是prototype原型物件和__proto__例項物件的原型。
相信大家肯定會問:不是ES5中的原型和原型鏈嘛?沒錯,這就是原型物件。
也就是說使用class建立物件的方式就是隱式的使用原型物件和原型鏈。
分析:
1. ES6中`宣告類和建構函式`其實就等於ES5中使用`function`宣告的建構函式
2. 而靜態方法和靜態屬性其實就是在原型物件中設定的屬性和方法
3. 在例項化物件的時候,瀏覽器自動建立了一個物件(原型物件),並且將該物件所屬類的建構函式與原型物件繫結,或者說原型物件記錄了建構函式的引用並指向了建構函式,而建構函式的`prototype`屬性指向了原型物件
4. 當通過例項屬性呼叫靜態屬性和方法的時候,例項屬性的`__proto__`屬性又指向了原型物件
5. 那麼這無疑是ES5中建構函式、例項物件與原型物件的三角關係
**溫馨提示:**如果有看不懂的朋友,請看博主上兩篇博文,詳細講解了原型物件和基與原型物件的繼承。
四、繼承
在傳統物件導向中(ES5物件導向),類是可以繼承類的,這樣派生類就可以使用基類中的屬性和方法,來達到code複用的目的。
當然,ES6中也可以實現繼承。
ES6中明確提出了類的繼承語法,即使用extends關鍵字,並使用super()方法呼叫基類的建構函式。
其實super()類似於call()中的借調繼承。
請看下方code:
//基類
classAnima{
constructor(name,age){
this.name=name;
this.age=age;
}
say(){
console.log(`我的名字叫${this.name},今年${this.age}歲了`);
}
}
//派生類繼承基類
classDogextendsAnima{
constructor(name,age,sex){
//呼叫基類的構造
super(name,age)
//例項成員
this.sex=sex;
//靜態成員
Dog.color="紅色";
//靜態方法
Dog.run=function(){
console.log("我想睡覺");
}
}
//方法重寫
say(){
console.log(`我的名字叫${this.name},今年${this.age}歲了,顏色是${Dog.color}`);
}
}
vardog=newDog("大黃",18,"男");
dog.nm="哈哈"
dog.say()
Dog.run();
console.log(dog);
console.log(Dog);
實際上ES6中的繼承與ES5中的繼承原理是一樣的,其本質都是基與原型物件和原型鏈的繼承。
五、物件常用方法
Object.key(物件):獲取當前物件中的屬性名,並返回一個包含所有屬性名的陣列。
Object.defineProperty():該方法用於設定、修改、新增物件中的屬性
Object.defineProperty(物件,修改或新增的屬性名,{
value:修改或新增的屬性的值,
writable:true/false,//如果值為false不允許修改這個屬性值
enumerable:false,//enumerable如果值為false則不允許遍歷
configurable:false//configurable如果為false則不允許刪除這個屬性屬性是否可以被刪除或是否可以再次修改特性
})
體驗:
//基類
classAnima{
constructor(name,age){
this.name=name;
this.age=age;
}
say(){
console.log(`我的名字叫${this.name},今年${this.age}歲了`);
}
}
//派生類繼承基類
classDogextendsAnima{
constructor(name,age,sex){
//呼叫基類的構造
super(name,age);
//例項成員
this.sex=sex;
//靜態成員
Dog.color="紅色";
//靜態方法
Dog.run=function(){
console.log("我想睡覺");
}
}
//方法重寫
say(){
console.log(`我的名字叫${this.name},今年${this.age}歲了,顏色是${Dog.color}`);
}
}
//例項化dog物件
vardog=newDog("大黃",18,"男");
//設定dog物件中的sex屬性
Object.defineProperty(dog,"sex",{
value:"小明",
writable:false,
enumerable:false,
configurable:false
});
//試圖修改,但是並不能修改
dog.sex="女";
//列印的還是小明
console.log(dog.sex);
//以陣列的形式獲取物件中所有物件的屬性
//注意:由於我們上邊設定sex屬性不可遍歷,所以無法通過key()方法獲取到sex屬性,因為key()方法的原理是通過遍歷查詢的
console.log(Object.keys(dog));
六、總結
雖然ES5中,class(類)的繼承和靜態方法要比ES5中的語法簡單,好理解。
但是js中並沒有一個真正的class原始型別,class僅僅只是對原型物件運用的語法糖。
簡單來說,js中不管是ES5還是ES6中的繼承和靜態方法的實現都是基與原型物件和原型鏈實現的。
所以,只有理解ES5中如何使用原型物件實現類和類繼承,才能真正地用好ES6中的class。
希望大家不要因為ES6的語法簡單而忽略ES5中的知識。
不管是ES6也好,ES7也罷,基本上都是基與ES5來封裝實現的,所以希望各位博友能夠先學好ES5。
同時也希望大家能夠廣集意見,如果博主有說的不對的地方還請給位博友糾正。
當然如果還有不懂的地方,博主也會給大家詳細解釋。
最後感謝各位博友的支援,以及感謝CSDN能夠提高這樣好的一個平臺,謝謝!
相關文章
springboot啟動時報異常Classnotfoundsoassumingcodeisrunningonapre-Java9JVM
2020-12-22
JavaJVMSpring
JavaScript預編譯原理,引擎,作用域
2020-12-22
JavaScript
Zero-shotLearning零樣本學習論文閱讀(一)——Learningtodetectunseenobjectclassesbybetween-classattribute
2020-12-22
【Javascript】淺析JS中閉包的來龍去脈
2020-12-22
JavaScript
JavaScript實現:插入排序!!!
2020-12-23
JavaScript
JavaScript防抖實現
2020-12-24
JavaScript
從零開始手把手教你使用javascript+canvas開發一個塔防遊戲01地圖建立
2020-12-24
JavaScript
現代JavaScript:ES6+中的Imports,Exports,Let,Const和Promise
2020-12-24
JavaScriptES6
關於dom(javascript)
2020-12-24
JavaScript
composer安裝完成輸入命令報錯:Fatalerror:Class‘Phar‘notfoundinC:\\ProgramData\\ComposerSetup\\bin\\compo
2020-12-25
使用網頁前端JavaScript使用RSA對長字串進行加密及測試解密,1024位可對長字串進行
2020-12-25
前端JavaScript加密
簡單介紹下各種JavaScript解析器
2020-12-25
JavaScript
JavaScript獲取css的值
2020-12-25
JavaScriptCSS
javascript函式(5)
2020-12-25
JavaScript
現代JavaScript—ES6+中的Imports,Exports,Let,Const和Promise
2020-12-25
JavaScriptES6
【JavaScript】奇怪的知識void0===undefined為true
2020-12-26
JavaScript
JavaScript實戰02
2020-12-26
JavaScript
JavaScript實現-LeetCode刷題-【對稱二叉樹】-第101題!!!
2020-12-26
演算法JavaScriptLeetCode
2020-12-26JavaScript基本概念5:cookie,sessionStorage和localStorage,0.1+0.2!=0.3怎麼處理,陣列的常用方法,new一個物件的過程,繼承
2020-12-26
JavaScriptCookielocalStorage
【已解決】IDEA2020.3java.lang.UnsupportedClassVersionError
2020-12-26
Java
最新文章
SpringBean如何初始化的
央視新聞《彩3平臺邀請瑪》手機搜狐網
央視新聞《買彩⃞票的app有哪些》手機搜狐網
央視新聞《下載大⃞發彩⃞票APP》手機搜狐網
央視新聞《一分快速三正規信譽平臺》手機搜狐網
央視新聞《團隊精準人工計劃》手機搜狐網
央視新聞《有什麼彩⃞票正規大平臺》手機搜狐網
央視新聞《快三計劃軟體哪個最準最穩》手機搜狐網
央視新聞《全網最高彩⃞票平臺》手機搜狐網
央視新聞《大⃞發彩⃞票最新版app下載》手機搜狐網
央視新聞《天天中彩⃞票app官方版下載》手機搜狐網
HertzBeat赫茲節拍v1.0.beta.6釋出,Linux監控來啦
延伸文章資訊
- 1深入理解JavaScript 中的class | IT人
深入理解JavaScript 中的class(類) 學習內容: 1、 掌握ES6中建立類和物件的方式2、 掌握ES6中類的繼承3、 掌握ES6中靜態方法的使用和呼叫4、 ...
- 2Class 基本语法 - 现代JavaScript 教程
- 3[JS] JavaScript 類別(Class) | PJCHENder 未整理筆記
在實例中取用不存在的變數時會得到 undefined 。 ES6 Class. 在ES6 中可使用關鍵字 class 和 constructor(self) :.
- 4吃一顆Class 語法糖(上) - iT 邦幫忙- iThome
必須再次強調,JavaScript 的class 用法與其他class-based OOP 語言中的class 並不相同!雖然乍看寫法類似,但在JS 中的class 還是以原型prototype...
- 5JavaScript | ES6 中最容易誤會的語法糖Class - 基本用法
在JavaScript 的Prototype-Based 物件導向中,不區分Class 和Object 所有的東西都可以是Object ,. 且不一定需要經過Class 或Constructor...