JavaScript中實現new的兩種方式引發的探究
前言
當你 new 一個建構函式時發生了什麼?
“眾所周知”的三步:
建立一個空物件,將它的引用賦給 this,繼承函式的原型;通過 this 將屬性和方法新增至這個物件;最後返回 this 指向的新物件,也就是例項。
一般來說在js中大概是這樣的:
function Mynew(parent,...rest){ let obj={}; obj.__proto__=parent.prototype; let res=parent.apply(obj,rest); return typeof res=="object"?res:obj; }
上面提到的“空物件”只是簡稱。事實上,就算是定義一個
{}
,它也會從Object.prototype
上繼承很多方法和屬性。
《javascript語言精髓與程式設計實踐》中提出了一個“更加空白的物件”:它有兩種情況 ——Constructor.prototype
值為null;或者Object.getPrototypeOf(obj)
值為null。
但通常我們還能見到另一種寫法:
function Mynew_2(parent,...rest){ let child=Object.create(parent.prototype); let result=parent.apply(child,rest); return typeof result=="object"?result:child; }
這兩種實現的不同無疑引起了我的興趣!
Object.create()是怎麼實現的?
我們來看一段程式碼:
var Best1=function(){ this.a=2; } var o1=Object.create(Best1); var o2=Object.create(Best1.prototype); console.log(o1.a); // undefined console.log(o2.a); // undefined
可以看到,以 o1 為例,Object.create()
fxEJFsB失去了對原來物件屬性的訪問,而 o2 …同理。
再來看另一段程式碼:
var Best=function(){ this.a=2; } Best.prototype.a=3; var o1=Object.create(Best); var o2=Object.create(Best.prototype); console.log(o1.a); // undefined console.log(o2.a); // 3
到這裡,我似乎明白了什麼,又似乎沒明白…
我決定這麼做:
let b=new Behttp://www.cppcns.comshttp://www.cppcns.comt();
console.log(b);
console.log(Best.prototype);
恍然大悟!
原來我們平時說的 “當讀取例項屬性時,如果找不到,就會查詢與物件關聯的原型中的屬性;如果還找不到,就去找原型的原型,直到最頂層(__proto__
為null)為止” 是指 “一直順著 __proto__
向上查詢”(注意:不經過prototype!)。
! 那 __proto__
和 prototype
之間又有什麼呢?
console.log(b.__proto__); console.log(Best.prototype);
哦!這就是我們常聽到的“例項的http://www.cppcns.com __proto__
等於物件的 prototype
”吧。
那現在回過頭來,列印一下 o2 這個物件:
console.log(o2);
你有沒有想到什麼?
根據上面所描述的那樣,o2 就是 Best 的例項啊!
所以說,create()
函式實際上返回了一個物件的例項?
但 o1 仍然“不為所動”!
所以我們能否猜測:在 Object.create()
函式中應該是拿到物件的原型並以例項的形式返回:
Obje程式設計客棧ct.create=function(o){
let F=function(){};
F.prototype=o;
return new F();
}
為什麼這裡要用函式再 new 的方式?而不是直接用物件去接收?
這和“為什麼vue中data是一個函式而不是直接的物件”其實是一個問題:javaScript中的物件是引用型別,在一個例項中改變某一個元素的值其餘例項的值都會發生改變!
而通過create函式則不會:
總結
到此這篇關於JavaScript中實現new的兩種方式的文章就介紹到這了,更多相關JS實現new的方式內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!