JS 中 __proto__ 和 prototype 存在的意義是什麼?

本文爲飢人谷講師方方原創文章。前端

  1. 你的 JS 代碼還沒運行的時候,JS 環境裏已經有一個 window 對象了
  2. window 對象有一個 Object 屬性,window.Object 是一個函數對象
  3. window.Object 這個函數對象有一個重要屬性是 prototype,幹什麼用的等會說
  4. window.Object.prototype 裏面有這麼幾個屬性 toString(函數)、valueOf(函數)

好,目前先知道這些就夠了。
而後咱們寫一句代碼面試

var obj = {}
obj.toString()

這句代碼作了啥?爲何 obj 有 toString() 屬性?數組

這句話大概是讓 obj 變量指向一個空對象,這個空對象有個 proto 屬性指向 window.Object.prototype。微信

這樣你在調用 obj.toString() 的時候,obj 自己沒有 toString,就去 obj.__proro__ 上面去找 toString。數據結構

因此你調用 obj.toString 的時候,實際上調用的是 window.Object.prototype.toString函數

那麼 window.Object.prototype.toString 是怎麼獲取 obj 的內容的呢?this

那是由於 obj.toString() 等價於 obj.toString.call(obj) spa

同時 obj.toString.call(obj) 等價於 window.Object.prototype.toString.call(obj)prototype

這句話把 obj 傳給 toString 了。3d

再看複雜一點的

回到第一幅圖


咱們寫一句代碼

var arr = []
arr.push(1) // [1]

請問這兩句話作了什麼?

看紅色部分,var arr = [] 大概會讓 arr 指向一個空對象,而後 arr.__proto__ 指向 window.Array.prototype。(其實 arr 有一個 length:0,不過這裏就忽略吧)

這樣你在調用 arr.push 的時候,arr 自身沒有 push 屬性,就去 arr.__proto__ 上找 push

所以 arr.push 其實是 window.Array.prototype.push

arr.push(1) 等價與 arr.push.call(arr,1)

arr.push.call(arr,1) 等價於 window.Array.prototype.push.call(arr, 1)

再再複雜一點

arr.valueOf() 作了什麼?

arr 自身沒有 valueOf,因而去 arr.__proto__ 上找

arr.__proto__ 只有 pop、push 也沒有 valueOf,因而去 arr.__proto__.__proto__ 上找

arr.__proto__.__proto__ 就是 window.Object.prototype

因此 arr.valueOf 其實就是 window.Object.prototype.valueOf

arr.valueOf() 等價於 arr.valueOf.call(arr)

arr.valueOf.call(arr) 等價於 window.Object.prototype.valueOf.call(arr)

看,JavaScript 其實很優美很簡單。

只是你想複雜了而已:

prototype 指向一塊內存,這個內存裏面有共用屬性

proto 指向同一塊內存

prototype 和 proto 的不一樣點在於

prototype 是構造函數的屬性,而 proto 是對象的屬性

難點在於……構造函數也是對象!

若是沒有 prototype,那麼共用屬性就沒有立錐之地

若是沒有 __proto__,那麼一個對象就不知道本身的共用屬性有哪些。

反證法

假設咱們把 proto 去掉,那麼

var obj = {}
obj.toString() // 報錯,沒有 toString 方法

因此你只能這樣聲明一個對象咯:

var obj = {
  toString: window.Object.prototype.toString,
  valueOf: window.Object.ptototype.valueOf
}
obj.toString() // '[object Object]'

知道 proto 幫你省多少代碼了嗎?

假設咱們刪掉 prototype,包括 window.Object.prototype 和 window.Array.prototype。

那麼 window.Object.prototype.toString 也一併被刪除了。

而後咱們基本就無法寫代碼了……

var obj = {}
obj.toString() // toString 不存在,由於 toString 沒有定義過啊

prototype 的意義就是把共有屬性預先定義好,給以後的對象用。

本身想一想吧~

新人搞不懂原型大抵是由於

  1. 不懂內存、引用
  2. 不懂鏈表、樹等數據結構
  3. 不知道函數是一種對象
  4. 被 Java 的 class 關鍵字毒害了
  5. 還有一種多是由於沒遇到我方應杭:
「每日一題」什麼是 JS 原型鏈?
JS 的 new 究竟是幹什麼的?
this 的值究竟是什麼?一次說清楚

以上是「方三篇」新人必定要看哦。

想看視頻版本能夠購買個人網課(收費):
JS 深刻淺出 - 寫代碼啦!

這幅圖我還能夠繼續講,把 JS 全部基礎知識都能串起來。

好比不少人不懂什麼是僞數組,很簡單:

  1. 若是一個數組的 proto 直接或間接指向 Array.prototye(用到了數組的共用屬性),那麼就是真數組
  2. 若是一個數組的 proto 沒有直接或間接指向 Array.prototye,那麼就是僞數組
var realArr = {0: 'a', 1:'b', length: 2}
realArr.__proto__ = Array.prototye
// 這就是真數組
// 等價於 realArr = ['a', 'b']
realArr.push !== undefined // true

var fakeArr = {0: 'a', 1:'b', length: 2}
// 這就是僞數組
realArr.push === undefined // true

完。

加微信號: astak10或者長按識別下方二維碼進入前端技術交流羣 ,暗號:寫代碼啦

每日一題,每週資源推薦,精彩博客推薦,工做、筆試、面試經驗交流解答,免費直播課,羣友輕分享... ,數不盡的福利免費送

相關文章
相關標籤/搜索