宝哥软件园

对javascript构造函数和原型对象的深入理解

编辑:宝哥软件园 来源:互联网 时间:2021-09-10

几种常见的对象创建模式

用new关键字创建最基本的创建对象的方式无非就是和大多数其他语言说一样的话:没有对象,但你是新的!

var gf=新对象();gf.name='汤唯';gf.bar=' cgf . SayWhat=function(){ console . log(this . name ' said : love you forever ');}使用文字创建

这似乎是合适的,但生活在沉默中的极客可以喜欢这样一种复杂而低调的定义变量的方式。作为一种脚本语言,它应该具有与其他同类语言相同的风格,因此有一种方法可以定义对象的字面量:

var gf={ name : '汤唯',bar : 'c ',say what : function(){ console . log(this . name ' said : love you forever ');}}工厂模式

实际上,这是实践中最常用的定义对象的方式,但我希望有许多属性相似的对象(想想就兴奋。)我该怎么办?如果我们一个一个定义,会产生很多代码。为什么不建一个工厂,批量生产我们的物品呢?javascript世界里的第一个充气娃娃。不,“工厂模式”诞生了!

函数createGf(名称,条){ var o=new Object();o.name=nameo.bar=baro . SayWhat=function(){ alert(this . name ' said : love you forever ');}返回o;}var gf1=createGf('bingbing ',' d ');var gf2=createGf('mimi ',' a ');构造器

工厂模式解决了创建许多相似对象的问题,但问题又来了。这些物体都是由物体组成的。如何区分它们具体的对象类型?这时,我们需要切换到另一种模式,构造器模式:

函数Gf(name,bar){ this . name=name;this.bar=barthis . SayWhat=function(){ alert(this . name ' said : love you forever ');}}var gf1=new Gf('vivian ',' f ');var gf2=新Gf('vivian2 ',' f ');在这里,我们使用一个以大写字母开头的构造函数,而不是前面例子中的createGf,并按照约定注意构造函数的大写字母。这里我们创建一个新对象,然后将构造函数的范围分配给新对象,并在构造函数中调用方法。上面的方法看起来没什么问题,但是我们可以发现两个实例中调用的构造函数中的sayWhat方法不是同一个Function实例:

console . log(gf1 . SayWhat==gf2 . SayWhat);//false调用相同的方法但声明不同的实例是对资源的浪费。我们可以在构造函数之外优化sayWhat函数的声明:

函数Gf(name,bar){ this . name=name;this.bar=barthis . say what=say what }函数say what(){ alert(this . name ' said : love you forever ');}这样就解决了多个实例多次定义同一个方法实例,但是新的问题又来了。我们定义的sayWhat是一个全局范围的方法,但是这个方法不能直接调用,有点矛盾。如何更优雅地定义具有一定封装的对象?让我们看看javascript原型对象模式。

原型对象模式

理解原型对象当我们创建一个函数时,函数将有一个原型属性,它指向构造函数创建的函数的原型对象。通俗地说,原型对象是内存中为其他对象提供共享属性和方法的对象。

在原型模式下,不需要在构造函数中定义实例属性,但是可以直接给原型对象属性信息:

函数Gf(){ Gf . prototype . name=' vivian ';gf . prototype . bar=' c ';gf . prototype . sayWhat=function(){ alert(this . name ' said : love you forever ');} } var Gf1=new Gf();gf1 . SayWhat();var gf2=新Gf();与构造函数不同,新对象的属性和方法可以被所有实例共享,换句话说,gf1和gf2访问相同的属性和方法。除了我们给出的属性,原型对象中还有一些内置属性。所有原型对象都有一个构造器属性,它是一个指向包含原型属性的函数的指针(再敢绕过这个点!)。通过一张图片,我们可以清晰地梳理出上弦口的过程:

所有对象都有一个原型对象,原型对象中的构造函数属性指向包含原型属性的函数。Gf的两个实例Gf1和gf2都包含指向原型对象的内部属性(在firefox浏览器中表示为私有属性proto)。当我们访问对象中的属性时,我们将首先询问它是否存在于实例对象中。如果没有,我们将继续搜索原型对象。

使用原型对象在前面的例子中,我们注意到当向原型对象添加属性时,我们需要向每个对象添加Gf.prototype。这项工作重复进行。在上面的对象创建模式中,我们知道一个对象可以以文字量的形式创建,我们也可以在这里对其进行改进:

function Gf(){ } Gf . prototype={ name : ' vivian ',bar : 'c ',say what : function(){ alert(this . name ' said : love you forever ');}}有一个地方需要特别注意。构造器属性不再指向对象Gf,因为定义了每个函数,同时会为其创建一个原型对象,这个对象会自动获取一个新的构造器属性。在这个地方,我们使用Gf.prototype从本质上覆盖了原来的prototype对象,所以构造函数就变成了新对象的构造函数属性,而不是指向Gf,它就是Object:

var gf1=新Gf();console . log(Gf1 . constructor==Gf);//false console . log(gf1 . constructor==object)//true一般来说,这种细微的变化不会对我们造成影响,但是如果你对constructor有特殊的要求,我们也可以明确指定Gf.prototype的constructor属性:

Gf . prototype={ constructor : Gf,name : 'vivian ',bar : 'c ',say what : function(){ alert(this . name ' said : love you forever ');} } var Gf1=new Gf();console . log(Gf1 . constructor==Gf);//true通过对原型对象模式的初步了解,我们发现所有实例对象都共享相同的属性,这是原型模式的基本特征,但对于开发人员来说,这往往是一把“双刃剑”。在实际开发中,我们希望实例应该有自己的属性,这也是实际开发中很少有人单独使用原型模式的主要原因。

构造器和原型组合模式

在实际开发中,我们可以使用构造函数定义对象和原型的属性来定义共享的属性和方法,这样我们就可以通过传递不同的参数来创建不同的对象,同时拥有共享的方法和属性。

函数Gf(name,bar){ this . name=name;this.bar=bar} Gf . prototype={ constructor : Gf,say what : function(){ alert(this . name ' said : love you forever ');}}var gf1=new Gf('vivian ',' f ');var gf2=新Gf('vivian1 ',' c ');在这个例子中,我们在构造函数中定义了对象的属性值,在原型对象中定义了构造函数属性和sayWhat函数,这样gf1和gf2属性之间就没有影响了。这种模式也是实际开发中最常用的对象定义方法,包括很多js库采用的模式(bootstrap等)。)默认情况下。

更多资讯
游戏推荐
更多+