我们在上篇说到了工厂模式和构造函数模式,结尾说到解决构造函数模式的缺点的方法是引入了原型模式,本篇就来说说原型模式及其与构造函数模式的组合使用。
一、原型模式
首先要理解:我们创建的每一个函数都有一个prototype(原型)属性,该属性是一个指针,指向一个对象,该对象的用途就是包含特定类型所有实例共享的属性和方法。
举个例子: 我们定义一个构造函数Person;那么他的prototype属性所指的对象包含着所有Person的实例所共享的属性和方法;且该对象就是Person所有实例
的原型对象
使用原型的好处是:所有实例可以共享原型对象中的属性和方法;举例如下:
function Person() {
}
Person.prototype.name = 'Jack';
Person.prototype.friends = ['Lily', 'John'];
var person1 = new Person();
var person2 = new Person();
console.log(person1.name);//Jack
console.log(person2.name);//Jack
由于person1和person2都是Person的实例,所以都能访问他们共同的原型对象上的name属性。
然而,原型模式也有缺点,继续上边的代码执行以下代码:
person1.friends.push('Lucy');
console.log(person1.friends);//["Lily", "John", "Lucy"]
console.log(person2.friends);//["Lily", "John", "Lucy"]
由于friends属性定义在原型对象上,所以一旦改变,所有实例都会改变,显然实际中这不是我们期望的,我们希望各自的friends属性互不影响;为解决这一问题,我们采用了原型模式和构造函数的组合使用;
二、组合使用原型模式和构造函数模式
继续上边的例子,我们将实例需要独自拥有的属性或方法定义在构造函数里边,将共享的属性或者方法定义在原型对象中,举例如下:
function Person(name) {
this.name=name;
this.friends=['Jack'];
}
Person.prototype.sayName=function(){
console.log(this.name);
};
var person1 = new Person('Alice');
var person2 = new Person('Bob');
person1.sayName();//Alice
person2.sayName();//Bob
person1.friends.push('Lucy');
console.log(person1.friends);//["Jack", "Lucy"]
console.log(person2.friends);//["Jack"]
可以看到,构造函数里边的name和friends属性各实例分别拥有自己的一份,不会互相干扰,sayName方法所有实例共享。