文章目录
- 原型模式
- 动态原型模式
原型模式
在JS中,每一个函数被定义之后,就会为这个函数创建一个prototype
属性,该属性指向了这个函数的原型对象。
那原型对象能在对象的构造中发挥多大的作用呢?先看一个例子
function Person(){
this.name = 'Tom';
this.age = 22;
this.sayHi = function(){
console.log('Hello');
}
}
let personA = new Person();
let personB = new Person();
console.log(personA.sayHi === personB.sayHi); //false
可以看到创建的两个person
对象的sayHi
方法是不一样的,这就意味着每一次Person
类的实例被创建都要重新创建一遍sayHi
方法,这十分浪费时间跟空间。
而引入原型对象之后,就可以比较好的解决这个问题。
function Person(){
this.name = 'Tom';
this.age = 22;
}
Person.prototype.sayHi = function(){
console.log('Hello');
};
let personA = new Person();
let personB = new Person();
console.log(personA.sayHi === personB.sayHi); //true
通过原型对象可以在多个实例之间共享一些属性而不必重复创建。
然而使用原型对象也会存在问题,如下面的例子
function Person(){
this.name = 'Tom';
this.age = 22;
}
Person.prototype={
constructor: Person,
friends: []
};
let personA = new Person();
let personB = new Person();
personA.friends.push('Paul');
console.log(personB.friends); //['Paul']
在原型中定义了一个friends
数组,我用personA来访问friends
数组并往里添加了一个’Paul’。然而,在访问personB的friends
数组的时候,发现也有’Paul’。
这是因为原型对象解决的就是一个共享的问题,然而成也共享,败也共享。原型对象可能会让一些不需要实例间共享的属性被共享。
解决方法也很简单,只要我们不把不想被共享的属性放进原型对象里就可以了。
动态原型模式
把构造方法和原型对象分开写可能不够优雅,那么动态原型模式就是一种较为优雅的解决方案。
function Person(name, age){
this.name = name;
this.age = age;
if(typeof this.saiHi != 'Function'){
Person.prototype.sayHi = function(){
console.log('Hello');
}
}
}
这个构造函数仅会在第一次调用的时候设置原型对象,因为第一次设置完了之后原型对象上就有了sayHi
这个方法。