js中的原型對象/prototype


前置任務

在說原型對象是什么之前,我們先討論一下對象是什么東西
在說對象是什么之前,我們又得討論一下引用類型

引用類型


首先,js 中變量的值分兩種類型

  • 引用類型
  • 值類型

關於這兩種類型,我們需要從內存的角度來看

var num = 9527            //值類型
var str = "一段字符串"     // 值類型
var obj = {               // 引用類型
  attr_1:"qwer",
  attr_2:"df"
  }

上面這些數據,在內存中可能是這樣的

可以看到

  • 值類型的numstr兩個變量,變量名直接對應具體值
  • 引用類型的obj這個變量對應的是一段地址,而這個地址的位置存的才是真正的obj的具體值(對象)

至於為什么要這么存,這跟內存的管理有關就不展開說,簡單的

你媽媽給你生了五個可愛的妹妹

  for(var i=0;i<5;i++){
    var 妹妹i號=new 妹妹()
  }

每個妹妹都是new出來的一個對象,她們都有一些屬性,比如

妹妹1號:{
  age:3
  name:妹妹1號,
  parent:{
    媽媽:你的媽媽,
    爸爸:你的爸爸
  }
}

每個妹妹的agename屬性都是不同的,而parent屬性都是相同的,這時候如果每個妹妹都存一份parent就太浪費內存了,所以我們可以存個地址.內存中這個地址的位置存真正的parent信息,這樣就可以很好的利用起寶貴的內存空間啦

ps: 我們建立一個概念,一個對象是一個獨立的'塊',而不是妹妹i號.parent這樣一條屬性,妹妹i號.parent這條屬性指向一個對象,也不用糾結,先往下看

對象

前面我們說了,對象是獨立的塊內存,要想訪問或者操作對象,就得通過該對象的的地址,而變量存儲的就是這個地址

然后我們來看

var obj = {
  attr_1: "qwer",
  attr_2: "df"
};
var obj_2=obj

obj_2.attr_1="qwqaqaaaaaawer"

console.log(obj.attr_1) //qwqaqaaaaaawer

這樣,為什么改的是obj_2.attr_1而打印obj.attr_1的時候是qwqaqaaaaaawer應該就很清楚了

原型對象

無論什么時候,只要創建了一個新函數,就會根據一組特定的規則為該函數創建一個 prototype 屬性,這個屬性指向函數的原型對象

注意兩點

  • 函數的prototype屬性指向函數的原型對象,而不是說prototype就是原型對象,prototype是地址,內存中這個地址的位置上的東西才是原型對象
  • 函數也是對象,所以函數也可以有屬性

拓展閱讀: 為什么要創建原型對象

在默認情況下,所有原型對象都會自動獲得一個 constructor(構造函數)屬性,這個屬性包含一個指向 prototype 屬性所在函數(下圖這個例子中的a)的地址。看圖理解:

到目前為止,內存中是這樣的

思考題:為什么a.prototype.constructor==a
答案:a.prototype.constructora指向同一塊內存

上面說,創建了自定義的構造函數之后,其原型對象默認會取得 constructor 屬性

然鵝:


這個a.prototype.toString函數根本沒有定義,上面的內存圖中也看不到它,那它是從哪哪冒出來的???

至於其原型對象的其他方法,則都是從 Object 繼承而來的。

(這個__proto__是什么,看下面的詳細講解)

當調用構造函數創建一個新實例后(是一個對象),該實例的內部將包含一個指針(內部屬性),指向構造函數的原型對象。

es5 中管這個指針叫[[Prototype]]。雖然在 js 中沒有標准的方式訪問[[Prototype]]

但 Firefox、Safari 和 Chrome 在每個對象(函數的原型對象也是對象,所以也有__proto__屬性)上都支持一個屬性__proto__

再來看一遍這段代碼:

  • a.prototype指向原型對象,原型對象是由構造函數Ojbect生成的
  • Object也是一個函數,是Object.prototype指向Object的原型對象
  • 思考題: a.prototype.__proto__是函數a的原型對象的一條屬性,這個屬性的屬性值是一個地址,那么內存中這個地址存的是什么?
    答案: 存的是Object的原型對象
    附內存圖一張,方便理解:

這個連接存在於實例的原型對象與構造函數的原型對象之間,而不是存在於實例與構造函數之間

a的原型對象是由構造函數Object生成的,他們兩個之間存在鏈接(通過__proto__)

接着說,js中,有這樣一條規則:訪問一條屬性(假設是屬性attr)時,在當前對象(假設是obj)中找不到的,就往obj.__proto__找,即obj.__proto__.attr,再找不到,就往obj.__proto__.__proto__找,直到找到或者obj.__proto__.......null才停止

所以 前面的a.prototype.toString實際上是a.prototype.__proto__.toString也就是Object.tostring


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM