本文主要講三個 問題javascript
首先咱們說下在 JS 中,經常讓咱們感到困惑的地方,就是 prototype 和 __proto__ 究竟是幹嗎的 1. __proto__ 就是 Javascript中 所謂的原型 (這裏,咱們仍是拿具體的例子來講明吧)
function A (name) { // 這裏是一個構造函數 thia.name = name } var Aobj = { // 這裏是一個 對對象字面量 name: '' } // 咱們分別打印出來這二個對象看看 console.dir(A) console.dir(Aobj)
這裏咱們能夠很明顯的看到
構造函數的 __proto__ 屬性 指向了 function() 對象字面量的 __proto__ 屬性 指向了 Object 爲何 指向的 是不同的呢? 思考下: 確實是 不同的, 由於 構造函數自己也是一個 函數, 因此它 的原型 指向 function() 而對象字面量 是一個 對象, 那麼他的 原型確定是指向 Object 擴展思考,若是 是一個數組 對象, 那麼它的 __proto__ 會指向什麼吶?
const arr = [112,22,3333] console.dir(arr)
沒錯, 這裏的 __proto__ 就指向了 Array[0] 總結 :一個對象的 __proto__ 屬性和本身的內部屬性[[Prototype]]指向一個相同的值 (一般稱這個值爲原型) tips:firefox、chrome等瀏覽器把對象內部屬性 [[Prototype]] 用 __proto__ 的形式暴露了出來.(老版本的IE並不支持 __proto__ ,IE11中已經加上了 __proto__ 屬性) 2. prototype : 看看上面的 截圖,你會發現 只有 構造函數 中 有這個玩意兒, 對的。 prototype 確實 是 在 function 中特有的。 別的對象類型中 都不會有的屬性。
咱們在看這個 function 對象屬性的 時候就會發現這麼一個 prototype 的屬性,它的值是 一個 Object 。 點開這個 obj 咱們就會發現啊, 這個 obj 的constructor 屬性 指向了 這個構造函數自己。 是否是很神奇,至於爲何會是這樣子的。 留一個 思考題吧, 爲何在 javascript 中,函數對象的 prototype 屬性的 constructor 指向是 函數自己? (在下面的介紹中,咱們會 回答到這個問題)
一樣,咱們來先看一個例子。
function B(name) { this.name = name this.getName = function() { console.log(this.name) } var c = 'test' console.log(c) } var b = new B('testb') // test console.log(b) // B: { name: 'testb',getName: function() {} } B('testc') // test
看到上面的 輸出 是否是以爲又很詫異了。
確實, 爲何 在 new 的時候, 構造函數竟然 執行了一次。 一樣, 在非嚴格模式下, 咱們直接執行 構造函數, B('testc') 至關於:
// window.name = 'testc' // window.getName = function() { console.log(this.name) }
思考:
咱們的函數B既能夠直接執行,又能夠new一下返回一個對象。function和object究竟是什麼關係,new的時候發生了什麼?
仍是上面的 問題, 當咱們執行 var b = new B('testb') 的時候發生了什麼? MDN 上的介紹是這樣的說的: 對於 var b = new B('testb')
// javascript 實際上執行的是: var o = new Object() // 生成一個 新的 對象 b 這裏 能夠約等於 var b = {} o.__proto__ = B.prototype // 這裏就是 函數對象中 獨有的 prototype 屬性。 // 這個獨有的 prototype 屬性 包含了一個 constructor 屬性方法,指向的就是 構造函數, 也就是 這裏的 function B(name) {} B.call(o) // tips :這裏 就須要注意了,由於不少同窗都搞不清楚 這裏是什麼意思。 // 因爲 call 的使用 將這裏this是指向o, 因此就 能夠 把什麼this.name/getName 強行的綁定到o上。同時,須要注意的一點就是, 這裏的 構造函數 執行科一遍, 只不過是 將 this 指向的 屬性和方法,都 強行的 給 新建立的 這個 o 對象 綁定了一遍。 var b = o // 把 這個 o 返回給了 b 。 從而完成了 var b = new B('testb') 的過程 // 若是 仍是不明白是 什麼意思的話。 咱們來看看 call 是幹嗎用的
// 關於 call 的使用說明 var o1 = { name: '111', getName: function() { console.log(this.name) } } var o2 = { name: '222' } o1.getName.call(o2) // 222
因此 這個時候,咱們反過頭來 看看 這個 new 的對象都有哪些 屬性 和方法。 咱們 能夠 來 作一個 小實驗,來 證實下,咱們以上所說的東西。
function A (name) { // 這裏是一個構造函數 this.name = name } var o = {} o.__proto__ = A.prototype A.call(o) var a = o var b = new A() console.log(a) console.log(b)
果真 和 咱們想象 的如出一轍。
至於 js 爲何要 把 新建 對象的 原型 指向 構造函數的 prototype 屬性。 咱們能夠這樣來理解。 由於 經過 new 方法來建立的 obj 。確定是須要 一個 標記 來找到本身的 構造器函數。 因此 爲了讓 整個 程序結構看上去 合理。 咱們須要 把 新建 對象的 原型 指向 構造函數的 prototype 屬性。
`
因此到最後,咱們 總結一下 。vue
在 javascript 中 prototype 和 proto 到底有什麼區別。java
prototype 是 面向 構造函數,來思考,
proto 是 面向 實例化 後 的對象 來思考就對了。chrome
`數組
最後再 給一個例子, 是一個,咱們常常會在開發中用到的 例子。
瀏覽器
var Person = function(){} Person.prototype.sayName = function() { alert('my name is xxx') } Person.prototype.age = 12 var p = new Person() p.sayName() // 當咱們 實例化 以後, 在咱們 去執行 p.sayName() 的 時候,咱們就會去 this 內部去 查找(這裏就是 構造函數 Person 內部去找。 但是 沒找到啊。只是一個 空函數, 怎麼辦呢?) // 這個時候 就會沿着 原型鏈向上追溯, 可是如何 追溯呢? // 這裏就要用到 __proto__ 屬性 來做爲 追溯的 橋樑。 // 由於 實例化對象的 __proto__ 屬性 指向的就是 構造函數的 prototype 屬性所對應的 對象啊
最後 終於 愉快的 找到了,本身的對象啦~ 單身狗就可能一直找不到,或者看不懂這篇文章。markdown
好了,以上就是 在 看 vuejs 源碼 的時候 關於 new 的 一個 知識 擴展。函數