JS中的原型對象

JS中的原型對象

白天寫了一篇【JS中創建對象的方法】,寫完以後感覺意猶未盡(實際情況是感覺原型那塊內容沒有交

代清楚),所以開這一篇繼續聊聊關於JavaScript中的原型對象

相信用過vue的童鞋,都經常這樣做,用Vue.prototype.xxx = xxx 把一個方法或者屬性添加到Vue對象的原型上,

這樣,我們在vue實例的任何地方,都可以用這個方法或屬性了,我最喜歡用的,就是把非同步請求庫

(我比較喜歡用axios)掛載到vue原型上:

// 一般是./src/mian.js// 這裡為了方便理解就直接引入axios,實際使用,我們可以先用axios封裝一個非同步請求模塊// 在模塊里做一些攔截或者處理,然後再導入這個模塊。具體做法看import axios from axiosimport Vue from vueimport App from ./App// 為所有Vue實例添加一個post模塊,可以在vue實例中直接使用this.postVue.prototype.post = axiosnew Vue({ el: #app, components: { App }, template: <App/>})

這了是prototype就是我們所說的原型,那什麼是原型呢? 我們看看MDN給的解釋

當談到繼承時,JavaScript 只有一種結構:對象。每個對象都有一個私有屬性(稱之為 [[Prototype]]),

它指向它的原型對象(prototype)。該 prototype 對象又具有一個自己的 prototype ,

層層向上直到一個對象的原型為 null。根據定義,null 沒有原型,並作為這個原型鏈中的最後一個環節。

視乎看起好有點拗口,沒關係,我用自己的話總結了一下

1.prototype其實就是存在於對象中的一個特殊的對象,你可以把它理解為對象的一個屬性或方法,

如 a.prototype,看起來是不是很像對象a的一個屬性呢?

2.每個對象都有一個prototype,除了null

那這個prototype是幹嘛的呢? 其實回頭看看上面關於vue的代碼就知道了,

prototype最主要的作用就是該原型所屬對象的所有實例,都能共享prototype里的屬性和方法

上面的代碼中,通過向Vue.prototype中添加一個post方法,然後就可以在所有vue實例中使用該方法,就是個簡單的實踐。

我們回頭看看 【JS中創建對象的方法】裡面的原型模式

function Student(){} // 聲明一個空函數Student.prototype.name = xiaohongStudent.prototype.age = 17Student.prototype.gender = fStudent.prototype.study = fucntion() { console.log(我在學習...)}

我們先定義了一個空函數,注意:這個時候,我們並沒有認為的給函數添加一個prototype屬性/方法,

而Student卻自動有了prototype,然後我們往prototype裡面添加了name,age,gender屬性和study方法,

然後我們用new實例化2個Student對象出來

var studentA = new Student()console.log(studentA.name) // xiaohongconsole.log(studentA.age) // 17console.log(studentA.gender) // fstudentA.study() // 我在學習...var studentB = new Student()console.log(studentB.age) // xiaohongconsole.log(studentB.name) // 17console.log(studentB.gender) // fstudentB.study() // 我在學習...

上面的例子可以看出,對象的prototype裡面的屬性和方法,在該對象的所有實例裡面,都是共享的

那如果我們想要讓實例對象有自己的屬性/方法,該怎麼辦呢? 比如,我想讓studentB的名字是lili,

很簡單,直接在實例對象上添加該屬性/方法:

studentA.name = lilistudentA.study = function () { console.log(我在偷懶)}console.log(studentA.name) // liliconsole.log(studentB.name) // xiaohongstudentA.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) // truestudentB.hasOwnProperty(name) // false

那如果想同時查找實例對象和原型對象prototype呢?我們可以用 in 操作符

name in studentA // truename in studentB // true

有了這2個方法,我們就可以組合起來判斷屬性是屬於實例還是原型了。

這裡老是說到實例,不得不提一下,實例對象雖然是構造函數「構造」出來的,但是其實跟構造函數沒有直接聯繫,

實例對象內部指向的是構造函數的prototype(原型)。 實例跟構造函數的一個間接關係是

實例.prototype.constructor --> 構造函數

關於原型的介紹就到這裡,有需要更深入的童鞋,建議去讀一下javascript權威指南。裡面關於原型的介紹比我這詳細。

下面列幾個javascript權威指南裡面介紹的關於原型的方法

  1. 獲取一個實例對象的原型 (ES5才支持)

Object.getPrototypeOf(studentA) // Student.prototype

部分瀏覽器(chrome,safari,firefox)也支持一個屬性 __proto__

studentA.__proto__ == Student.prototype

  1. 判斷一個構造函數是否是指定實例對象的原型

Student.prototype.isPrototypeOf(studentA) // true


推薦閱讀:

橫行的前端(上)
怎麼把PSD內容轉換成HTML代碼?
Web前端開發-小米網站頭部導航條製作
echarts實現非同步載入數據,點擊更新圖表功能。
個人前端小知識總結

TAG:前端開發 | 前端入門 | 前端開發框架和庫 |