JS创建对象方法之构造函数模式

JS创建对象方法之工厂方法,构造函数方法

我们在ECMAScript中创建对象虽然可以通过Object()构造方法或者是对象字面量的方式,但是这两种方式有缺点的:使用同一接口创建很多对象,会产生大量重复的代码。

JS创建对象之工厂模式

关于工厂模式,首先简单地从字面意思来理解,为什么叫工厂模式,而不叫其他的名字,我觉得可以这样理解。比如说这个工厂是一个加工手刹的工厂,我们是雇主,我们想要一定数目的手刹,我们只需要把订单交给工厂就可以了,不需要知道这个手刹是怎么制作的,同样工厂会给我们的是已经做好的手刹。我们只需要知道如果我们需要手刹,直接交给工厂解决就可以了。
那么,ECMAScript中创建对象的工厂模式就是这个意思,即抽象创建具体对象的过程。 由于在ECMAScript中无法创建类,因此我们可以通过函数来封装以特定接口创建对象的细节。

function createPersonalInfor(name,age,job)
{
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function ()
    {
        alert(this.name);
    }
    return o;
}
var person1 = createPersonalInfor("Jona",20,"student");
var person2 = createPersonalInfor("Jone",19,"software engineer");

从上面的代码可以看到,我们通过createPersonalInfor()函数,创建了两个对象,这样无疑节省了不少的代码量。但是这种方法也是有着缺点:没有解决对象识别问题(即怎样知道一个对象的类型)。
由于我们在createPersonalInfor()中的对象都是通过Object()构造函数创建的,因此不管你的信息是属于哪个对象的,当判断对象的类型时,结果都是Object。比如说我们想要对象A是Company1类型,对象B是Company2类型的,但是如果使用上面的工厂模式,我们就无法判断A和B分别是哪一个类型的。 对于此问题,出现了一个新的模式:构造函数模式

JS创建对象之构造函数模式

ECMAScript中的构造函数可以用来创建对象。类似于Object, Array这样的原生构造函数,在运行时会自动出现在执行环境中。即他们是已经存在的函数,不需要我们再去显示的写出这个构造函数,直接用就行了。 我们也可以使用自定义的构造函数,从而自定义对象类型的属性和方法。

function Person(name,age,job)
{
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function ()
    {
        alert(this.name);
    }
}
var person1 = new Person("Jona",20,"student");
var person2 = new Person("Jone",19,"software engineer");

从这个例子中,我们可以看到与工厂模式时的不同:

  • 没有显示创建对象
  • 直接将属性和方法赋给this对象
  • 没有return 语句

在这里注意一种写法,我们这里自定义的构造函数的函数名首字母大写,非构造函数首字母小写,这样主要是为了区别来构造函数和非构造函数。毕竟,构造函数也还是函数。

我们在创建自定义对象时,使用了new操作符。那么在构造函数调用时,会经历以下几个步骤:

  • 创建一个新对象
  • 将构造函数的作用域赋给新对象(this就指向了该新对象)
  • 执行构造函数中的代码
  • 返回新对象

我们可以通过person1.constructor 来得知该对象的类型,但是如果已知有哪几种类型,也可以通过instanceof来判断对象类型。

1.将构造函数当作函数

构造函数与其他函数的唯一不同就是调用方式不同。但构造函数也还是函数,没有定义构造函数的特殊语法。任何函数,只要通过new操作符来点用,就可以作为构造函数。而任何函数,没有通过new操作符调用,那么就是普通函数。

var person = new Person("jona",20,"student");
person.sayName();    //Jona

Person("Jone",19,"nurse");  //添加到了window中,当成了普通函数调用
window.sayName();    //Jone

//在别的对象中调用
var o = new Object();
Person.call(o,"Ravi",30,"teacher");
o.sayName();      //Ravi

2. 构造函数的问题

那么,构造方法模式有没有缺点呢? 答案是肯定的。

不知道有没有发现,正如上面我们自定的构造函数,如果构造函数里有方法,那么我们每次创建一个新对象的时候,都会创建一个新的Function()实例,即创建了一个新的对象。“函数是对象,函数名是指针”。虽然每次创建的函数会导致不同的作用域链和标识符解析,但是他们的作用机理都是一样的,比如上面定义的Person()中,都是要显示当前对象的name属性。因此,我们可以把函数定义移到构造函数之外来解决这个问题。

function Person(name,age,job)
{
    this.name  = name;
    this.age  = age;
    this.job = job;
    this.sayName = sayName;
}
function sayName()
{
    alert(this.name);
}
var person1  = new Person("Jona",20,"student");
var person2 = new Person("Jone",19,"nurse");

在此例中,由于构造函数中的sayName属性的值等于全局作用域中的sayName函数,这样一来,person1 和 person2 就共享了同一个sayName()函数。

缺点是什么呢?

在全局作用域中定义的函数实际上只能被某一个函数调用,这让全局作用域有点名不副实。(这句话可能一时想不明白,请参见博文,我觉得讲的很清楚:
https://blog.csdn.net/chengdabelief/article/details/50990938 )。
而且,如果对象需要定义很多方法,那么我们就要在全局作用域中定义很多全局函数,这破坏了自定义引用类型的封装性。
那么,对于这种问题,可以通过原型模式来解决。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值