JavaScript中创建对象的模式汇总(2)

使用Person构造函数和Person.prototype创建实例的代码为例,展示个对象之间的关系

 

图中展示了Person构造函数、Person的原型属性以及Person的两个实例,之间的关系。Person.prototype指向了原型对象,Person.prototype.constructor有指回了Person。原型对象中除了包含constructor属性,还包含后来添加的其他属性和方法,Person的两个实例person1和person2都包含一个内部属性,该属性仅指向Person.prototype。

sayName()方法的调用过程:

在person1实例上查找logName()方法,发现没有这个方法,于是追溯到person1的原型

在person1的原型上查找sayame()方法,有这个方法,于是调用该方法

基于这样一个查找过程,我们可以通过在实例上定义原型中的同名属性,来阻止该实例访问原型上的同名属性,需要注意的是,这样做并不会删除原型上的同名属性,仅仅是阻止实例访问。

function Person() {} Person.prototype.name ="Nicholas"; Person.prototype.age = 22; Person.prototype.job = "software Engineer"; Person.prototype.sayName(){ alert(this.name); }; var person1 = new Person(); var person2 = new Person(); person1.name="Greg" alert(person1.name) //Greg 来自实例 alert(person2.name) //Nicholas 来自原型

使用delete操作符可以完全删除实例属性

delete person1.name; alert(person1.name) //Nicholas 来自原型

使用hasOwnProperty()方法可以检测一个属性是存在于实例还是原型中

function Person() {} Person.prototype.name ="Nicholas"; Person.prototype.age = 22; Person.prototype.job = "software Engineer"; Person.prototype.sayName(){ alert(this.name); }; var person1 = new Person(); var person2 = new Person(); alert(person1,hasOwnProperty("name"));//false person1.name="Greg" alert(person1.name) //Greg 来自实例 alert(person1,hasOwnProperty("name"));//true alert(person2.name) //Nicholas 来自原型 alert(person2,hasOwnProperty("name"));//false delete person1.name; alert(person1.name) //Nicholas 来自原型 alert(person1,hasOwnProperty("name"));//false

下图展示了在不同情况下实例与原型之间的关系

这里写图片描述

简单的原型语法

function Person() {} Person.prototype={ name :"Nicholas", age : 22, job : "software Engineer", sayName:function(){ alert(this.name); } };

在上面的代码中constructor属性不再指向Person了,通过constructor无法确定对象的类型了。可以像下面这样特意将他设置回适当的值

function Person() {} Person.prototype={ constructor:Person, name :"Nicholas", age : 22, job : "software Engineer", sayName:function(){ alert(this.name); } };

重设constructor属性会导致它的[[Enumerable]]特性被设置为true,默认情况,原生的constructor属性是不可枚举的,可以使用Object.defineProperty()方法来改变

Object.defineProperty(Person.prototype,"constructor",{ enumerable:false, value:Person });

原型中查找值的过程是一次搜索,原型对象所做的任何修改都能从实例上立即反应出来

var friend=new Person(); Person.prototype.sayHi=function(){ alert("hi); } friend,sayHi();//"hi"(没有问题)

person实例是在添加新方法之前创建的,但仍可以访问新添加的方法,原因是实例与原型之间的松散连接关系
重写原型对象后的情况

function Person() {} var friend=new Person(); Person.prototype={ name :"Nicholas", age : 22, job : "software Engineer", sayName:function(){ alert(this.name); } }; friend.sayName();//error

调用friend.sayName()时发生错误的原因是,friend指向的原型中不包含以该字段命名的属性,如下图。

这里写图片描述

 

原型对象的问题

原型对象省略了为构造函数传递初始化参数这一环节,所有势力在默认情况下都取得相同的属性值。原型模型最大的问题是有其共享本性所导致的。当原型模型包含引用类型的属性来说,问题就比较严重了。来看下面的例子。

function Person() {} Person.prototype={ constructor:Person, name :"Nicholas", age : 22, job : "software Engineer", friends:["Shelby","Court"], sayName:function(){ alert(this.name); } }; var person1=new Person(); var person2=new Person(); person1.friend.push("Van"); alert(person1.friends);//"Shelby,Court,Van" alert(person2.friends);//"Shelby,Court,Van" alert(person1.friends==person2.friends);//true

5、组合使用构造函数模式和原型模式

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wgywds.html