上帝說(shuō)要有光!于是有了光。
JavaScript在ES6
之前語(yǔ)法上還沒(méi)有"類",JavaScript的開發(fā)者們?cè)诤诎抵锌嗫嗝鳎罱K有了屬于js風(fēng)格的面向?qū)ο缶幊田L(fēng)格。
面向過(guò)程&面向?qū)ο?/h2>
面向過(guò)程就是分析出解決問(wèn)題所需要的步驟,然后用函數(shù)把這些步驟一步一步實(shí)現(xiàn),使用的時(shí)候一個(gè)一個(gè)依次調(diào)用就可以了。
面向?qū)ο?/strong>是把構(gòu)成問(wèn)題事務(wù)分解成各個(gè)對(duì)象,建立對(duì)象的目的不是為了完成一個(gè)步驟,而是為了描敘某個(gè)事物在整個(gè)解決問(wèn)題的步驟中的行為
例子:大象裝進(jìn)冰箱的問(wèn)題
面向過(guò)程就是分析出解決問(wèn)題所需要的步驟,然后用函數(shù)把這些步驟一步一步實(shí)現(xiàn),使用的時(shí)候一個(gè)一個(gè)依次調(diào)用就可以了。
面向?qū)ο?/strong>是把構(gòu)成問(wèn)題事務(wù)分解成各個(gè)對(duì)象,建立對(duì)象的目的不是為了完成一個(gè)步驟,而是為了描敘某個(gè)事物在整個(gè)解決問(wèn)題的步驟中的行為
如果我們是按這個(gè)命題去思考:大象裝進(jìn)冰箱分幾步?
那這思維就是面向過(guò)程的,偽代碼實(shí)現(xiàn):
// step1:打開冰箱
openFridge();
// step2:把大象塞進(jìn)去
pushIntoFridge(elephant);
// step3:關(guān)閉冰箱
closeFridge();
如果我們這么思考:冰箱是什么,有什么行為?大象是什么? 大象能裝進(jìn)去嗎?
,我們先把冰箱抽象出來(lái),便是面向?qū)ο?/code>的思維:
//抽象出'類'才是面向?qū)ο蟮闹攸c(diǎn)
class Fridge { //冰箱類
open(){}
close(){}
accommodate(something){}
}
class Elephant {} //大象類
const fridge = new Fridge(); //構(gòu)造一個(gè)冰箱
const elephant = new Elephant(); //構(gòu)造一只大象
fridge.accommodate(elephant); //冰箱裝大象
類與對(duì)象的關(guān)系
類是對(duì)事物的抽象,對(duì)象是類所描述的具體事物。類與對(duì)象的關(guān)系就像汽車設(shè)計(jì)圖與汽車實(shí)車的關(guān)系:
面向?qū)ο?OOP)的編程思維便是基于類與對(duì)象的編程。"面向?qū)ο?在軟件工程的概念中有三個(gè)特征:封裝、繼承、多態(tài)。
- 封裝:即是對(duì)所描述事物的抽象過(guò)程,將其行為和屬性存放于"類";
- 繼承:方便被傳宗接代,父類可以方便的被子類"占有"它的屬性和方法,子類還可以擁有一些父類的沒(méi)有的新技能;
- 多態(tài):同一操作作用于不同的對(duì)象,可以有不同的解釋,產(chǎn)生不同的執(zhí)行結(jié)果。JavaScript由于自身語(yǔ)言的特征,沒(méi)有這一特征。
JavaScript里的"類"
js是基于對(duì)象的語(yǔ)言,里面的任何東西幾乎都是對(duì)象。例如:
var arr = [1,2]; //字面量寫法,實(shí)際上等同于:var arr = new Array(1, 2);
console.log(arr);
數(shù)組類型的變量實(shí)際上是一個(gè)Array
類的實(shí)例。我們所熟知的Object
類型數(shù)據(jù)、window
、document
、DOM節(jié)點(diǎn)都是對(duì)象。
類
js在實(shí)現(xiàn)"類"時(shí)是用的構(gòu)造函數(shù)
或者使用關(guān)鍵字class
(ES6新增),構(gòu)造函數(shù)
的編寫就是上述特征之一的封裝
。
原型與原型鏈
JavaScript的"類"有一個(gè)對(duì)象叫"原型",在類的屬性prototype
可訪問(wèn)到,原型
可定義該類所有實(shí)例(對(duì)象)所擁有的方法和屬性,所以我經(jīng)常們可以把實(shí)例所共有的屬性或方法存在prototype
屬性(下面會(huì)談到)。
我們還是以"汽車"為例來(lái)解釋,那么在代碼中如何描述"汽車"?從國(guó)產(chǎn)某車企李總的話中有感而發(fā):
汽車就是四個(gè)輪子加兩個(gè)沙發(fā)
另外,汽車肯定是會(huì)跑的。所以js的簡(jiǎn)單實(shí)現(xiàn)"汽車"的類如下:
// ES5寫法(Es5和ES6選其一寫法)
function Car(){
this.wheel = 4;
this.safa = 2;
}
Car.prototype.drive = function(){
console.log('Wow~')
}
//ES6寫法 (js終于有真正的"類"了)
class Car {
constructor() {
this.wheel = 4;
this.safa = 2;
}
drive(){
console.log('Wow~')
}
}
現(xiàn)在"造"一輛車并讓它"跑"起來(lái):
var car = new Car();
console.log(car); // => Car {wheel: 4, safa: 2}
car.drive(); // =>'Wow~'
再來(lái)看一下打印出來(lái)的"car"對(duì)象可以發(fā)現(xiàn)他還有個(gè)屬性__proto__
:
在絕大多數(shù)瀏覽器里對(duì)象的__proto__
屬性所指向的對(duì)象便是Car
類的原型,也就是:
car.__proto__ === Car.prototype; // => true
Car
的原型里有我們上面定義的"drive"方法,以及有constructor
屬性用來(lái)表明類的構(gòu)造函數(shù)。
需要注意的它還有個(gè)__proto__
,這個(gè)如何解釋?
上面說(shuō)到原型本身也是對(duì)象,是對(duì)象就有原型,然后就形成了原型鏈,原型鏈的末端是null
:
//Car類的原型指向是Object類的原型,
//也就是說(shuō)car的原型對(duì)象是Object的實(shí)例,說(shuō)起來(lái)有點(diǎn)繞...
car.__proto__.__proto__ === Object.prototype; // => true
// 原型鏈的結(jié)尾
car.__proto__.__proto__.__proto__ // => null
他們的關(guān)系如下圖:
感謝閱讀!歡迎評(píng)論一起探討。