1.對象的概念
首先樹立一個概念:萬物皆對象艇潭。JavaScript 中的所有事物都是對象,包括字符串戏蔑、數(shù)值蹋凝、數(shù)組、函數(shù)等等总棵。
js中的對象分為內(nèi)建對象和自定義對象鳍寂。內(nèi)建對象是指String、Date情龄、Array等js中內(nèi)置定義的對象類型迄汛。除內(nèi)建對象外的其他對象為自定義對象捍壤。
對象,是帶有屬性和方法的特殊數(shù)據(jù)類型鞍爱。
2.面向?qū)ο?/b>
使用對象時鹃觉,只關(guān)注對象提供的功能,不關(guān)注其內(nèi)部細節(jié)硬霍。比如電腦——有鼠標帜慢、鍵盤,我們只需要知道怎么使用鼠標唯卖,敲打鍵盤即可粱玲,不必知道為何點擊鼠標可以選中、敲打鍵盤是如何輸入文字以及屏幕是如何顯示文字的拜轨〕榧酰總之我們沒必要知道其具體工作細節(jié),只需知道如何使用其提供的功能即可橄碾,這就是面向?qū)ο蟆?/p>
JavaScript的面向?qū)ο缶幊毯痛蠖鄶?shù)其他語言如Java卵沉、C#的面向?qū)ο缶幊潭疾惶粯印H绻闶煜ava或C#法牲,很好史汗,你一定明白面向?qū)ο蟮膬蓚€基本概念:
類:類是對象的類型模板,例如拒垃,定義Student類來表示學(xué)生停撞,類本身是一種類型,Student表示學(xué)生類型悼瓮,但不表示任何具體的某個學(xué)生戈毒;
實例:實例是根據(jù)類創(chuàng)建的對象,例如横堡,根據(jù)Student類可以創(chuàng)建出xiaoming埋市、xiaohong、xiaojun等多個實例命贴,每個實例表示一個具體的學(xué)生道宅,他們?nèi)紝儆赟tudent類型。
所以胸蛛,類和實例是大多數(shù)面向?qū)ο缶幊陶Z言的基本概念培己。
不過,在JavaScript中胚泌,這個概念需要改一改。JavaScript不區(qū)分類和實例的概念肃弟,而是通過原型(prototype)來實現(xiàn)面向?qū)ο缶幊嚏枋摇S嘘P(guān)原型的概念和原理下文會提到零蓉。
3.對象的基本構(gòu)成
訪問名稱為ObjectName的對象的屬性:
ObjectName.propertyName
訪問名稱為ObjectName的對象的方法并直接調(diào)用該方法:
ObjectName.methodName()
4.對象的創(chuàng)建
原型是指當我們想要創(chuàng)建xiaoming這個具體的學(xué)生時,我們并沒有一個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也可以調(diào)用。
JavaScript的原型鏈和Java的Class區(qū)別就在于它沒有“Class”的概念抹腿,所有對象都是實例岛请,所謂繼承關(guān)系不過是把一個對象的原型指向另一個對象而已。
(1) 創(chuàng)建對象的原理
JavaScript對每個創(chuàng)建的對象都會設(shè)置一個原型警绩,指向它的原型對象崇败。
當我們用ObjectName.propertyName訪問一個對象的屬性時,JavaScript引擎先在當前對象上查找該屬性房蝉,如果沒有找到僚匆,就到其原型對象上找,如果還沒有找到搭幻,就一直上溯到Object.prototype對象咧擂,最后,如果還沒有找到檀蹋,就只能返回undefined松申。
現(xiàn)在我們開始創(chuàng)建一個對象:
var arr = [1,2,3];
其原型鏈如下所示:
arr => Array.prototype => Object.prototype => null
在這里,數(shù)組arr是JavaScript的內(nèi)建對象Array的一個實例俯逾,其原型鏈指向Array的prototype贸桶。Array本身為一種特殊的對象(即key值為0,1,2,3...的鍵值對),因此Array的原型鏈指向Object的prototype桌肴。原型鏈的終點指向null皇筛。
由上例啟發(fā),我們再看一下前面提到的xiaoming與Stutent的關(guān)系:
上圖中坠七,小明作為一個Student的實例(可以理解為xiaoming是學(xué)生這個大類下的一個個體)水醋,含有一個名為__proto__的原型鏈指針(標準寫法為[[prototype]]旗笔,許多瀏覽器中為便于區(qū)分顯示為__proto__),該指針指向當前對象的原型的構(gòu)造器(constructor)拄踪。
大多數(shù)情況下蝇恶,__proto__可以理解為“構(gòu)造器函數(shù)的原型”,即:__proto__ === constructor.prototype? (通過Object.create()創(chuàng)建的對象不適于此等式)
有些同學(xué)可能會有疑問惶桐,prototype屬性與__proto__的區(qū)別撮弧。兩者的概念上可以這樣理解:prototype屬性是函數(shù)才擁有的屬性,而每一個對象都有一個指向其原型的__proto__屬性姚糊,其__proto__屬性在一般情況下指向其原型的constructor(即對象的__proto__指向本對象的構(gòu)造器)贿衍。
(2) 對象的原型鏈的理解
JavaScript的原型及原型鏈概念的原理,類似于數(shù)據(jù)結(jié)構(gòu)中的鏈表結(jié)構(gòu):
鏈表是一種物理存儲單元上非連續(xù)叛拷、非順序的存儲結(jié)構(gòu)舌厨,數(shù)據(jù)元素的邏輯順序是通過鏈表中的指針鏈接次序?qū)崿F(xiàn)的。鏈表由一系列結(jié)點(鏈表中每一個元素稱為結(jié)點)組成忿薇,結(jié)點可以在運行時動態(tài)生成裙椭。
相比數(shù)組而言,鏈表在內(nèi)存中不需要連續(xù)的區(qū)域署浩,只需要每一個節(jié)點都能夠記錄下一個節(jié)點的內(nèi)存地址揉燃,通過引用進行查找,這樣的特點也就造就了鏈表增刪操作時間消耗很小筋栋,而查找遍歷時間消耗很大的特點炊汤。
鏈表的兩種模式(單向鏈表、雙向鏈表)如下圖:
簡單了解了鏈表結(jié)構(gòu)后,我們現(xiàn)在可以來了解一下JavaScript中的原型鏈與鏈表的區(qū)別了:
(3) ES6中的Class的理解
前文提到JS中沒有類的概念襟交,是針對ES5而言迈倍。在2015年推出的ES6語法中,JS提供了更接近傳統(tǒng)語言的寫法捣域,引入了 class(類)這個概念啼染,作為對象的模板。通過class關(guān)鍵字焕梅,可以定義類迹鹅。
傳統(tǒng)的ES5中,定義類似“類”的概念贞言,使用的方法是定義一個構(gòu)造函數(shù)斜棚,通過繼承的方式實現(xiàn)“類”的功能:
// 先定義一個函數(shù),強行叫它構(gòu)造函數(shù),構(gòu)造函數(shù)常規(guī)建議首字母大寫:
function Student(name, age) {?
????this.name = name;? ?// 構(gòu)造函數(shù)的屬性都定義在函數(shù)內(nèi)部
????this.age = age;? ?// this指向?qū)嵗龑ο?/p>
?}??
// 構(gòu)造函數(shù)的方法都定義在構(gòu)造函數(shù)的原型上?
Student.prototype.showHisInfo = function () {?
????return? '(' + this.name + ', ' + this.age + ')';?
};?
// new 一個對象弟蚀,就OK了
var xiaoming = new Student('小明', 18);?
當使用class時脂新,結(jié)構(gòu)如下:?
class Student{
????constructor(name,age) {? // 構(gòu)造函數(shù),為類的一部分
????????// 定義將來實例的屬性
????????this.name =?name;?
????????this.age = age;? ?
????}
????// 給類添加方法
????showHisInfo() {
????????return this.name + ','+this.age;? ?// 取到上面兩個屬性值
????}
}
let xiaoming = new Student('小明', 18);
參考文獻:
廖雪峰--面向?qū)ο缶幊蹋?a target="_blank" rel="nofollow">https://www.liaoxuefeng.com/wiki/1022910821149312/1023022126220448
數(shù)據(jù)結(jié)構(gòu)——淺談鏈表:https://blog.csdn.net/weixin_41582192/article/details/81181077