一、理解面向物件
- 面向物件程式設計以物件為核心,該方法認為程式由一系列物件組成,類是對現實世界的抽象,包括表示靜態屬性的資料和對資料的操作,物件是類的實體化,面向物件有三個特點:封裝性、繼承性、多型性,
- 封裝性
- 將描述每一個物件的屬性以及其行為的程式代碼組裝到一起,一并封裝在一個有機的物體中,把它們封裝在一個“模塊”中,也就是一個類中,
- 繼承性
- 繼承性是面向物件技術中的另外一個重要特點,繼承在面向物件技術是指一個物件針對于另一個物件的某些獨有的特點、能力進行復制或者延續,
- 多型性
- 從宏觀的角度來講,多型性是指在面向物件技術中,當不同的多個物件同時接收到同一個完全相同的訊息之后,所表現出來的動作是各不相同的,具有多種形態;從微觀的角度來講,多型性是指在一組物件的一個類中,面向物件技術可以使用相同的呼叫方式來對相同的函式名進行呼叫,
二、物件創建的方式
1.new Object() 方式
const obj = new Object()
obj.name = 'cara'
obj.age = 18
console.log(obj)
2.字面量方式
const obj = {
name: 'cara',
age: 18
}
console.log(obj)
3.工廠模式
-
工廠模式的主要作業原理是用函式來封裝創建物件的細節,從而通過呼叫函式來達到復用的目的,但是它有一個很大的問題就是創建出來的物件無法和某個型別聯系起來,它只是簡單的封裝了復用代碼,而沒有建立起物件和型別間的關系,
function star (name, age) { const obj = { name: name, age: age } return obj } const ldh = star('劉德華', 18) console.log(ldh)
4.建構式方式
-
js 中每一個函式都可以作為建構式,只要一個函式是通過 new 來呼叫的,那么就可以把它稱為建構式,執行建構式首先會創建一個空物件,然后將物件的原型指向建構式的 prototype 屬性,然后將執行背景關系中的 this 指向這個物件,最后再執行整個函式,給實體物件添加屬性和方法,最后再指回這個新物件,建構式模式相對于工廠模式的優點是,所創建的物件和建構式建立起了聯系,因此可以通過原型來識別物件的型別,但是建構式存在一個缺點就是,造成了不必要的函式物件的創建,因為在 js 中函式也是一個物件,因此如果物件屬性中如果包含函式的話,那么每次都會新建一個函式物件,浪費了不必要的記憶體空間,因為函式是所有的實體都可以通用的,
function Star (name, age) { this.name = name, this.age = age, this.sing = function () { console.log(this.name) } } const ldh = new Star('劉德華', 18) ldh.sing()
5.原型方式
-
因為每一個函式都有一個 prototype 屬性,這個屬性是一個物件,它包含了通過建構式創建的所有實體都能共享的屬性和方法,因此可以使用原型物件來添加公用屬性和方法,從而實作代碼的復用,這種方式相對于建構式模式來說,解決了函式物件的復用問題,但是這種模式也存在一些問題,一個是沒有辦法通過傳入引數來初始化值,另一個是如果存在一個參考型別如 Array 這樣的值,那么所有的實體將共享一個物件,一個實體對參考型別值的改變會影響所有的實體,
function Star () { } Star.prototype.name = 'cara' Star.prototype.age = 18 Star.prototype.sing = function () { console.log(this.name) } const ldh = new Star('劉德華', 18) ldh.sing()
6.建構式+原型方式
-
這是創建自定義型別的最常見方式,因為建構式模式和原型模式分開使用都存在一些問題,因此可以組合使用這兩種模式,通過建構式來初始化物件的屬性,通過原型物件來實作函式方法的復用,這種方法很好的解決了兩種模式單獨使用時的缺點,但是有一點不足的就是,因為使用了兩種不同的模式,所以對于代碼的封裝性不夠好,
function Star (name, age) { this.name = name this.age = age } Star.prototype.sing = function () { // 建構式原型身上的方法也指向實體物件 console.log(this.age) } const ldh = new Star('劉德華', 18) ldh.sing()
7.類方式
class Star {
constructor (name, age) {
this.name = name
this.age = age
}
// 類中的方法也指向實體物件
sing () {
console.log(this.name)
}
}
const ldh = new Star('劉德華', 18)
ldh.sing()
三、物件繼承的方式
1.建構式繼承(call/apply)
function Animal (name) {
this.name = "wang"
}
function Cat (name, age) {
Animal.call(this)
this.age = age
}
const cat = new Cat('wang', 1)
console.log(cat)
2.prototype原型鏈繼承
-
子類原型 = 父類實體
function Animal (name, age) { this.name = name this.age = age } Animal.prototype.dance = function () { console.log(this.name) } function Cat (name) { Animal.call(this, name) } Cat.prototype = new Animal() Cat.prototype.constructor = Cat const cat = new Cat('neal') cat.dance() // neal
3.類繼承(extends+super)
class Father {
constructor (uname) {
this.uname = uname
}
// 普通函式
sing () {
console.log(123)
}
// 建構式
dance () {
console.log(this.uname)
}
}
class Son extends Father {
constructor (uname) {
// 呼叫建構式時
super(uname)
this.uname = uname
}
// 呼叫普通函式時
song () {
super.sing()
}
}
const son = new Son('cara')
// 兒子呼叫普通函式
son.song()
// 兒子呼叫建構式
son.dance()
四、new的程序
使用new呼叫建構式會執行如下步驟:
- 在記憶體中創建一個新物件,
- 這個新物件內部的
[[Prototype]]指標被賦值為建構式的prototype屬性, - 建構式內部的
this被賦值為這個新物件(即 this 指向新物件), - 執行建構式內部的代碼(給新物件添加屬性),
- 如果建構式回傳非空物件,則回傳該物件;否則,回傳剛創建的新物件,
五、總結
最后再來個總結:
- JS中的函式可以作為函式使用,也可以作為類使用,
- 作為類使用的函式實體化時需要使用
new, - 為了讓函式具有類的功能,函式都具有
prototype屬性, - 為了讓實體化出來的物件能夠訪問到
prototype上的屬性和方法,實體物件的__proto__指向了類的prototype,所以prototype是函式的屬性,不是物件的,物件擁有的是__proto__,是用來查找prototype的, prototype.constructor指向的是建構式,也就是類函式本身,改變這個指標并不能改變建構式,- 物件本身并沒有
constructor屬性,你訪問到的是原型鏈上的prototype.constructor, - 函式本身也是物件,也具有
__proto__,他指向的是JS內置物件Function的原型Function.prototype,所以你才能呼叫func.call,func.apply這些方法,你呼叫的其實是Function.prototype.call和Function.prototype.apply, prototype本身也是物件,所以他也有__proto__,指向了他父級的prototype,__proto__和prototype的這種鏈式指向構成了JS的原型鏈,原型鏈的最終指向是Object的原型,Object上面原型鏈是null,即Object.prototype.__proto__ === null,- 因為JS中所有函式的原型都是
Function.prototype,也就是說所有函式都是Function的實體,Function本身也是可以作為函式使用的----Function(),所以他也是Function的一個實體,類似的還有Object,Array等,他們也可以作為函式使用:Object(), Array(),所以他們本身的原型也是Function.prototype,即Object.__proto__ === Function.prototype,換句話說,這些可以new的內置物件其實都是一個類,就像我們的Puppy類一樣, - ES6的class其實是函式類的一種語法糖,書寫起來更清晰,但原理是一樣的,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/538758.html
標籤:JavaScript
上一篇:CSS偽類使用詳解
下一篇:淺入淺出JS垃圾回識訓制
