动态原型模式
动态原型模式
以构造函数模式组合原型模式在目前看来已经很完美了,硬要挑出它的缺点的话就是封装性差了点,动态原型模式正是致力于解决这个问题的一个方案:
function Person(name, age, sex){
this.name = name
this.age = age
this.sex = sex
Person.prototype.sleep = function(){
alert(this.name + '睡觉了')
}
}
将修改原型属性的代码一块写进构造函数里面。但是上面的代码还有一个问题,如果每创建出一个实例,那么就会为 Person.prototype.sleep 重新赋值,这是完全没有必要的,因此下面对此做出了一点修改:
function Person(name, age, sex){
this.name = name
this.age = age
this.sex = sex
if (typeof this.sleep !== 'function'){
Person.prototype.sleep = function(){
alert(this.name + '睡觉了')
}
}
}
typeof this.sleep !== 'function' 这句判断只会在第一次创建实例的时候为真。由于在创建第一次实例我们就为它的原型对象的属性 sleep 赋值了一个方法,所以在第二次创建新的实例的时候,这个 sleep 的类型自然为 function,判断也就不成立,也就不会再次为原型对象重复无意义的赋值操作。
那么能否再次简化代码,在内部使用字面量的方法重写 Person 的原型呢?
function Person(name, age, sex) {
this.name = name
this.age = age
this.sex = sex
if (typeof this.sleep !== 'function') {
Person.prototype = {
constructor: this,
sleep: function() {
alert(this.name + '睡觉了')
}
}
}
}
上面的代码看似没什么问题,实则有个致命的错误:
const person1 = new Person('小明', 22, '男')
const person2 = new Person('小红', 22, '女')
console.log(person1.sleep) // undefined
console.log(person2.sleep) // f()
因为在第一次创建实例的时候,内部的 if 语句在进行它的第一次判断时,第一次创建的实例的原始的原型对象(在创建Person时自动创建的原型对象)就已经存在,所以 person1 内部的原型对象的指针指向的原型对象仍旧是原始的原型对象,在第二次创建出实例 person2 的时候,它的原型指针指向的才是 if 语句中我们重写的新的原型对象。这也就造成了在 person1 访问不到原型对象的属性 sleep,而 person2 却能够正常访问到属性 sleep。

浙公网安备 33010602011771号