在 JavaScript 中 prototype 和 __proto__ 有什么區別


本文主要講三個 問題

  1. prototype 和 proto
  2. function 和 object
  3. new 到底發生了什么

prototype 和 proto

首先我們說下在 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 和 object

同樣,我們來先看一個例子。

    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的時候發生了什么?

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 屬性。

`
所以到最后,我們 總結一下 。

在 javascript 中 prototype 和 proto 到底有什么區別。

prototype 是 面向 構造函數,來思考,
proto 是 面向 實例化 后 的對象 來思考就對了。

`

最后再 給一個例子, 是一個,我們經常會在開發中用到的 例子。

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 屬性所對應的 對象啊

最后 終於 愉快的 找到了,自己的對象啦~ 單身狗就可能一直找不到,或者看不懂這篇文章。

好了,以上就是 在 看 vuejs 源碼 的時候 關於 new 的 一個 知識 擴展。


免責聲明!

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



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