一:簡述html
當初學編程一看到什麼什麼模式就比較頭暈,不過本文咱們經過簡單的示例代碼來講一下js 對象這個話題 ,來看下如何理解這個原型模式。java
二:理解對象chrome
1.簡單對象編程
js對象中沒有java、C#等類的概念。可是在js中 一切皆對象嘛 咱們能夠這麼寫一個實例數組
1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> 5 <title></title> 6 </head> 7 <body> 8 9 <script> 10 //建立一個對象 11 var person = new Object(); 12 //聲明屬性 13 person.name = 'hello'; 14 person.age = 29; 15 person.job = 'Software Engineer'; 16 //聲明方法 17 person.sayName = function () { 18 alert(this.name); 19 } 20 </script> 21 </body> 22 </html>
是否是很像一個class。但這是早期js建立對象的寫法,後來出現了對象字面量的寫法 簡化了上面的寫法瀏覽器
2.對象字面量ide
咱們來改進上面的寫法 函數
1 var person = { 2 //屬性 3 name: 'hello', 4 age: 29, 5 job: 'Software Engineer', 6 //聲明方法 7 sayName: function () { 8 alert(this.name); 9 } 10 }
是否是簡化了不少,可是上面兩種建立的對象若是建立多了會產生大量重複代碼 ,因此也就出現瞭如下第三種模式(又是模式....)ui
3.工廠模式this
1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <title></title> 6 </head> 7 <body> 8 9 <script> 10 //用函數來包裝 11 function createPerson() { 12 var person = new Object(); 13 //聲明屬性 14 person.name = 'hello'; 15 person.age = 29; 16 person.job = 'Software Engineer'; 17 //聲明方法 18 person.sayName = function () { 19 alert(this.name); 20 } 21 return person; 22 } 23 //調用 24 var person1 = createPerson('tom', 21, 'baidu'); 25 var person2 = createPerson('tony', 31, 'tencent'); 26 </script> 27 </body> 28 </html>
工廠就是把東西加工、包裝成一個對象。 其實咱們大多數的寫法也就是這麼個模式 。可是這樣咱們怎麼知道這個對象的類型呢 ?隨着js發展又出來一個新模式
4.構造函數模式
1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <title></title> 6 </head> 7 <body> 8 9 <script> 10 11 12 function Person(name,age,job) { 13 this.name = name; 14 this.age = age; 15 this.job = job; 16 this.sayName = function () { 17 alert(this.name); 18 } 19 } 20 21 var pserson1 = new Person('tom', 21, 'baidu'); 22 var pserson2= new Person('tony', 31, 'tencent'); 23 </script> 24 </body> 25 </html>
看着是否是跟對象字面量很像。這個模式跟工廠模式對比來看
a.沒有顯示的建立對象
b.直接將屬性和方法賦值給了this對象
c.沒有return
d.執行構造函數中的代碼(在Person新對象中添加屬性和方法)
console.info(person1.constructor == Person);//true console.info(person1.constructor == Person);//true
對象的constructor屬性 是用來標識對象類型的 ,能夠將他的實例標識爲一種特定的類型
說說這個特殊的函數--構造函數 ,它跟函數的惟一區別就是調用的方式不一樣(有啥不一樣啊。。)
只要是能經過new操做符來調用的函數就能夠做爲構造函數。(沒new的就是普通函數唄O(∩_∩)O)
//我是構造函數 var pserson1 = new Person('tom', 21, 'baidu'); //我是普通函數 person('tony', 31, 'tencent');
構造函數模式也有本身的問題。每一個方法都要在每一個實例上從新建立一遍。
構造函數的另外一種定義:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> </head> <body> <script> function Person(name,age,job) { this.name = name; this.age = age; this.job = job; //第一種寫法 this.sayName = function () { alert(this.name); } //第二種寫法 this.sayName = new Function("alert(this.name)") } </script> </body> </html>
這樣就能夠看出person1.sayName 不等於person2.sayName了 由於不一樣實例的同名函數是不相等的
可是咱們能夠這麼寫:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> </head> <body> <script> function Person(name,age,job) { this.name = name; this.age = age; this.job = job; this.sayName = sayName } function sayName() { alert(this.name); } </script> </body> </html>
可是這樣雖然是函數指向相同了 可是方法多了 就沒有封裝性可言了 。
5.原型模式
咱們每一個函數都有一個prototype(原型)屬性。它是構造函數中(就是new的函數)自動建立的對象實例的原型對象 (就是一new就有了)
好處:可讓全部對象實例共享它包含的屬性和方法(能夠直接添)以下
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> </head> <body> <script> //聲明一個空函數(首字母大寫) function Person() { }
//添加屬性和方法 Person.prototype.name = "tony"; Person.prototype.age=29; Person.prototype.job = 'baidu'; Person.prototype.sayName = function () { alert(this.name); } var person1 = new Person(); person1.sayName();//baidu var person2 = new Person(); person2.sayName();//baidu alert(person1.sayName == person2.sayName);//true </script> </body> </html>
由於新對象的屬性和方法都是共享的,因此person1和person2都是訪問的同一個sayName函數
a.理解原型對象:
上面說到只要建立一個函數就會自動建立一個prototype屬性,這個屬性指向的就是函數的原型對象
Person.prototype.constructor就是Person
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> </head> <body> <script> //聲明一個函數(首字母大寫) function Person() { } Person.prototype.name = "tony"; Person.prototype.age=29; Person.prototype.job = 'baidu'; Person.prototype.sayName = function () { alert(this.name); } var person1 = new Person(); console.info(person1); </script> </body> </html>
chrome中打印輸出結構:
雖然person1不包含任何屬性和方法 ,可是咱們可使用person1.sayName() 這就是經過查找對象屬性來實現的
person1就是實例 Person就是原型 當實例中的屬性修改後
person1.name='1234' 不影響實例的屬性 person2沒修改 name仍是tony
delete person1.name;
這個能夠刪除person1的實例屬性 從而訪問到原型中的值
(1)咱們能夠經過hasOwnProperty方法來判斷自己是否有這個屬性(就是判斷本身有沒有該屬性 返回true、false)
1 <script> 2 //聲明一個函數(首字母大寫) 3 function Person() { 4 5 } 6 Person.prototype.name = "tony"; 7 Person.prototype.age=29; 8 Person.prototype.job = 'baidu'; 9 Person.prototype.sayName = function () { 10 alert(this.name); 11 } 12 var person1 = new Person(); 13 alert(person1.hasOwnProperty('name'));//false 14 person1.name = '123';//我本身從新賦值 有了該屬性 15 alert(person1.hasOwnProperty('name'));//true 16 console.info(person1); 17 </script>
(2)經過 in操做符來判斷(單獨使用和在for循環中)
1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <title></title> 6 </head> 7 <body> 8 <script> 9 //聲明一個函數(首字母大寫) 10 function Person() { 11 12 } 13 Person.prototype.name = "tony"; 14 Person.prototype.age=29; 15 Person.prototype.job = 'baidu'; 16 Person.prototype.sayName = function () { 17 alert(this.name); 18 } 19 var person1 = new Person(); 20 alert(person1.hasOwnProperty('name'));//false 21 alert('name' in person1) //true 22 person1.name = '123';//我本身從新賦值 有了該屬性 23 alert(person1.hasOwnProperty('name'));//true 24 alert('name' in person1) //true 25 26 </script> 27 </body> 28 </html>
能夠看到in能夠訪問到原型中去查找也就返回了都是true 而hasOwnProperty只在自己查找
(3)我只想看是否在原型中的屬性 使用hasPrototypeProperty (在原型中不在實例中的屬性)
(4)像in的用法在ie等瀏覽器中是有bug的 因此es5提供了 Object.keys() 方法來獲取全部枚舉屬性
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> </head> <body> <script> //聲明一個函數(首字母大寫) function Person() { } Person.prototype.name = "tony"; Person.prototype.age=29; Person.prototype.job = 'baidu'; Person.prototype.sayName = function () { alert(this.name); } var keys = Object.keys(Person.prototype); alert(keys);//name,age,job,sayName var person1 = new Person(); person1.name = '123';//我本身從新賦值 有了該屬性 var keys2 = Object.keys(person1.prototype); alert(keys2);//name </script> </body> </html>
上面原型寫法徹底能夠用對象字面量的形勢簡寫(注意字面量寫法中的紅字)
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> </head> <body> <script> //聲明一個函數(首字母大寫) function Person() { } Person.prototype = {
constructor:Person,//修正構造函數從新指向本身 name: "tony", age: 29, job: 'baidu', sayName: function () { alert(this.name); } } //Person.prototype.name = "tony"; //Person.prototype.age=29; //Person.prototype.job = 'baidu'; //Person.prototype.sayName = function () { // alert(this.name); //} </script> </body> </html>
原型模式最大的問題是共享的本性致使的 。裏面包含引用類型好比數組 也會跟着共享
因此原型模式通常不會單獨出現
6.組合使用構造函數模式和原型模式
構造函數模式用來定義實例屬性
原型模式用來定義方法和共享的屬性
這種混合模式是目前es中使用最普遍和認同度最高的一種自定義類型的方法 這也是引用類型的一種默認方式
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> </head> <body> <script> //聲明一個函數(首字母大寫) function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.friends = ["lili","tonk"]; } Person.prototype = { constructor: Person, sayName: function () { alert(this.name); } } var person1 = createPerson('tom', 21, 'baidu'); var person2 = createPerson('tony', 31, 'tencent'); person1.friends.push('van'); console.info(person1.friends);//lili、tonk、van console.info(person2.friends);//lili、tonk console.info(person1.friends == person2.friends);//false console.info(person1.sayName == person2.sayName);//true </script> </body> </html>