對象在全部編程語言中都是核心內容在js中他的建立方式也是多種多樣,每一種建立方式都有其利弊,下面簡單總結一下;編程
最簡單的兩種方式之一,直接利用系統內置的Object 來建立,系統內置Object 只有不多的方法屬性,用它建立十分安全安全
var person1=new Object(); person.name='xiaoming'; person.age='18'; person.sayName=function (){ alert(this.name) } var person2=new Object(); person.name='xiaohong'; person.age='16'; person.sayName=function (){ alert(this.name) } person1.sayName();//xiaoming person2.sayName();//xiaohong
這種方式優缺點很明顯,優勢是簡單,不須要額外的代碼,直接建立就好,方法屬性都是掛在本身身上;缺點也很明顯,這東西一次只能建立一個,不適合批量建立,假設遇到重複建立那就讓人崩潰;編程語言
這個跟上面的利用Object 內置對象建立是一個意思,本質也就是同樣,{}這個東西也就是Object 的語法糖而已;函數
var person1={ name:'xiaoming', age:'18', sayName:function(){ alert(this.name); } } person.sayName(); var person2={ name:'xiaohong', age:'16', sayName:function(){ alert(this.name); } } person1.sayName(); person2.sayName();
優缺點不用說,跟上面就是一個玩意兒;測試
有了上面的缺點天然就要想辦法克服,對於相同的東西人們喜歡抽出來,類似的就集合封裝,因而有了這種東西this
function ceartPerson(name,age){ var person={ name:name, age:age, sayName:function(){ alert(this.name) } } return person; } var person1=ceartPerson('zhangshan',18); person1.sayName();//zhangshan var person2=ceartPerson('lishi',20); person2.sayName(); //lishi
咱們建立了一個函數用來返回所須要的對象,把這個對象所須要的信息經過傳參的方式傳入來構造不一樣的對象;咱們在函數ceartPerson裏面有一個原料person對象,咱們就是經過改變這個原料person對象的屬性來構造一個個對象,這種做業方式很像工廠的流水線做業,外面來一個,裏面加工一個,因此這種方式也被形象的成爲工廠模式;prototype
可是這種方式也是有本身的缺點的,第一個有些難爲強迫症患者,就是沒有new 關鍵字,對於人們建立對象的固有認知不同;
第二個相對致命,一個神奇的事情code
alert(person1.sayName===person2.sayName) //false;
這就很鬱悶了,這表明着什麼呢,這就意味着從這個工廠裏面出來的對象每個都是獨立個體,互不影響,他們之間的方法並非引用同一個地方,可是明明功能都是同樣的,因此這種方式會極大的消耗咱們的系統資源,這顯然不是咱們樂意看到的對象
第三個缺點,沒法使用instanceof 來判斷本身的來歷;在前面提到過instanceof 能夠用來斷定 對象的隱式原型和目標的原型對象是否在一條原型鏈上(更加官網的說法 instanceof運算符用於測試構造函數的prototype屬性是否出如今對象的原型鏈中的任何位置),如今使用工廠模式建立的對象卻沒法使用instanceof,這就致使原型鏈混亂,這顯然也不是咱們樂意看到的;原型鏈
var obj={}; console.log(obj instanceof Object) //true console.log(person1 instanceof ceartPerson) //false;
function CreatPerson(name,age){ this.name=name; this.age=age; this.sayName=function(){ alert(this.name) } } var person1=new CreatPerson('zhangshan',18); var person2=new CreatPerson('lishi',16); person1.sayName(); //zhangshan;
構造函數,主語是函數,因此這種東西也就是一個函數,跟其餘函數沒什麼區別,只是做用有點兒特殊而已,是用來建立對象而已,就像醫生也仍是一我的,只是工做是救人,因此咱們管他叫醫生,管教書育人的人叫老師,因此函數該有的操做構造函數都有;
這種作法比上面的工廠模式略有簡化,首先在構造函數內部並滅有顯式的建立對象,也沒有顯示的返回對象這一步,
全部的操做都在外部的new 關鍵字作了
首先new 會在構造函數裏面偷偷的建立一個對象,而後使用call 方法轉換this 指向爲該對象,而後在偷偷的返回該對象;固然這只是簡單描述構造函數的建立過程;
console.log(person1 instanceof CreatPerson) //true console.log(person1.sayName===person2.sayName) //false;
結果很明顯,每個出來的都是單獨的實例對象,方法仍是沒有共同,一樣存在了上面的問題,可是他卻解決了原型鏈的問題,可使用instanceof 來斷定他的來源;
前面提到的原型鏈頂端的存在,會讓這條原型鏈下面的存在都具備相同的方法和屬性,咱們能夠利用這個特性來建立對象試試
function CreatPerson(){};//建立一個構造函數,主要來利用這個玩意兒產生原型對象; CreatPerson.prototype.name='zhangshan'; CreatPerson.prototype.age='18'; CreatPerson.prototype.sayName=function(){ alert(this.name) } var person1=new CreatPerson(); person1.sayName();//zhangshan; var person2=new CreatPerson(); person2.name='lishi'; person2.sayName(); //lishi; alert(person1 instanceof CreatPerson) //true; console.log(person2.sayName===person1.sayName) //true;
結果證實 從Person出來的實例都是對他的高度引用,新對象實例的屬性和方法能夠重寫覆蓋;這樣作到個性化的操做;全部的實例均能共享一樣的原型對象,因此也就解決了重複建立的問題,也解決了原型混亂的問題;可是缺點也很明顯,沒辦法初始化參數,用上面的例子說明就是全部從CreatPerson 出來的對象實例的name 屬性初始化都是zhangshan,這是至關危險的操做;
既然構造函數能夠初始化參數,原型模式能夠搞定原型鏈混亂,能不能想辦法綜合一下呢?
function CreatPerson(name,age){ this.name=name; this.age=age; } CreatPerson.prototype.sayName=function(){ alert(this.name) } var person1=new CreatPerson('zhangshan',18); person1.sayName()//zhanshan var person2=new CreatPerson('lishi',16); person2.sayName()//lishi console.log(person1 instanceof CreatPerson); //true console.log(person1.sayName===person2.sayName);//true
能夠看到這種原型混合構造模式可以有效的解決建立對象過程的問題,使用構造函數加屬性,使用原型加方法;這樣既能搞定初始化參數的問題,也能解決方法重複建立的問題;他是一種較爲穩妥的方法,缺點就是寫着麻煩了點兒