一、工厂模式
function createCar(color,type){
var car = new Object();
car.color = color;
car.type = type;
car.sayColor = function(){
alert(this.color);
};
return car;
}
var car1 = createCar('red','CDV');
var car2 = createCar('blue','SUV');
car1.sayColor(); //red
car2.sayColor(); //blue
console.log(car1);
console.log(car2);
运行结果:
-
特点:用函数来封装创建对象的细节,内部最终返回一个对象。
-
优点:解决了创建多个相似对象的问题
-
缺点:不能确定对象的类型(即无法用 instanceof 去判断)
二、构造函数模式
function Car(color,type){
this.color = color;
this.type = type;
this.sayColor = function(){
alert(this.color);
};
}
var car1 = new Car('red','CDV');
var car2 = new Car('blue','SUV');
car1.sayColor(); //red
car2.sayColor(); //blue
console.log(car1);
console.log(car2);
console.log(car1 instanceof Car);
1、特点:
-
- 没有显式创建对象
- 属性和方法赋给了this
- 没有 return 语句
2、调用过程:
-
- 使用new操作符创建一个新对象
- 将构造函数的作用域赋给新对象(this就指向了新对象)
- 执行构造函数里的代码
- 返回新对象
3、优点:可将实例标识为一种特定类型(比如car1的类型就是Car,可用instanceof判断)
4、缺点:每个方法都要在每个实例上重新创建一遍。可以将其写在外部共享,但又失去了封装性。如下:
function Car(color,type){
this.color = color;
this.type = type;
}
function sayColor(){
alert(this.color);
}
var car1 = new Car('red','CDV');
var car2 = new Car('blue','SUV');
sayColor.call(car1); //red,这里通过call来改变作用域
sayColor.call(car2); //blue,这里通过call来改变作用域
console.log(car1);
console.log(car2);
console.log(car1 instanceof Car);
三、原型模式
function Car(){
}
Car.prototype.color = 'red';
Car.prototype.type = 'SUV';
Car.prototype.sayColor = function(){
alert(this.color);
}
var car1 = new Car();
var car2 = new Car();
car1.sayColor(); //red 来自原型
car2.sayColor(); //red 来自原型
car1.color = 'blue'; //屏蔽了原型的color,但没有覆盖,原型的color还在
alert(car1.color); //blue 来自实例
alert(car2.color); //red 来自原型
1、原型、构造函数与实例的关系:每个构造函数都有一个原型对象(prototype属性),原型对象包含一个指向构造函数的指针(constructor),实例包含一个指向原型对象的指针(__proto__)。实例与构造函数没有直接关系。
2、访问一个对象属性的过程:在上面代码中,比如car2.color ,先问car2实例上有color属性吗?没有,则查找原型,car2原型上有color属性吗?有,则返回。再比如car1.color ,先问car1上有color属性吗?有,则返回。就不需要查找原型了。
3、判断属性是否存在于实例中:hasOwnProperty() , true——实例
4、优点:属性和方法可以共享,并且可以在实例上重新定义属性,而不改变原型。
5、缺点:由于共享,对于引用类型,在实例上进行修改,也会改变原型的值。如下:
function Person(){
}
Person.prototype = {
constructor:Person, //防止一些操作切断构造函数与原型的关系
name:'Jemma',
friends:['Lucy','Jack']
}
var person1 = new Person();
var person2 = new Person();
console.log(person1.name); //Jemma
console.log(person2.name); //Jemma
//改变基本类型的属性
person1.name = 'King';
console.log(person1.name); //King
console.log(person2.name); //Jemma
//改变引用类型
person1.friends.push('Marry');
console.log(person1.friends); //["Lucy", "Jack", "Marry"]
console.log(person2.friends); //["Lucy", "Jack", "Marry"]
四、构造函数+原型模式(一般使用这个)
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype = {
constructor:Person, //防止一些操作切断构造函数与原型的关系
sayName:function(){
alert(this.name);
}
}
var person1 = new Person('Jemma',19);
var person2 = new Person('King',21);
console.log(person1.name); //Jemma
console.log(person2.name); //King
person1.sayName(); //Jemma
person2.sayName(); //King
特点:所有实例共享的属性和方法原型中定义;自己独有的在构造函数定义。
优点:既可以共享,又有特定类型。
其实关于这些细节可以讲很多东西,我这里只是简单总结一下。