對象的定義:無序屬性的集合,屬性的值能夠是基本值、對象或者函數.
每一個對象都是基於一個應用類型建立的,這個引用類型能夠是內置的(例如Object Array Math),也能夠是用戶自定義的. web
全部的對象都是繼承自Object的,所以咱們能夠從Object着手建立對象. 設計模式
//經過new 關鍵字建立對象 var person = new Ojbect(); person.name = 'yuhualinfeng'; person.age = 30; person.job = 'web developer'; //經過對象字面量建立對象 var person = {}; person.name = 'yuhualinfeng'; person.age = 30; person.job = 'web developer';
基於Object建立對象有兩種形式,一種是使用new關鍵字,另外一種是使用對象字面量.
使用這種方式建立對象的缺點是:當建立多個相同類型的對象時,會產生許多重複的代碼,假如我要三個person對象,我就須要寫三相同結構的代碼,爲了解決這個問題,咱們引入了工廠模式建立對象. ide
工廠模式是軟件工廠領域一種廣爲認知的設計模式,這種模式抽象了建立具體對象的過程. 函數
function createPerson(name,age,job){ var obj = new Object(); obj.name = name; obj.age = age; obj.job = job; return obj; } var person1 = createPerson('yuhualingfeng',30,'web developer'); var person2 = createPerson('obama',45,'president');
咱們建立了兩我的物對象,假如咱們基於Object建立對象,那麼createPerson內的代碼就會重複編碼.
可是使用這種模式建立的對象任然有一個問題:沒法得知建立的對象的類型名.解決這問題的可行方法是使用構造函數建立對象. this
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); } } var person1 = new Person('yuhualingfeng',30,'web developer'); var person2 = new Person('obama','45','president');
這裏咱們建立了一個名爲Person的引用類型,而後咱們用new 關鍵字實例化此引用類型,這個過程能夠細化爲如下四個過程: 編碼
建立一個新對象 spa
將構造函數的做用域賦值給新函數(所以this就指向這個新對象) prototype
執行構造函數中的代碼(爲this對象賦值,等同於爲新對象賦值) 設計
返回新對象 指針
咱們能夠用instanceof來檢測person1,person2的對象類型是否爲Person.
alert(person1 instanceof Person); //true alert(person2 instanceof Person); //true alert(person1 instanceof Object); //true 由於Person繼承自Object,因此這裏同樣成立.
注:細心的朋友應該會注意到,這裏的構造函數的首字母是大寫,這裏們遵循一個規範,普通函數的首字母大寫,普通函數的首字母小寫.
構造函數也有本身的缺點,你們能夠看到Person包含一個sayName的函數(方法),函數也是對象(函數式Function的實例),因此每實例化一個Person,就會產生一個sayName方法,也就是一個對象,
隨着建立的person實例怎多,產生的對象也相應增多,最終致使更多的內存,那麼咱們能不能找到更好的解決辦法呢,是確定的.
咱們每建立一個函數都有一個prototype(原型)屬性,這個屬性是一個指針,指向一個對象而這個特定對象的用途是包含能夠由特定類型的全部實例共享的屬性和方法.這就意味着原型對象不會由於實例的增多二佔用
更多的內存.每一個原型對象都默認有一個constructor屬性,故名思議,這個屬性指向構造函數.下面展現了經過原型對象來建立對象.
function Person(){ } Person.prototype.name = "yuhualingfeng"; Person.prototype.age = 30; Person.prototype.job = "web developer"; Person.prototype.sayName=function(){ alert(this.name); }; var person1 = new Person(); person.sayName(); //yuhualingfeng var person2 = new Person();
這裏Person.prototype.constructor指向的是Person.固然你也能夠向下面這樣直接給原型對象賦值來建立對象.
Person.prototype={ constructor:Person, name:"yuhualingfeng", age:30, job:"web developer" };
這裏之因此添加了constructor屬性是應爲直接給原型對象賦值會把原型對象的指針指向另外一個對象,之前默認的值將沒法訪問到.
順便給你們介紹兩個與原型對象相關的方法和in關鍵字:
isPrototypeOf:判斷是某對象否爲實例的原型.
alert(Person.prototype.isPrototypeOf(person)); //true
hasOwnProperty:檢測某屬性是存在於實例中,仍是原型對象中.
alert(person1.hasOwnProperty('name')); //false,由於屬性存在於原型中.
in操做符:in操做符有兩種使用方式,一種是單獨使用,一種是和for搭配使用,單獨使用的做用是判斷某屬性是否在某實例中訪問到(不管是在實例自身的仍是原型對象中的),for-in是枚舉(循環)中使用.
//判斷屬性是否存在原型中 function hasPrototypeProperty(object,name){ return object.hasOwnProperty(name) && (name in object); }
原型模式建立對象的缺點:實例的原型對象是共享的,當修改一個實例的屬性,若是屬性的值爲方法或者基本類型時,不會有什麼影響,當屬性爲引用類型時,會影響其餘實例的屬性值.
綜合構造函數模式和原型模式建立對象,咱們結合他們的優勢,去粗取精,咱們組合使用構造函數模式原型模式.
經過構造函數建立對象的缺點是每一個方法都會在實例上從新建立,形成沒必要要的內存消耗;經過原型建立對象的缺點在於實例引用類型值的屬性會相互影響.綜上考慮,咱們能夠把存儲值得屬性放在構造函數中,把方法放在原型對象中.這種模式是建立對象使用最普遍的一種,能夠說是建立對象的默認模式.
function Person(name,age,job){ this.name = name; this.age = age; this.job = job; } Person.prototype = { constuctor:Person, sayName:function(){ alert(this.name); } }; var person = new Person('yuhualingfeng',30,'web developer'); person.sayName();
以上就是建立對象的幾種模式,你們能夠結合它們的優缺點和你自身建立對象的用處進行權衡,而後選擇適合你的建立對象的模式.