嚴格來說, JS 並不是一個物件導向的語言, 類似 Java, Python, C++ 這樣的. JS 的獨特精妙的設計其實是 原型 prototype
因此這裡講一嘴物件導向其實是為了後面引出原型的東西.
總之, JS 的物件導向 (封裝, 繼承, 多型) 並不真正存在, 但可以巧用 prototype
近似實現而已.
後來看作者自己說之所以搞這麼一通主要也是為了靠近和迎合一下 Java 而已. 但 JavaScript 和 Java 除了名字有點像, 其他哪裡都不像, 完全是兩個領域的東西.
new 呼叫函式 4 步走
在 js 中函式的呼叫大致有好幾種常見的, 如 函式宣告呼叫, 匿名函式呼叫, 物件.方法呼叫, call 和 apply 呼叫. 而這裡將要說的一種呼叫是透過 new
來呼叫函式.
new 函式()
注意這裡的 new
和其他物件導向的語言不太一樣, 並非是 new 一個物件這麼簡單哦, 但這裡呢還是從規則和語法層面先了解再說吧, 它主要會進行 "四步走":
- 函式體內會自動建立一個空物件
{}
- 函式的上下文 (
this
) 會指向這個空物件 - 函式體內的語句會執行
- 函式會自動返回上下文
this
不論函式是否有return
function fn() {
this.a = 1
this.b = 2
}
var obj = new fn()
console.log(obj);
這裡就用了 new 來呼叫函式, 咱們就仔細來分析一波這個過程吧.
// 第一步: 建立空物件
var obj = {}
// 第二步: this 指向這個空物件
this = obj
// 第三步: 函式體內的語句執行
obj = { a: 1, b: 2}
// 第四步: 函式自動返回 this
return this
因此上例 new 呼叫函式()
程式的執行結果就是返回一個物件, { a: 1, b: 2 }. 這個 new 來呼叫函式會自動返回一個物件, 且會執行一些邏輯就還是有點東西的哦.
建構函式
就是類建立時的一些自動呼叫的方法呀, 初始化啥的, 即 Java 類裡面的同類名一致的方法實現, 或者是 Python 類裡面的 def __ init __
它的內部語句會給剛建立的物件 (例項化) 新增若干屬性和方法, 助力其完成物件的初始化.
在 JS 中建構函式必須要透過 new
進行呼叫, 開發者們也約定建構函式命名時首字母要大寫.
當然咱不遵守約定就小寫也是行的, 只是有點不講武德而已.
function People(name, age, sex) {
this.name = name
this.age = age
this.sex = sex
}
var youge = new People('油哥', 28, '男')
var yaya = new People('亞亞', 18, '女')
- 建構函式的關鍵在於
new
關鍵字呼叫, 而非是否函式首字母大小寫 - 建構函式中的
this
指向例項物件而非函式本身
接著嘗試給物件新增一下方法看看:
function People(name, age, sex) {
this.name = name
this.age = age
this.sex = sex
this.sayHi = function () {
console.log('我是: ', this.name, '今年: ', this.age, '歲啦!');
}
}
var youge = new People('油哥', 28, '男')
var yaya = new People('亞亞', 18, '女')
youge.sayHi()
yaya.sayHi()
PS C:\Users\Administrator\Desktop> node test.js
我是: 油哥 今年: 28 歲啦!
我是: 亞亞 今年: 18 歲啦!
類與例項
上面所談的關於 JS 中透過建構函式便基本實現了物件導向的一些核心要素. 比如在寫建構函式 People
時, 我們用的核心思想是 抽象
. 然後再透過 new 函式()
的四步走時, 建立了新物件, 新增了一些屬性和方法, 則實現了 封裝
和進行例項化.
計算機其實就是對現實世界的抽象. 裡面的類和例項也對應著現實世界中的 "歸類 和 個體".
從程式語言來看呢, Java, C++, Python 是物件導向的 OO 語言, 而 JavaScript 是基於物件 object-based
的語言. JS 中的建構函式可以類比於物件導向裡面的 class
. 但二者的實現邏輯是完全不同的. JS 的獨特之處是基於原型 prototype
的設計哦.
當然在 ES6
以後 JS 也引入了一個 class
的關鍵字 和建構函式 constructor
來模擬純面嚮物件語言的特性, 如繼承. 但本質上還是基於原型鏈來展開的.
關於建構函式和類的簡單認知就差不多了, 核心還是為了引出 JS 原型 這個有點牛的東西.