创建对象的模式
創建對象的模式
1.工廠模式
工廠模式抽象了創建具體對象的過程,使用一個函數,封裝以特定接口創建對象的細節。
function createPerson(name, age, job){var o = new Object();o.name = name;o.age = age;o.job = job;o.sayName = function(){alert(this.name);}; return o; }var person1 = createPerson("Nicholas", 29, "Software Engineer"); var person2 = createPerson("Greg", 27, "Doctor");person1.sayName(); //"Nicholas" person2.sayName(); //"Greg"缺點:無法知道一個對象的類型。
2.構造函數模式
function Person(name, age, job){this.name = name;this.age = age;this.job = job;this.sayName = function(){alert(this.name);}; }var person1 = new Person("Nicholas", 29, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor");person1.sayName(); //"Nicholas" person2.sayName(); //"Greg"缺點:無法達到函數復用,每實例化一個新對象,就會創建一個新的函數對象。
function Person(name, age, job){this.name = name;this.age = age;this.job = job;this.sayName = sayName; }function sayName(){alert(this.name); }把函數單獨放在外面,每次調用函數時,只是相當于指針調用,但是不符合全局作用域,因為它只是單獨為實例對象服務的。
3.原型模式
function Person(){ }Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){alert(this.name); };var person1 = new Person(); person1.sayName(); //"Nicholas"var person2 = new Person(); person2.sayName(); //"Nicholas"上面每天添加一個屬性和方法,就要敲一遍Person.prototype。為減少輸入,也為了從視覺上更好封裝原型的功能。更常用的做法是用一個包含所有屬性和方法的對象字面量來重寫怎個原型對象
function Person(){ }Person.prototype = {name : "Nicholas",age : 29,job: "Software Engineer",sayName : function () {alert(this.name);} };var friend = new Person(); alert(friend instanceof Object); //true alert(friend instanceof Person); //true alert(friend.constructor == Person); //false alert(friend.constructor == Object); //true但是上面的方法還存在一個問題,那就是constructor屬性不在指向Person()了。每創建一個函數,就會同時創建它的prototype對象,這個對象也會自動獲得constructor屬性。而我們在這里重寫了默認的prototype對象,constructor屬性作為prototype對象的屬性,在這也就被改寫了,沒有寫就認為是Object()這個原始構造函數。
function Person(){ }var friend = new Person();Person.prototype = {constructor: Person,name : "Nicholas",age : 29,job : "Software Engineer",sayName : function () {alert(this.name);} };friend.sayName(); //error重寫原型對象切斷了現有原型與任何之前已經存在的對象實例之間的聯系
原型模式缺點:
(1)首先,這個構造函數沒有參數,省略了為構造函數初始化參數這一環節,結果所有實例在默認情況下都取得相同的屬性值。使用原型方式,不能通過給構造函數傳遞參數來初始化屬性的值,這意味著必須在對象創建后才能改變屬性的默認值,這點很令人討厭。
function Car() { }Car.prototype.color = "blue"; Car.prototype.doors = 4; Car.prototype.mpg = 25; Car.prototype.showColor = function() {alert(this.color); };var oCar1 = new Car(); var oCar2 = new Car();(2)真正的問題出現在屬性指向的是對象,而不是函數時。函數共享,基本屬性值共享不會造成問題,但對象卻很少被多個實例共享。因為對象是屬于引用類型值,在原型里面的是它的指針,當修改它的值時,不會創建副本,而是直接修改原來的值
function Car() { }Car.prototype.color = "blue"; Car.prototype.doors = 4; Car.prototype.mpg = 25; Car.prototype.drivers = new Array("Mike","John");//引用類型值 Car.prototype.showColor = function() {alert(this.color); };var oCar1 = new Car(); var oCar2 = new Car();oCar1.drivers.push("Bill");alert(oCar1.drivers); //輸出 "Mike,John,Bill" alert(oCar2.drivers); //輸出 "Mike,John,Bill"function Person(){ }Person.prototype = {constructor: Person,name : "Nicholas",age : 29,job : "Software Engineer",friends : ["Shelby", "Court"],//引用類型值sayName : function () {alert(this.name);} };var person1 = new Person(); var person2 = new Person();person1.friends.push("Van");//friends是引用類型值,這里是它的一個指針,所以修改它,在下面兩個實例對象上都會體現出來alert(person1.friends); //"Shelby,Court,Van" alert(person2.friends); //"Shelby,Court,Van" alert(person1.friends === person2.friends); //true4.混合的構造函數/原型方式
混合模式是最常見的模式
function Person(name, age, job){this.name = name;this.age = age;this.job = job;this.friends = ["Shelby", "Court"]; }Person.prototype = {constructor: Person,sayName : function () {alert(this.name);} };var person1 = new Person("Nicholas", 29, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor");person1.friends.push("Van");alert(person1.friends); //"Shelby,Court,Van" alert(person2.friends); //"Shelby,Court" alert(person1.friends === person2.friends); //false alert(person1.sayName === person2.sayName); //true5.動態原型模式
動態原型方法的基本想法與混合的構造函數/原型方式相同,即在構造函數內定義非函數屬性,而函數屬性則利用原型屬性定義。唯一的區別是賦予對象方法的位置。
function Car(sColor,iDoors,iMpg) {this.color = sColor;this.doors = iDoors;this.mpg = iMpg;this.drivers = new Array("Mike","John");if (typeof Car._initialized == "undefined") {Car.prototype.showColor = function() {alert(this.color);};Car._initialized = true;} }直到檢查 typeof Car._initialized 是否等于 "undefined" 之前,這個構造函數都未發生變化。這行代碼是動態原型方法中最重要的部分。如果這個值未定義,構造函數將用原型方式繼續定義對象的方法,然后把 Car._initialized 設置為 true。如果這個值定義了(它的值為 true 時,typeof 的值為 Boolean),那么就不再創建該方法。簡而言之,該方法使用標志(_initialized)來判斷是否已給原型賦予了任何方法。該方法只創建并賦值一次,傳統的 OOP 開發者會高興地發現,這段代碼看起來更像其他語言中的類定義了。
總結:
目前使用最廣泛的是混合的構造函數/原型方式。此外,動態原始方法也很流行,在功能上與構造函數/原型方式等價??梢圆捎眠@兩種方式中的任何一種。不過不要單獨使用經典的構造函數或原型方式,因為這樣會給代碼引入問題。
轉載于:https://www.cnblogs.com/YeChing/p/6346390.html
總結
- 上一篇: 关于微信小程序的尺寸关系
- 下一篇: 支付宝福卡怎么最快