创建对象
创建对象的四种模式:工厂模式、构造函数模式、原型模式、组合使用构造函数和原型模式
- 工厂模式
function sayName(){
return this.name;
}
function createPerson(name,age,gender){
var o = new Object();
o.name = name;
o.age = age;
o.gender = gender;
/*o.sayName = function(){
return this.name;
};*/
o.sayName = sayName;
return o;
/*return {
name:name,
age:age,
gender:gender,
sayName:function(){
return this;
}
}*/
}
var o1 = createPerson('Tom',18,'男');
var o2 = createPerson('Mary',16,'女');
console.log(o1.constructor);//[Function: Object]
console.log(o2.constructor);//[Function: Object]
console.log(o1.sayName===o2.sayName);//false->true
当在对象中定义sayName
时,相当于每次创建一个新对象,都会在内存中重新开辟一个新的空间存放sayName
方法,所以o1.sayName===o2.sayName
为false
,因为两者的sayName
方法内存地址不同。而通过声明函数声明的sayName
,在内存中的内存地址不变,所以返回true
。
工厂模式的问题:工厂模式创建的所有对象都是Object类型,且工厂模式每创建一个对象,其对象的方法就会开辟一个新的内存空间,耗费内存资源。
- 构造函数模式
function sayName(){
return this.name;
}
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
/*this.sayName = function(){
alert(this.name);
} */
this.sayName = sayName;
}
var p1 = new Person("terry",11,"boss");
var p2 = new Person("larry",12,"daBoss");
console.log(p1.constructor);//[Function: Person]
console.log(p1.sayName===p2.sayName);//false->true
使用new关键字调用构造函数创建对象的步骤:
- 创建一个新对象
- 将构造函数的作用域赋给新对象(this指向这个新对象)
- 执行构造函数中的代码
- 返回新对象
构造函数的问题:每个方法都需要在每个实例上重新创建一遍,但是毫无必要。可以通过在全局作用域中声明一个函数,然后将引用传递给对象中的函数属性,但是这样会导致全局函数过多,体现不了对象的封装性。
- 原型模式
原型语法:
创建了自定义的构造函数之后,会同时创建它的prototype
对象,其原型对象默认会取得constructor
属性;当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。(指向的是原型对象而不是构造函数)
function Person(){}
Person.prototype.name = 'z';
Person.prototype.friends = [];
Person.prototype.sayName = function(){
console.log(this.name);
};
var p1 = new Person();
console.log(p1.name);//z
var p2 = new Person();
console.log(p2.name);//z
p1.friends.push('tom');
console.log(p1.friends);//[ 'tom' ]
console.log(p2.friends);//[ 'tom' ]
console.log(p1.sayName===p2.sayName);//true
更简单的原型语法:
将原型对象设置为等于一个以对象字面量形式创建的新对象,实例对象使用效果相同,但是原型中的constructor
属性不再指向Person
。因为每创建一个函数,就会同时创建它的prototype
对象,这个对象也自动获得constructor
属性。这里重写了prototype
对象因此新创建的原型中constructor
属性指向就不再是Person
,所以往Person
的父级寻找,最后指向Object
。
function Person(){}
Person.prototype={
name:'yoyo',
friends:[],
sayName:function(){
console.log(this.name);
}
}
原型对象的问题:所有实例在默认情况下都将取得相同的属性值,这种共享对于函数来说非常合适,但是包含引用数据类型的值就不太好
- 组合使用构造函数模式和原型模式
构造函数用于定义实例属性,原型模式用于定义方法和共享属性。
function Person(name,age){
this.name = name;
this.age = age;
this.friends = [];
}
Person.prototype = {
constructor:Person,
sayName:function(){
return this.name;
}
};
var p1 = new Person('Tom',18);
var p2 = new Person('Jerry',16);
p2.friends.push('Mary');
console.log(p1);//Person { name: 'Tom', age: 18, friends: [] }
console.log(p2);//Person { name: 'Jerry', age: 16, friends: [ 'Mary' ] }
console.log(p1.sayName());//Tom