白天寫了一篇【JS中建立對象的方法】,寫完之後感受意猶未盡(實際狀況是感受原型那塊內容沒有交 代清楚),因此開這一篇繼續聊聊關於JavaScript中的原型對象javascript
相信用過vue的童鞋,都常常這樣作,用Vue.prototype.xxx = xxx 把一個方法或者屬性添加到Vue對象的原型上, 這樣,咱們在vue實例的任何地方,均可以用這個方法或屬性了,我最喜歡用的,就是把異步請求庫 (我比較喜歡用axios)掛載到vue原型上:vue
// 通常是./src/mian.js
// 這裏爲了方便理解就直接引入axios,實際使用,咱們能夠先用axios封裝一個異步請求模塊
// 在模塊裏作一些攔截或者處理,而後再導入這個模塊。具體作法看
import axios from 'axios'
import Vue from 'vue'
import App from './App'
// 爲全部Vue實例添加一個post模塊,能夠在vue實例中直接使用this.post
Vue.prototype.post = axios
new Vue({
el: '#app',
components: { App },
template: '<App/>'
})
複製代碼
這了是prototype就是咱們所說的原型,那什麼是原型呢? 咱們看看MDN給的解釋java
當談到繼承時,JavaScript 只有一種結構:對象。每一個對象都有一個私有屬性(稱之爲 [[Prototype]]), 它指向它的原型對象(prototype)。該 prototype 對象又具備一個本身的 prototype , 層層向上直到一個對象的原型爲 null。根據定義,null 沒有原型,並做爲這個原型鏈中的最後一個環節。ios
視乎看起好有點拗口,不要緊,我用本身的話總結了一下git
1.prototype其實就是存在於對象中的一個特殊的對象,你能夠把它理解爲對象的一個屬性或方法, 如 a.prototype,看起來是否是很像對象a的一個屬性呢?github
2.每一個對象都有一個prototype,除了nullchrome
那這個prototype是幹嗎的呢? 其實回頭看看上面關於vue的代碼就知道了, prototype最主要的做用就是該原型所屬對象的全部實例,都能共享prototype裏的屬性和方法 上面的代碼中,經過向Vue.prototype中添加一個post方法,而後就能夠在全部vue實例中使用該方法,就是個簡單的實踐。axios
咱們回頭看看 【JS中建立對象的方法】裏面的原型模式瀏覽器
function Student(){} // 聲明一個空函數
Student.prototype.name = 'xiaohong'
Student.prototype.age = 17
Student.prototype.gender = 'f'
Student.prototype.study = fucntion() { console.log('我在學習...')}
複製代碼
咱們先定義了一個空函數,注意:這個時候,咱們並無認爲的給函數添加一個prototype屬性/方法, 而Student卻自動有了prototype,而後咱們往prototype裏面添加了name,age,gender屬性和study方法, 而後咱們用new實例化2個Student對象出來app
var studentA = new Student()
console.log(studentA.name) // xiaohong
console.log(studentA.age) // 17
console.log(studentA.gender) // f
studentA.study() // 我在學習...
var studentB = new Student()
console.log(studentB.age) // xiaohong
console.log(studentB.name) // 17
console.log(studentB.gender) // f
studentB.study() // 我在學習...
複製代碼
上面的例子能夠看出,對象的prototype裏面的屬性和方法,在該對象的全部實例裏面,都是共享的 那若是咱們想要讓實例對象有本身的屬性/方法,該怎麼辦呢? 好比,我想讓studentB的名字是'lili', 很簡單,直接在實例對象上添加該屬性/方法:
studentA.name = 'lili'
studentA.study = function () {
console.log('我在偷懶')
}
console.log(studentA.name) // lili
console.log(studentB.name) // xiaohong
studentA.study() // 我在偷懶
studentB.study() // 我在學習...
複製代碼
能夠看出,studentA的屬性/方法被改變的時候,studentB沒有對應的跟着改變,這是爲何呢? 不是說好的全全部prototype裏的屬性/方法都是共享的嗎?事實上,prototype裏的屬性/方法,確實是共享的, 問題出在咱們是在實例對象上賦值,因此這個屬性/方法,是屬於實例的,而不是屬於prototype的,prototype的屬性, 也沒法在實例對象上寫入,也就是說,實例對象和prototype上,同時存在了 name屬性和study方法,那麼, 爲何 studentA 和 studentB 訪問到的屬性/方法 會不同呢? 其實每次訪問一個屬性/方法的時候, 都會先從實例對象開始查找,若是實例上有,就直接返回,若是實例上沒有,就繼續往prototype上查找,有就返回, 若是prototype上還有 prototype,那麼還會繼續網上查找,直到原型鏈的最頂層。若是都沒有查到,則會返回undefined。
那麼新的問題來了,咱們該如何判斷一個屬性,是屬於實例自己的,仍是屬於prototype的? 答案是hasOwnProperty方法, hasOwnProperty方法能夠檢測到實例對象裏面有沒有給定的屬性,該方法只能檢測到實例裏面的屬性,檢測不到prototype上的
studentA.hasOwnProperty('name') // true
studentB.hasOwnProperty('name') // false
複製代碼
那若是想同時查找實例對象和原型對象prototype呢?咱們能夠用 in 操做符
'name' in studentA // true
'name' in studentB // true
複製代碼
有了這2個方法,咱們就能夠組合起來判斷屬性是屬於實例仍是原型了。
這裏總是說到實例,不得不提一下,實例對象雖然是構造函數「構造」出來的,可是其實跟構造函數沒有直接聯繫, 實例對象內部指向的是構造函數的prototype(原型)。 實例跟構造函數的一個間接關係是 實例.prototype.constructor --> 構造函數
關於原型的介紹就到這裏,有須要更深刻的童鞋,建議去讀一下javascript權威指南。裏面關於原型的介紹比我這詳細。
下面列幾個javascript權威指南里面介紹的關於原型的方法
獲取一個實例對象的原型 (ES5才支持)
Object.getPrototypeOf(studentA) // Student.prototype
部分瀏覽器(chrome,safari,firefox)也支持一個屬性 __proto__
studentA.__proto__ == Student.prototype
判斷一個構造函數是不是指定實例對象
的原型
Student.prototype.isPrototypeOf(studentA) // true