prototype和__proto__

簡單地說,prototype就是原型對象的一個開放接口,讓咱們能夠爲對象的實例擴展屬性和方法。
先看一下對象的靜態方法和實例方法。瀏覽器

function Person () {
};
Person.sayHello = function () { //定義一個靜態方法
  console.log("Hello!");
};
var p = new Person();
Person.sayHello(); // Hello!
p.sayHello(); // p.sayHello is not a function

由此能夠看出,對象的靜態方法不能被對象實例調用。例如String對象的fromCharCode()方法,正確的調用方法應該是 String.fromCharCode(),而使用 myString.fromCharCode()會報錯。函數

若是咱們想給對象的實例添加方法,能夠在構造函數中使用"this"來定義:this

var Person = function () {
  this.sayHello = function () {
    console.log("Hello!");
  }
};
var p = new Person();
p.sayHello(); // Hello!

構造函數模式雖然好用,但有個很大的缺點,那就是每一個方法都會在每一個實例上從新建立一遍。例如,咱們建立兩個Person實例,p1和p2都有一個名爲sayHello()的方法,但這兩個方法不是同一個Function的實例。prototype

var Person = function () {
  this.sayHello = function () {
    console.log("Hello!");
  }
};
var p1 = new Person();
var p2 = new Person();
console.log(p1.sayHello == p2.sayHello); // false

由於JavaScript中函數也是對象,所以每定義一個函數就會實例化一個Function對象,形成了沒必要要的內存開銷。另外,使用this建立實例方法也並不老是可行的。例如咱們想給Date對象實例擴展一個format()方法,咱們總不能直接修改Date的源碼吧,而用prototype就很簡單了:指針

Date.prototype.format = function () {
  //do something...
}
var time = new Date();
time.format();

下面說一下__proto__。當調用構造函數建立一個新實例後,該實例內部會包含一個指針,指向構造函數的原型對象。這個指針在ECMA-262第5版上叫[[Prototype]],雖然沒有標準方式訪問[[Prototype]],但在Firefox、Safari和Chrome等瀏覽器上都實現了一個__proto__屬性來訪問它。當解析器查找實例上的某個屬性時,若是沒有查找到,就會在__proto__上查找,而__proto__指向構造函數的原型對象,這就是多個對象實例共享原型的屬性和方法的基本原理。code

簡單的說就是,p.__proto__ === p.constructor.prototypeorm

但也有例外,那就是使用Object.creat建立對象的時候。對象

function Person () {
};
var p1 = new Person();
var p2 = Object.create(Person)
console.log(p1.__proto__ === Person.prototype) // true
console.log(p2.__proto__ === Person.prototype) // false
console.log(p2.__proto__ === Person.prototype.constructor) // true

通常狀況下,對象的__proto__等於其構造函數的prototype ,而使用Object.create()建立的對象,其__proto__等於其原型對象的構造函數。接口

相關文章
相關標籤/搜索