JS創(chuàng)建對象的幾種方式
一. 直接創(chuàng)建Object實例
方式一:
var person = new Object();
person.name = 'zzx';
person.age = 20;
person.job = 'Programmer';
person.sayName = function(){
console.log(this.name);
};
方式二:
var person = {
name: 'zzx';
age: 20;
job: 'Programmer';
sayName: function(){
console.log(this.name);
}
}
這種方式的缺點顯而易見,每次創(chuàng)建一個對象就需要手動設置它的每一個屬性囱稽,造成大量代碼重復,JS可以使用工廠模式的變體解決這個問題
二. 工廠模式
function createPerson(name, age, job){
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
console.log(this.name);
};
return o;
}
var person1 = createPerson('zzx', 22, 'Programmer');
var person2 = createPerson('yzy', 20, 'Teacher');
console.log(person1);
//{ name: 'zzx', age: 20, job: 'Programmer', sayName: [Function] }
這種模式解決了創(chuàng)建多個相似對象的問題,但是卻不知道當前創(chuàng)建的對象是什么類型傻丝,即是Person還是Robot不能判斷出來
三. 構造函數(shù)模式
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
console.log(this.name);
};
}
function Robot(name, age){
this.name = name;
this.age = age;
}
var person1 = new Person('zzx', 22, 'Programmer');
var person2 = new Person('yzy', 20, 'Teacher');
console.log(person1 instanceof Person); //true
console.log(person2 instanceof Robot); //false
構造函數(shù)名開頭大寫借鑒了其他面向?qū)ο笳Z言,是為了區(qū)別普通函數(shù)诉儒。任何一個函數(shù)不通過new操作符調(diào)用葡缰,就是一個普通函數(shù):
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
console.log(this.name);
};
}
Person('zzx', 22, 'Programmer');
sayName(); //zzx
構造函數(shù)仍然存在缺點,就是其中的每個方法例如sayName()忱反,在每次實例化時都會自動重新創(chuàng)建一遍泛释,產(chǎn)生不同的作用域鏈,因此即使是同名函數(shù)也是不相等的温算,下面利用上述代碼創(chuàng)建兩個實例:
var person1 = new Person('zzx', 22, 'Programmer');
var person2 = new Person('yzy', 20, 'Teacher');
console.log(person1.sayName == person2.sayName); //flase
四. 原型模式
使用原型對象的好處是可以讓所有對象實例共享它所包含的屬性和方法怜校。
function Person(){
}
Person.prototype.name = 'zzx';
Person.prototype.age = 22;
Person.prototype.job = 'Programmer';
Person.prototype.sayName = function(){
console.log(this.name);
}
var person1 = new Person();
person1.sayName(); //zzx
var person2 = new Person();
console.log(person1.sayName == person2.sayName); //true
這里將sayName()方法和所有的屬性直接添加到了Person 的prototype屬性中,構造函數(shù)就成了空函數(shù)注竿,但是也能調(diào)用構造函數(shù)創(chuàng)建新對象茄茁。新隊先后的屬性和方法是所有實例共享的,person1和person2訪問的都是同一組屬性和同一個sayName()函數(shù)巩割。
要理解原型模式工作原理裙顽,先要理解原型對象。
[原型對象]http://www.reibang.com/p/b958bfd92a41
上述方式每添加一個屬性和方法都要輸入Person.prototype宣谈,因此還有更簡單的方式是以對象字面量形式創(chuàng)建:
function Person(){
}
Person.prototype = {
name: 'zzx',
age: '22',
job: 'Programmer',
sayName: function(){
console.log(this.name);
}
};
var person1 = new Person();
console.log(person1 instanceof Person); //true
console.log(person1.constrcutor == Person); //false
但這里使用的語法本質(zhì)上完全重寫了默認的prototype對象(原型對象)愈犹,因此本來會自動獲得的constructor屬性變成了新對象的constructor屬性(指向Object構造函數(shù)),不再指向Person函數(shù)闻丑,此時instanceof能返回正確的結果漩怎,但是constructor已經(jīng)無法確定對象類型了
如果constructor值真的很重要,可以通過下面這樣特意將它設置回適當?shù)闹?/p>
function Person(){
}
Person.prototype = {
constructor: Person,
name: 'zzx',
age: '22',
job: 'Programmer',
sayName: function(){
console.log(this.name);
}
};
原型模式也有缺點嗦嗡,當其中包含引用類型值屬性時會出現(xiàn)問題:
function Person(){
}
Person.prototype = {
constructor: Person,
name: 'zzx',
age: '22',
job: 'Programmer',
friends: ['wc', 'rt'],
sayName: function(){
console.log(this.name);
}
};
var person1 = new Person();
var person2 = new Person();
person1.friends.push('lol');
console.log(person1.friends); //[ 'wc', 'rt', 'lol' ]
console.log(person2.friends); //[ 'wc', 'rt', 'lol' ]
由于數(shù)組存在于Person.prototype中勋锤,當向數(shù)組中添加了一個字符串時,所有的實例都會共享這個數(shù)組(基本值可以被實例屏蔽)
五. 組合使用構造函數(shù)模式和原型模式
創(chuàng)建自定義類型的常見方式侥祭,就是組合使用構造函數(shù)模式與原型模式叁执。構造函數(shù)模式用于定義實例屬性,而原型模式用于定義方法和共享的屬性卑硫。
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ['wc', 'rt'];
}
Person.prototype = {
constructor: Person,
sayName: function(){
console.log(this.name);
}
};
六. 動態(tài)原型模式
這里只在 sayName()方法不存在的情況下徒恋,才會將它添加到原型中。
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
if(typeof this.sayName != "function"){
Person.prototype.sayName = function(){
console.log(this.name);
};
}
}
var person1 = new Person('zzx', 22, 'Programmer');
person1.sayName();
七. 寄生構造函數(shù)模式
這種模式的基本思想是創(chuàng)建一個函數(shù)欢伏,該函數(shù)的作用僅僅是封裝創(chuàng)建對象的代碼入挣,然后再返回新創(chuàng)建的對象;但從表面上看硝拧,這個函數(shù)又很像是典型的構造函數(shù)径筏。
function Person(name, age, job){
var o = new Object()
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
console.log(this.name);
}
return o;
}
var person1 = new Person('zzx', 22, 'Programmer');
person1.sayName();
這個例子中葛假,除了使用 new 操作符并把使用的包裝函數(shù)叫做構造函數(shù)之外,這個模式跟工廠模式其實是一模一樣的滋恬。