一. 理論基礎
1. 普通對象和函數對象
JavaScript中,萬物皆對象!但是對象也是有差別的,分為普通對象和函數對象。
function F(){}; //F:普通對象
var f = new Function(); //f: 函數對象
var o = new Object(); //o: 函數對象
Object、Function是js自帶的函數對象。
2. 構造函數
與大部分面向對象的語言不同,JavaScript中并沒有引入類(class)的概念,但JavaScript仍然大量使用了對象,為了保證對象之間的聯系,JavaScript引入了原型與原型鍊的概念。
與Java不同,JavaScript的new操作符後面跟的并非類名而是函數名,JavaScript并非通過類而是直接通過構造函數來建立執行個體。
function Dog(name, color) {
this.name = name
this.color = color
this.bark = () => {
console.log('wangwang~')
}
}
const dog1 = new Dog('dog1', 'black')
const dog2 = new Dog('dog2', 'white')
上述代碼中,有兩個執行個體被建立,它們有自己的屬性,但bark方法是一樣的,而通過構造函數建立執行個體的時候,每個執行個體都需要建立這個方法。為什麼不把這個方法放到一個單獨的位置,并讓所有執行個體都可以通路到呢?
3. 構造函數和普通函數
構造函數和普通函數主要有以下差別:
-
調用方式:
(1)構造函數需要使用new運算符調用,如果沒有參數,可以省略括号,比如new Object
(2)普通函數的調用不需要new運算符,而且必須有括号
-
this指向
(1)構造函數的this會指向建立的對象執行個體上
(2)普通函數的this則指向函數的調用者
-
命名方式
(1)構造函數名稱首字母要大寫
(2)普通函數首字母要小寫,使用駝峰命名方式
這裡就需要用到原型。
二. 原型
- 每一個構造函數都有一個prototype屬性,指向原型對象。當使用這個構造函數建立執行個體的時候,prototype屬性指向的原型對象,就是執行個體的原型對象。
- 原型對象預設擁有一個constructor屬性,指向指向它的那個構造函數。
- 每個對象都有一個隐藏屬性
,每個函數對象都有一個obj._proto_
,它們指向同一原型對象。function.prototype
- 原型對象就是用來存放執行個體中共有的屬性。
- 通路對象屬性時,會先在對象自身屬性内查找,若沒有找到,則會跳轉到對象的原型對象中查找。
那麼上述代碼就可以修改為
function Dog(name, color) {
this.name = name
this.color = color
}
Dog.prototype.bark = () => {
console.log('wangwang~')
}
接着就可以建立執行個體,并通路它的bark方法:
const dog1 = new Dog('dog1', 'black')
dog1.bark() //'wangwang~'
這個時候,我們還可以重寫bark方法:
const dog2 = new Dog('dog2', 'white')
dog2.bark = () => {
console.log('miaomiaomiao???')
}
dog1.bark() //'wangwang~'
dog2.bark() //'miaomiaomiao???'
由上可知,重寫的bark方法是為自己添加了一個新的方法使原型中的bark方法被覆寫了,而并非直接修改原型中的方法。
要修改原型中的方法應該這樣:
Dog.prototype.bark = () => {
console.log('haha~')
}
dog1.bark() //'haha~'
dog2.bark() //'haha~'
三. 結語
如有遺漏,後面會繼續總結。
參考
https://www.jianshu.com/p/dee9f8b14771
https://juejin.im/post/5a94c0de5188257a8929d837
https://www.cnblogs.com/shayueblog/p/5813230.html
http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html