1、前言javascript
上一篇介紹了對象的基本簡單的概念和對象的數據屬性和訪問器屬性,以及對這兩種屬性類型的一些操做,接來講一下與建立對象的模式。html
2、建立對象的方式java
(1)工廠模式編程
這種模式就是經過建立一個Object對象,並將屬性和方法保存在Object對象中,將Object對象返回。函數
function createPerson(name, age, job){ var obj = new Object();//經過建立Object來保存傳遞進來的屬性 obj.name = name; obj.age = age; obj.job = job; obj.sayName = function(){ console.log(this.name); } return obj;//返回建立對象 } var person1 = createPerson('jiang', 12, 'software'); person1.sayName();
在上面的例子中,聲明一個createPerson()的函數,這個函數接受三個參數,而在函數體中實例化一個Object對象,來接收傳遞進來的參數,最後將建立的對象返回,這樣子就能得到一個person對象。這種模式是一種廣爲人知的設計者模式,抽象了建立具體對象的過程。這種模式雖然解決了建立多個類似對象的問題,可是並無結局對象識別的問題。而接下來的構造函數就解決了這樣的問題this
(二)構造函數模式spa
在大多數的面向對象編程,構造函數主要用來在建立對象時初始化對象, 即爲對象成員變量賦初始值,總與new一塊兒使用在建立對象的語句中。特別的一個類能夠有多個構造函數 ,可根據其參數個數的不一樣或參數類型的不一樣來區分它們,即構造函數的重載(在javascript中並無重載這個概念)。構造函數模式解決了對象識別的問題,它能夠用來建立特定類型的對象。prototype
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ console.log(this.name); } }
這種方式與工廠模式相比設計
1.沒有顯示的建立對象
2.直接將屬性和方法賦給了this對象
3.沒有return語句指針
var person = new Person('jiang', 13, 'sfs'); person.sayName();
經過new操做符建立實例,須要經歷一下的步驟
-> 建立一個新對象
-> 將構造函數的做用域賦給了新對象,(所以this也就指向了新對象)
-> 執行構造函數中的代碼(爲該新對象添加屬性)
-> 返回新對象
在兩個不一樣的實例,雖然是兩個不一樣的實例,但這兩個對象都有一個constructor屬性指向Person,因此也能夠看出,構造函數模式對於工廠模式在於對象識別的區別
var person2 = new Person('zhen', 13, 'sfs'); person2.sayName(); console.log(person.constructor == Person);//true console.log(person2.constructor == Person);//true
所謂構造函數模式,其實也是函數。跟其餘函數的區別就在於調用的方式,任何函數經過new操做符來調用的,就是構造函數,若是不是經過new操做符調用的就是普通的函數。
固然構造函數並非完美的,其問題就在於,每一個方法都要在實例上從新建立一次,也就是說兩個實例的方法是不相等的。這樣使得有些多餘。佔用內存。
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = sayName; } function sayName(){ console.log(this.name); }
將對象內的方法提取到構造函數外面,能夠減小同一方法的重複定義。可是這種方式也很差,因而出現了一下的原型模式
(三)原型模式
prototype 每一個函數都有的屬性,是指向一個對象的指針,包含了能夠有特定類型的全部實例共享的屬性和方法,換句話說,prototype就是經過調用函數而建立的對象實例的原型對象,其好處就是可讓全部對象實例共享包含的屬性和方法。
function Person(){} Person.prototype.name = 'jiang'; Person.prototype.age = 15; Person.prototype.job = 'sf'; Person.prototype.sayName = function(){ console.log(this.name); }; var person = new Person(); person.sayName();
首先聲明一個空的函數。將對象的方法和屬性都放到prototype屬性上。這樣使用構造函數的方式建立新對象,新對象也會擁有相同的屬性和方法。那麼有人就會問了,Person函數中分明是空的,那麼爲什麼建立出來的新對象會有這些屬性和方法呢?那麼首先就要了解一下什麼是原型對象。
(a)原型對象
當咱們建立一個新的函數的同時,與之同時prototype會做爲新函數的屬性被建立出來,而這個屬性呢就是一個指針,會指向新函數的原型對象。而在默認狀況下原型對象就會得到一個constructor(構造函數)屬性,這個屬性又指向了咱們建立的新函數。上面的例子Person.prototype.constructor,就是咱們的Person上面例子用一張圖片來講明一下
Person函數中的prototype屬性指向了Person.prototype,同時Person.prototype.constructor又指向了Person函數,當咱們實例化person1對象時,這個對象內部也含有一個prototype指針指向了Person.prototype對象。
在上面的例子中。Person對象的全部屬性和方法都賦值給了原型對象,也就是在Person對象並無這些屬性,因此實例出來的person1對象中也沒有這些屬性,只有一個指向原型對象的指針,那麼實例化出來的對象不是至關與沒有東西。可是若是person1.name又是有數據的。這就涉及到了原型模式的搜索機制
(b)原型模式的搜索機制
原型對象的遍歷方式,先從實例自己開始,搜索給定的屬性的名稱,全部實例中是否有這個屬性的值,若是有就返回,若是沒有就全部原型中是否存在,存在就返回這個屬性的值
原型中會存在屏蔽原理,當咱們爲實例添加一個屬性是,這個屬性就會屏蔽原型中同名的屬性,也就是當咱們訪問實例中的某個屬性時,若是該屬性存在,就會返回該屬性不會在搜索原型中的同名屬性屬性,若是使用delete操做符刪除實例中的屬性時,就會回覆對原型中同名屬性的鏈接。
(c)原型模式的簡寫方式
Person.prototype = { name: 'jiang', age: 14, job: 'sf', sayName: function(){ console.log(this.name); } }
以上重寫後,起原型的constructor再也不指向Person,而是指向了Object,由於這樣設置的話就至關與一個以字面量形式建立的新對象,在本質上已經徹底重寫了默認的prototype對象,所以prototype的constructor再也不指向原來的Person。除非本身指定constructor:Person。
//或者重設構造函數 Object.defineProperty(Person.prototype, 'constructor', { enumerable:false, value: Person });
這樣的寫法,就能夠將原型對象中的構造函數屬性從新指向了Person。
原型模式雖然解決了工廠模式和構造函數模式的缺點,當仍然不是完美的模式。此次先吹水吹到這了