任何一個函數都可以被當做構造函數使用,只需要使用new關鍵字
使用new關鍵字,就是當做構造函數使用,就會創建一個新的對象。
創建新對象的過程,就是先創建一個空對象,然后把這個構造函數的prototype賦值給空對象的[[Prototype]]屬性。然后執行constructor方法。注意這個constructor方法哪里來的呢?答案是這個constructor方法來自原型鏈。剛剛前面賦值了的[[Prototype]]屬性, 也就是構造函數的prototype,這兩個指向了同一個對象。這個對象里面有個constructor屬性,是一個函數表達式,這個函數表達式的值就是構造函數。所以執行了constrctor方法,就相當于執行了構造函數。如果構造函數里面有this.name = name,那就會給new出來的新對象賦值。
這個[[Prototype]]是js對象內置的一個屬性,隱藏和不可見。遍歷不到。但是可以使用proto來賦值。obj.proto = some object
需要注意的是通過原型鏈調用的方法/函數,里面的this,還是執行了調用對象,也就是新對象。執行方法時this永遠指向dot前面的對象。
下面再來說prototyte和[[Prototype]], 這兩者實際上是不同的東西,首先函數的prototype就是一個普通的屬性,js內置的函數也都有這個屬性。這個prototype有一個默認值,里面有一個constructor屬性,這個constructor屬性的值是一個函數,這個函數又是前面持有prototype的這個這個函數。
而[[Prototype]]是任何對象的內置屬性,他是原型鏈機制的一個屬性,如果一個對象的屬性和方法沒有找到,那么就會沿著[[Prototype]], 一直找。
但prototype沒有這個功能,他是函數特有的一個普通屬性,可以隨意更改,但是如果更改了,比如把里面contructor方法移除了,那么new創建的時候,就會找不到constructor方法,仍然會繼續往上找constructor方法,直到找到Object這個根對象。這個對象會有一個constrctor方法。
注意,如果通過構造函數new了一個對象出來,這時對構造函數prototype,重新賦值,這時并不會對剛new出來的對象產生影響。因為新對象還是持有原來的對象,構造函數的prototype重新賦值,對于原來的新對象不產生影響,因為他們已經指向了兩個不同的對象。但是如果不是重新賦值,而是增加屬性,那么新對象的原型鏈也會跟著改變,因為他們指向的是同一個對象
而對象的proto又是什么呢?這個是對[[Prototype]]這個屬性的封裝,就是相當于[[Prototype]]的set和get方法。