动态原型模式

  • A+
所属分类:Web前端
摘要

​ 以构造函数模式组合原型模式在目前看来已经很完美了,硬要挑出它的缺点的话就是封装性差了点,动态原型模式正是致力于解决这个问题的一个方案:


动态原型模式

​ 以构造函数模式组合原型模式在目前看来已经很完美了,硬要挑出它的缺点的话就是封装性差了点,动态原型模式正是致力于解决这个问题的一个方案:

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