JavaScript 原型模式

2018-08-02 16:25 更新

原型模式

GoF將原型模式引用為通過克隆的方式基于一個(gè)現(xiàn)有對象的模板創(chuàng)建對象的模式。

我們能夠?qū)⒃湍J秸J(rèn)作是基于原型的繼承中,我們創(chuàng)建作為其它對象原型的對象.原型對象自身被當(dāng)做構(gòu)造器創(chuàng)建的每一個(gè)對象的藍(lán)本高效的使用著.如果構(gòu)造器函數(shù)使用的原型包含例如叫做name的屬性,那么每一個(gè)通過同一個(gè)構(gòu)造器創(chuàng)建的對象都將擁有這個(gè)相同的屬性。

在現(xiàn)存的(非Javascript的)語法中重新看一看對這個(gè)模式的定義,我們也許可以再一次發(fā)現(xiàn)對類的引用.真實(shí)的情況是那種原型繼承避免了完全使用類.理論上既不是一個(gè)"定義的“對象,也不是一個(gè)核心對象。我們可以簡單的創(chuàng)建現(xiàn)存函數(shù)型對象的拷貝。

使用原型模式的好處之一就是,我們在JavaScript提供的原生能力之上工作的,而不是JavaScript試圖模仿的其它語言的特性.而對于其它的模式來說,情況并非如此。

這一模式不僅僅是實(shí)現(xiàn)繼承的一種簡單方式,它順便還能夠帶來一點(diǎn)性能上的提升:當(dāng)定義對象的一個(gè)方法時(shí),它們都是使用引用創(chuàng)建的(因此所有的子對象都指向同一個(gè)函數(shù)),而不是創(chuàng)建屬于它們的單獨(dú)的拷貝。

對于那些有趣的,真正原型的集成,像ECMAScript 5標(biāo)準(zhǔn)中所定義的那樣,需要使用 Object.create(如我們在本節(jié)的前面部分所見到的).為了提醒我們自己,Object.create創(chuàng)建了一個(gè)擁有特定原型的對象,并且也包含選項(xiàng)式的特定屬性.(例如,Object.create(prototype,optionalDescriptorObject))。

我們可以在下面的示例中看到對這個(gè)的展示:

var myCar = {

  name: "Ford Escort",

  drive: function () {
    console.log( "Weeee. I'm driving!" );
  },

  panic: function () {
    console.log( "Wait. How do you stop this thing?" );
  }

};

// Use Object.create to instantiate a new car
var yourCar = Object.create( myCar );

// Now we can see that one is a prototype of the other
console.log( yourCar.name );

Object.create也允許我們簡單的繼承先進(jìn)的概念,比如對象能夠直接繼承自其它對象,這種不同的繼承.我們早先也看到Object.create允許我們使用 供應(yīng)的第二個(gè)參數(shù)來初始化對象屬性。例如:

var vehicle = {
  getModel: function () {
    console.log( "The model of this vehicle is.." + this.model );
  }
};

var car = Object.create(vehicle, {

  "id": {
    value: MY_GLOBAL.nextId(),
    // writable:false, configurable:false by default
    enumerable: true
  },

  "model": {
    value: "Ford",
    enumerable: true
  }

});

這里的屬性可以被Object.create的第二個(gè)參數(shù)來初始化,使用一種類似于我們前面看到的Object.defineProperties和Object.defineProperties方法所使用語法的對象字面值。

在枚舉對象的屬性,和(如Crockford所提醒的那樣)在一個(gè)hasOwnProperty()檢查中封裝循環(huán)的內(nèi)容時(shí),原型關(guān)系會造成麻煩,這一事實(shí)是值得我們關(guān)注的。

如果我們希望在不直接使用Object.create的前提下實(shí)現(xiàn)原型模式,我們可以像下面這樣,按照上面的示例,模擬這一模式:

var vehiclePrototype = {

  init: function ( carModel ) {
    this.model = carModel;
  },

  getModel: function () {
    console.log( "The model of this vehicle is.." + this.model);
  }
};

function vehicle( model ) {

  function F() {};
  F.prototype = vehiclePrototype;

  var f = new F();

  f.init( model );
  return f;

}

var car = vehicle( "Ford Escort" );
car.getModel();

注意:這種可選的方式不允許用戶使用相同的方式定義只讀的屬性(因?yàn)槿绻恍⌒牡脑抳ehicle原型可能會被改變)。

原型模式的最后一種可選實(shí)現(xiàn)可以像下面這樣:

var beget = (function () {

    function F() {}

    return function ( proto ) {
        F.prototype = proto;
        return new F();
    };
})();

一個(gè)人可以從vehicle函數(shù)引用這個(gè)方法,注意,這里的那個(gè)vehicle正是在模擬著構(gòu)造器,因?yàn)樵湍J皆趯⒁粋€(gè)對象鏈接到一個(gè)原型之外沒有任何初始化的概念。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號