【js基礎】JavaScript中的面向對象(OOP)

1.對象的概念

首先樹立一個概念:萬物皆對象。JavaScript 中的所有事物都是對象,包括字符串、數(shù)值、數(shù)組、函數(shù)等等。

js中的對象分為內建對象和自定義對象。內建對象是指String、Date、Array等js中內置定義的對象類型。除內建對象外的其他對象為自定義對象。

對象,是帶有屬性和方法的特殊數(shù)據(jù)類型。

2.面向對象

使用對象時,只關注對象提供的功能,不關注其內部細節(jié)。比如電腦——有鼠標、鍵盤,我們只需要知道怎么使用鼠標,敲打鍵盤即可,不必知道為何點擊鼠標可以選中、敲打鍵盤是如何輸入文字以及屏幕是如何顯示文字的??傊覀儧]必要知道其具體工作細節(jié),只需知道如何使用其提供的功能即可,這就是面向對象。

JavaScript的面向對象編程和大多數(shù)其他語言如Java、C#的面向對象編程都不太一樣。如果你熟悉Java或C#,很好,你一定明白面向對象的兩個基本概念:

類:類是對象的類型模板,例如,定義Student類來表示學生,類本身是一種類型,Student表示學生類型,但不表示任何具體的某個學生;

實例:實例是根據(jù)類創(chuàng)建的對象,例如,根據(jù)Student類可以創(chuàng)建出xiaoming、xiaohong、xiaojun等多個實例,每個實例表示一個具體的學生,他們全都屬于Student類型。

所以,類和實例是大多數(shù)面向對象編程語言的基本概念。

不過,在JavaScript中,這個概念需要改一改。JavaScript不區(qū)分類和實例的概念,而是通過原型(prototype)來實現(xiàn)面向對象編程。有關原型的概念和原理下文會提到。

3.對象的基本構成

訪問名稱為ObjectName的對象的屬性:

ObjectName.propertyName

訪問名稱為ObjectName的對象的方法并直接調用該方法:

ObjectName.methodName()

4.對象的創(chuàng)建

原型是指當我們想要創(chuàng)建xiaoming這個具體的學生時,我們并沒有一個Student類型可用。那怎么辦?恰好有這么一個現(xiàn)成的對象:

var robot = {? ?

????name:'Robot',

? ? height:1.6,? ?

????run:function(){

????????console.log(this.name +' is running...');? ?

????}

};

我們看這個robot對象有名字,有身高,還會跑,有點像小明,干脆就根據(jù)它來“創(chuàng)建”小明得了!

于是我們把它改名為Student,然后創(chuàng)建出xiaoming:

var Student = {? ?

????name:'Robot',? ?

????height:1.2,? ?

????run:function()? {

????????console.log(this.name +' is running...');? ?

????}

};

var xiaoming = { name: '小明' };

xiaoming.__proto__ = Student;? //指向原型對象

注意最后一行代碼把xiaoming的原型指向了對象Student,看上去xiaoming仿佛是從Student繼承下來的:

xiaoming.name;? //'小明'

xiaoming.run();? //小明 is running...

xiaoming有自己的name屬性,但并沒有定義run()方法。不過,由于小明是從Student繼承而來,只要Student有run()方法,xiaoming也可以調用。

JavaScript的原型鏈和Java的Class區(qū)別就在于它沒有“Class”的概念,所有對象都是實例,所謂繼承關系不過是把一個對象的原型指向另一個對象而已。


(1) 創(chuàng)建對象的原理

JavaScript對每個創(chuàng)建的對象都會設置一個原型,指向它的原型對象。

當我們用ObjectName.propertyName訪問一個對象的屬性時,JavaScript引擎先在當前對象上查找該屬性,如果沒有找到,就到其原型對象上找,如果還沒有找到,就一直上溯到Object.prototype對象,最后,如果還沒有找到,就只能返回undefined。

現(xiàn)在我們開始創(chuàng)建一個對象:

var arr = [1,2,3];

其原型鏈如下所示:

arr => Array.prototype => Object.prototype => null

在這里,數(shù)組arr是JavaScript的內建對象Array的一個實例,其原型鏈指向Array的prototype。Array本身為一種特殊的對象(即key值為0,1,2,3...的鍵值對),因此Array的原型鏈指向Object的prototype。原型鏈的終點指向null。

由上例啟發(fā),我們再看一下前面提到的xiaoming與Stutent的關系:

對象xiaoming的原型鏈

上圖中,小明作為一個Student的實例(可以理解為xiaoming是學生這個大類下的一個個體),含有一個名為__proto__的原型鏈指針(標準寫法為[[prototype]],許多瀏覽器中為便于區(qū)分顯示為__proto__),該指針指向當前對象的原型的構造器(constructor)。

大多數(shù)情況下,__proto__可以理解為“構造器函數(shù)的原型”,即:__proto__ === constructor.prototype? (通過Object.create()創(chuàng)建的對象不適于此等式)

有些同學可能會有疑問,prototype屬性與__proto__的區(qū)別。兩者的概念上可以這樣理解:prototype屬性是函數(shù)才擁有的屬性,而每一個對象都有一個指向其原型的__proto__屬性,其__proto__屬性在一般情況下指向其原型的constructor(即對象的__proto__指向本對象的構造器)。


prototype屬性與__proto__的區(qū)別??


函數(shù)對象與其原型對象的關系

(2) 對象的原型鏈的理解

JavaScript的原型及原型鏈概念的原理,類似于數(shù)據(jù)結構中的鏈表結構

鏈表是一種物理存儲單元上非連續(xù)、非順序的存儲結構,數(shù)據(jù)元素的邏輯順序是通過鏈表中的指針鏈接次序實現(xiàn)的。鏈表由一系列結點(鏈表中每一個元素稱為結點)組成,結點可以在運行時動態(tài)生成。

相比數(shù)組而言,鏈表在內存中不需要連續(xù)的區(qū)域,只需要每一個節(jié)點都能夠記錄下一個節(jié)點的內存地址,通過引用進行查找,這樣的特點也就造就了鏈表增刪操作時間消耗很小,而查找遍歷時間消耗很大的特點。

鏈表的兩種模式(單向鏈表、雙向鏈表)如下圖:

鏈表的兩種模式。顯然,JS中的原型概念類似于單向鏈表

簡單了解了鏈表結構后,我們現(xiàn)在可以來了解一下JavaScript中的原型鏈與鏈表的區(qū)別了:


單向鏈表與原型鏈的對比:原型鏈多了指向自身的constructor構造函數(shù)

(3) ES6中的Class的理解

前文提到JS中沒有類的概念,是針對ES5而言。在2015年推出的ES6語法中,JS提供了更接近傳統(tǒng)語言的寫法,引入了 class(類)這個概念,作為對象的模板。通過class關鍵字,可以定義類。

傳統(tǒng)的ES5中,定義類似“類”的概念,使用的方法是定義一個構造函數(shù),通過繼承的方式實現(xiàn)“類”的功能:

// 先定義一個函數(shù),強行叫它構造函數(shù),構造函數(shù)常規(guī)建議首字母大寫:

function Student(name, age) {?

????this.name = name;? ?// 構造函數(shù)的屬性都定義在函數(shù)內部

????this.age = age;? ?// this指向實例對象

?}??

// 構造函數(shù)的方法都定義在構造函數(shù)的原型上?

Student.prototype.showHisInfo = function () {?

????return? '(' + this.name + ', ' + this.age + ')';?

};?

// new 一個對象,就OK了

var xiaoming = new Student('小明', 18);?

當使用class時,結構如下:?

class Student{

????constructor(name,age) {? // 構造函數(shù),為類的一部分

????????// 定義將來實例的屬性

????????this.name =?name;?

????????this.age = age;? ?

????}

????// 給類添加方法

????showHisInfo() {

????????return this.name + ','+this.age;? ?// 取到上面兩個屬性值

????}

}

let xiaoming = new Student('小明', 18);


參考文獻:

廖雪峰--面向對象編程:https://www.liaoxuefeng.com/wiki/1022910821149312/1023022126220448

數(shù)據(jù)結構——淺談鏈表:https://blog.csdn.net/weixin_41582192/article/details/81181077

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容