javaScript构造函数和原型对象 - Go语言中文社区

javaScript构造函数和原型对象


创建对象

使用new关键字创建对象

var a = new Object();//创建对象
a.name = 'tom'//给对象中的属性赋值
a.say= function(str){//创建对象的方法
    console.log(str+'hello');
}

使用字面量创建

var a ={
  name:'tom',
  say: function(str){
    console.log(str+"hello");
  }
}

上面两种创建对象的效果是相同的。但是第二种方式似乎是交单一些

工厂模式

实际上这是我们在开发中最常用的对象定义方式,但是我们要有很多相似属性的对象,就会使用工厂模式创建对象。

function createA(name){
   var o = new Object();
   o.name = name;
   o.say= function(str){
    console.log(str+'hello');
   }
   return o;
}

var a = createA('tom');
var b = createA('jack');

这就是我们创建的工厂模式,我们可以看到我们在内部创建了一个对象O,在最后我们又返回了该对象。这就实现了我们说的工厂模式。

构造函数

工厂模式解决了多个相似对象创建的问题,但是问题又来了,这些对象都是Object整出来的,怎么区分他们的具体类型呢?这时候我们就需要切换到另一种模式了,构造函数模式:

function CA(name){
  this.name = name;
  this.say= function(str){
    console.log(str+'hello');
  }
}

var a = new CA('tom');
var b = new CA('jack');

这里我们使用一个大写字母开头的构造函数代替上例中的createA,注意按照约定构造函数首字母要大写。在合理我们创建一个新的对象,然后将构造函数的作用域赋给新对象,调用构造函数中的方法。上面的方法似乎没有什么不妥,但是我们可以发现,两个实例中调用的构造函数中的say方法不是同一个function实例:

console.log(a.say==b.say);//false

调用同一个方法,却声明了不同的实例,确实在浪费资源。我们可以优化一下将say函数放到构造函数外面声明:

function createA(name){
   this.name = name;
   this.say = say;
}
function say(str){
   console.log(str+'hello');
}

这样解决了,多个实例多次定义同一个实例的问题,但是新的问题又来了,我们定义的say是一个全局作用域的方法,但是这个方法其实是没法直接调用的,这就有点矛盾了。如何更优雅的定义一个具备一定封装性的对象呢,我们来看一下javaScript原型对象模式:

原型对象模式

当我们创建一个函数时,该函数就会具备一个prototype属性,这个属性指向通过构造函数创建的那个函数的原型对象。通俗点讲原型对象就是内存中为其他对象提供共享属性和方法的对象。
这里写图片描述
在原型模式中,不必再构造函数中定义实例属性,可以将属性信息直接赋值予原型对象

function CA(){
  CA.prototype.name = 'tom';
  CA.prototype.say = function(str){
    console.log(str+'hello');
  }
}

var ca1 = new CA();
ca1.say('javaScript');
var ca2 = new CA();

和构造函数不同的是这里新对象的属性和方法是所有实例都可以共享的,换句话说ca1和ca2访问的是同一份属性和方法。原型对象除了我们赋予的属性外,还有一些内置属性,所有原型对象都具备一个constructor属性,这个属性是一个指向包含prototype属性函数的一个指针。通过衣服图我们来清楚的理一下流程:
这里写图片描述
所有的对象都有一个原型对象(prototype),原型对象中有一个constructor属性指针包含prototype属性的函数,CA的实例ca1和ca2都包含一个内部属性指向原型对象,当我们访问一个对象的属性时,首先会询问对象中有没有该属性,如果没有则继续查找原型对象。

使用原型对象

在前面的示例中,我们注意到在位原型对象添加属性时,需要每个都增加CA.prototype,这个工作很重要,在上面对象的创建模式中,我们知道可以通过字面量的形式创建一个对象,在这里我们也可以改进一下:

function CA(){}
  CA.prototype={
    name : 'tom',
    say : function(str){
      console.log(str+'hello');
    }
  }

这里有一个地方需要特别注意下,constructor属性不再指向对象CA,因为没定义一个函数,就会同时为其创建一个prototype对象,这个对象也会自动获取一个新constructor属性,这个地方我们使用CA.protottype本质上是复写原有的prototype对象,因此constructor也变成了新对象constructor属性,不再指向CA,而是Object:

var ca1 = new CA();
console.log(ca1.constructor = CA);//fales
console.log(ca.constructor = object);//true

在一般情况下,这个微妙变化的改变是不会对我们造成任何影响的,但是如果你对constructor有特殊的需求我们也可以显示的指定constructor

CA.prototype={
   constructor : CA,
   name:'tom',
   say:function(str){
    console.log(str+'hello')
   }
}
var ca1 = new CA();
console.log(ca.constructor==CA);//true

通过对原型模式的初步了解,我们发现所有的实例对象都共享相同的属性,这是原型模式的基本特点,但往往对于开发者来说这是吧双刃剑,在实际开发中,我们希望的实例应该具备自己的属性,这也是在实际开发中很少人单独使用原型模式的主要原因。

构造函数和原型模组合模式

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

function CA(name,age){
 this.name = name;
 this.age = age;
 }

 CA.prototype={
  constructor:CA,
  say:function(str){
   console.log(str+'hello');
  }
}
//创建两个实例
var ca1 = new CA('tom',20);
var ca2 = new CA('jack','33');

在这个例子中,我们再构造函数中定义了对象各自的属性值,在原型对象中我们定义了constructor 属性和say函数,这样ca1和ca2属性之间就不会产生影响了,这中模式也是实际来发中最常用的的对像定义方式。

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_27038019/article/details/65445455
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-06-26 22:56:04
  • 阅读 ( 825 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢