原型是一個對象,每一個函數對象(在javascript 之對象中說過函數也是對象 )都有一個屬性(prototype)指向這個對象--原型對象,這個對象的做用是讓全部對象實例共享原型對象中的屬性、方法。即咱們能夠把公共的屬性、方法寫在這個原型中,因此說js中的繼承是基於原型實現的;javascript
每一個構造函數都有一個原型對象,原型對象包含一個指針指向構造函數,而實例包含一個指向原型對象的內部指針;java
1 function Person(name,age){ 2 this.name=name; 3 this.age=age; 4 } 5 console.dir(Person);
如圖:編程
Person 有個屬性prototype 指向原型對象瀏覽器
原型對象經過constructor 指向函數對象性能優化
Object.getPrototypeOf() 能夠查看MDN的介紹:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/GetPrototypeOf
函數
原型鏈是一種機制,指的是JavaScript每個對象、包括原型對象都有一個內部的[[proto]]屬性,它指向建立它的函數對象的原型對象。這個屬性是編程不可見的(雖然ES6標準中開放了這個屬性,然而瀏覽器對這個屬性的可見性的支持不一樣)。性能
當一個對象須要引用一個屬性時,JavaScript引擎首先會從這個對象自身的屬性表中尋找這個屬性標識,若是找到則進行相應讀寫操做,若是沒有在自身的屬性表中找到,則在_proto_屬性引用的對象(原型對象)的屬性表中查找,如此往復,直到找到這個屬性或者_proto_屬性指向null爲止(object prototype )。優化
對象的_proto_的引用鏈,稱爲原型鏈。this
注意:有一個性能優化的問題:原型鏈越深,耗費的時間越多,同理做用域鏈也是這樣。spa
原型鏈的存在,主要是爲了實現對象的繼承。
理解原型鏈,須要從幾個概念入手。
在JavaScript中,函數也是對象。
當定義一個函數對象時,會包含一個內部屬性,叫prototype稱之爲原型對象。
1 //普通對象 2 var a = {}; 3 console.log(a.prototype);//undefined
在建立對象的時候,都會有一個[[proto]]的內部屬性,用於指向建立它的函數對象的prototype(函數對象prototype 指向函數的原型對象)。原型對象也有[[proto]]屬性,所以在不斷的指向中,造成了原型鏈。
舉個例子來講,咱們將對象F的原型對象修改一下,就能夠清楚看到上述的關係
1 function F(){}; 2 var f = new F(); 3 console.log(f.__proto__);
當使用new去調用構造函數時,至關於執行了
1 var o = {}; 2 o.__proto__ = F.prototype; 3 F.call(o);
在原型鏈的實現上,new起到了很關鍵的做用。
原型對象prototype上都有個constructor屬性,指向它的函數對象,如上圖。
在實際運用中,常常這樣寫:
1 function F(){}; 2 F.prototype = { 3 constructor : F, 4 doSomething : function(){} 5 }
這裏要加constructor是由於重寫了原型對象,以前的constructor屬性跟重寫的原型對象沒有任何關係,因此須要本身手動補上。
1 function F(){ 2 this.name = 'zhang'; 3 }; 4 var f1 = new F(); 5 var f2 = new F();