原型對象

理解原型對象

       在JS中,每個對象都有一個prototype屬性,屬性值爲一個對象,初始值爲空,每個prototype屬性指向的對象都包含惟一一個不可枚舉屬性constructor,該屬性的值是一個對象,指向它所在的構造函數瀏覽器


       不管何時,只要建立了一個新函數,就會根據一組特定的規則爲該函數建立一個prototype屬性,這個屬性指向函數的原型對象。在默認狀況下,全部原型對象都會自動得到一個constructor(構造函數)屬性,這個屬性包含一個指向prototype屬性所在函數的指針。bash

       建立了自定義的構造函數以後,其原型對象默認只會取得constructor屬性,其餘方法都是從object繼承而來的。當調用構造函數建立一個新的實例後,該實例的內部將包含一個指針(prototype)指向構造函數的原型對象。在腳本中沒有標準的方式訪問[[ prototype ]],但在瀏覽器控制檯中能夠console出來能夠發現,每個對象上都支持一個屬性_proto_,而在其它實現中,這個屬性對腳本則是徹底不可見的,不過要明確的真正重要的一個電就是,這個鏈接存在於實例與構造函數的原型對象之間,而不是存在於實例與構造函數之間函數

建立對象

一、工廠模式ui

以下:this

function createPerson( name, age, job ){
  var p = new Object();
  p.name = name;
  p.age = age;
  p.job = job;
  p.sayName = function (){
    alert(this.name);
  };
  return p;
}
var person1 = createPerson("Bob", 19, "Teacher");
var person1 = createPerson("Greg", 26, "Doctor");複製代碼

函數createPerson()可以根據接受的參數來構建一個包含全部必要信息的Person對象,能夠無數次的調用這個函數,而每次它都會返回一個包含三個屬性和一個方法的對象。工廠模式雖然解決了建立多個類似對象的問題,但卻沒有解決對象識別的問題(即怎樣知道一個對象的類型)spa

二、構造函數模式prototype

用構造函數的模式能夠把上面的例子進行以下重寫:指針

function Person( name, age, job ){
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = function (){
    alert(this.name);
  }
}
var person3 = new Person("Jen", 19, "Teacher");
var person4 = new Person("Gen", 26, "Doctor");複製代碼

工廠模式和構造函數的區別:code

a、沒有顯式的建立對象cdn

b、直接將屬性和方法賦給了this對象

c、沒有return語句

d、構造函數始終都應該以一個大寫字母開頭

要建立Person的新實例必須使用new操做符,以這種方式調用構造函數實際上會經歷一下4個步驟:

(1)建立一個新對象

(2)將構造函數的做用域賦給新對象(所以this就指向了這個新對象)

(3)執行構造函數中的代碼(爲給這個新對象添加屬性)

(4)返回新對象

在上述的例子中person3和person4分別都保存着Person的一個不一樣的實例。這兩個對象都有一個constructor(構造函數)屬性,該屬性指向Person

console.log(person3.constructor == Person);    //true
console.log(person4.constructor == Person);    //true複製代碼

對象的constructor屬性最初是用來標識對象類型的,可是檢測對象類型咱們通常用instanceof操做符,上述的例子中建立的對象person3和person4既是Object的實例,同時也是Person的實例

console.log(person3 instanceof Person);   //true
console.log(person3 instanceof Object);   //true複製代碼

優勢:建立自定義的構造函數意味着能夠將它的實例標識爲一種特定的類型,這就是構造函數模式賽過工廠模式的地方

缺點:使用構造函數的主要問題,就是每一個方法都要在每一個實例上從新建立一遍。在上面的例子中,person3和person4都有一個名爲sayName()的方法,但那兩個方法卻不是同一個Function的實例,函數都是對象,所以每定義一個函數,也就是實例化了一個對象。然而建立兩個完成一樣任務的Function實例的確沒有必要,何況有this對象在,根本不用在執行代碼前就把函數綁定到特定對象上面。所以咱們能夠進行以下改造,經過把函數定義轉移到構造函數外部來解決這個問題:

function Person( name, age, job ){
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = sayName;
}

function sayName() {
  alert(this.name);
}複製代碼

咱們把sayName()函數的定義轉移到了構造函數外部,而在構造函數內部,咱們將sayName屬性設置成等於全局的sayName函數,這樣一來,因爲sayName包含的是一個指向函數的指針,所以person3和person4對象就共享了在全局做用域中定義的一個sayName()函數,這樣作雖然能解決兩個函數作同一件事的問題,可是,在全局做用域中定義的函數實際上只能被某個對象調用,這讓全局做用域有些名存實亡,更麻煩的是,若是對象須要定義多個方法,那麼就要定義不少個這種全局函數,因此引入了原型模式來解決這些問題

三、原型模式

咱們建立的每個函數都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象,而這個對象的用途是包含能夠由特定類型的全部實例共享的屬性和方法。簡單講,prototype就是指向經過調用構造函數而建立的那個對象實例的原型對象。使用原型對象的好處是可讓全部對象實例共享它所包含的屬性和方法,也就是沒必要在構造函數中定義對象實例的信息,而是能夠將這些信息直接添加到原型對象中,以下:

function Person( name, age, job ){

}
Person.prototype.name = "Bob";
Person.prototype.age = 32;
Person.prototype.job = "Doctor";
Person.prototype.sayName = function () {
  alert(this.name);
};

var person5 = new Person();
person5.sayName();    //Bob複製代碼

咱們把全部的屬性都添加到了Person的prototype屬性中,構造函數變成了空函數,但仍然能夠經過調用構造函數來建立新對象,並且新對象還會具備相同的屬性和方法,與構造函數模式不一樣的是,新對象的這些屬性和方法是由全部實例共享的

相關文章
相關標籤/搜索