1. 程式人生 > >js如何面向物件程式設計?(一)類與物件

js如何面向物件程式設計?(一)類與物件

原文:https://www.jianshu.com/u/30146fc58ef8

上帝說要有光!於是有了光。

JavaScript在ES6之前語法上還沒有"類",JavaScript的開發者們在黑暗中苦苦摸索,最終有了屬於js風格的面向物件程式設計風格。

面向過程&面向物件

面向過程就是分析出解決問題所需要的步驟,然後用函式把這些步驟一步一步實現,使用的時候一個一個依次呼叫就可以了。
面向物件是把構成問題事務分解成各個物件,建立物件的目的不是為了完成一個步驟,而是為了描敘某個事物在整個解決問題的步驟中的行為

例子:大象裝進冰箱的問題

如果我們是按這個命題去思考:大象裝進冰箱分幾步?那這思維就是面向過程的,虛擬碼實現:

// step1:開啟冰箱
openFridge();

// step2:把大象塞進去
pushIntoFridge(elephant);

// step3:關閉冰箱
closeFridge();

如果我們這麼思考:冰箱是什麼,有什麼行為?大象是什麼? 大象能裝進去嗎?,我們先把冰箱抽象出來,便是面向物件的思維:

//抽象出'類'才是面向物件的重點
class Fridge { //冰箱類
    open(){}
    close(){}
    accommodate(something){}
}
class
Elephant {} //大象類 const fridge = new Fridge(); //構造一個冰箱 const elephant = new Elephant(); //構造一隻大象 fridge.accommodate(elephant); //冰箱裝大象

類與物件的關係

類是對事物的抽象,物件是類所描述的具體事物。類與物件的關係就像汽車設計圖與汽車實車的關係:

面向物件(OOP)的程式設計思維便是基於類與物件的程式設計。"面向物件"在軟體工程的概念中有三個特徵:封裝、繼承、多型。

  • 封裝:即是對所描述事物的抽象過程,將其行為和屬性存放於"類";
  • 繼承:方便被傳宗接代,父類可以方便的被子類"佔有"它的屬性和方法,子類還可以擁有一些父類的沒有的新技能;
  • 多型:同一操作作用於不同的物件,可以有不同的解釋,產生不同的執行結果。JavaScript由於自身語言的特徵,沒有這一特徵。

JavaScript裡的"類"

js是基於物件的語言,裡面的任何東西幾乎都是物件。例如:

var arr = [1,2]; //字面量寫法,實際上等同於:var arr = new Array(1, 2);
console.log(arr);

陣列型別的變數實際上是一個Array類的例項。我們所熟知的Object型別資料、windowdocument、DOM節點都是物件。

js在實現"類"時是用的建構函式或者使用關鍵字class(ES6新增),建構函式的編寫就是上述特徵之一的封裝

原型與原型鏈

JavaScript的"類"有一個物件叫"原型",在類的屬性prototype可訪問到,原型可定義該類所有例項(物件)所擁有的方法和屬性,所以我經常們可以把例項所共有的屬性或方法存在prototype屬性(下面會談到)。

我們還是以"汽車"為例來解釋,那麼在程式碼中如何描述"汽車"?從國產某車企李總的話中有感而發:

汽車就是四個輪子加兩個沙發

另外,汽車肯定是會跑的。所以js的簡單實現"汽車"的類如下:

// 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~')
    }
}

現在"造"一輛車並讓它"跑"起來:

var car = new Car();
console.log(car); // => Car {wheel: 4, safa: 2}
car.drive(); // =>'Wow~'

再來看一下打印出來的"car"物件可以發現他還有個屬性__proto__

在絕大多數瀏覽器裡物件的__proto__屬性所指向的物件便是Car類的原型,也就是:

car.__proto__ === Car.prototype; // => true

Car的原型裡有我們上面定義的"drive"方法,以及有constructor屬性用來表明類的建構函式。
需要注意的它還有個__proto__,這個如何解釋?
上面說到原型本身也是物件,是物件就有原型,然後就形成了原型鏈,原型鏈的末端是null:

//Car類的原型指向是Object類的原型,
//也就是說car的原型物件是Object的例項,說起來有點繞...
car.__proto__.__proto__ === Object.prototype; // => true

// 原型鏈的結尾
car.__proto__.__proto__.__proto__  // => null

他們的關係如下圖:

感謝閱讀!歡迎評論一起探討。