JavaScript-用工厂函数构造函数创建对象

将Object.create()运用到工厂函数创建对象

工厂函数可以添加原型,用多个类型的原型对象创建多个对应类型的对象,为我们提供了原型对象更多的可能性;此外工厂函数内部还能使用闭包,这也让工厂函数更强大。

来看例子。

以我在自己的文章——JavaScript编程范例与常见编程范式的工厂函数示例代码为基础,我们需要原型上的方法以便新对象可以继承它们。因此设置原型对象objProto,把createRoom的reserve方法移到上面作为objProto的属性。然后在工厂函数使用Object.create()来创建带有原型对象objProto的对象obj,接着为obj添加属性(点语法添加属性)。接着修改工厂函数返回值,返回新建对象obj。修改了工厂函数,我们尝试以对象boardRoom(董事长会议室)为例看看能否使用reserve方法。在控制台执行代码,打印boardRoom,打开返回的对象,发现数组schedule有一些内容,没错就是我们上面使用boardRoom的reserve方法添加的值。因此我们使用继承(reserve方法)作为使用工厂函数创建的对象的一部分。

我们还有另一种方法使obj继承一些属性,即使用静态方法Object.assign(),它的作用是复制对象所有可枚举的自有属性到目标对象,我们用它直接继承基本会议室的属性(状态)。再将修改后的代码运行,显示结果同上图。

现在我们已经向工厂函数添加了原型,所以现在工厂功能变得更加强大,因为我们能使用原型。此外我们可以设置多个原型对象,应用到工厂函数中,用不同的原型对象创建出不同的对象(Object.create()),为我们提供了原型对象更多的可能性,这就是有些人使用工厂函数创建对象的原因。

我们看一道用工厂函数创建对象的练习。

题目:假设一家公司有留言板,留言板上面所有帖子都作为对象进行控制。补写工厂函数createPost()创建帖子,参数为帖子内容和部门;补写函数getAge(),注意该方法来自帖子对象的原型对象,它返回自帖子创建起到当前时间的毫秒数。因此用工厂函数添加帖子对象是还需添加创建日期。

解答:立即创建post1及其原型postProto,再手动在控制台输入打印getAge方法。日期类型做减法能直接返回毫秒数。每次调用post1的getAge()返回的时间间隔数会增大,符合我们当前创建这个方法的目的。

用构造函数创建对象

构造函数的目的是创建特定类型的对象,我们在JavaScript中看过它,因为在主要的JavaScript代码中有多个构造函数出现。JavaScript中使用的任何常见数据类型对象都可以使用构造函数创建。在处理构造函数时了解关键字new的作用十分重要,关键字new在构造函数中主要完成5件事:1,新的对象在内存中建立;2,将新对象的原型指针分配给构造函数的原型属性,在创建对象的同时也能创建对象的原型;3,关键字this对于构造函数来说是被分配到一个新的对象,所以新创建的对象可以使用关键字this来引用;4,执行构造函数的代码,构造函数中所有包含this的属性都会有值分配并随着this添加到新对象的属性中;5,如果构造函数没有返回值,则返回该对象。我们当然可以自己创建返回值,如果返回值是一个对象,则构造函数里创建的新对象不会被返回。通常构造函数会自动返回创建的新对象。因此,构造函数与常规函数之间的主要区别就是调用构造函数时要使用new关键字,而调用常规函数时不用。

示例——用构造函数创建常用数据类型对象

日期类型

使用构造函数创建日期对象而不是用显性的日期对象创建("20240520T1800")打印日期对象(new Date()),返回当前日期时间。

同理,使用构造函数创建数组对象而不是用显性的数组对象创建([])。用构造函数创建对象时前面要加上new关键字,这是必须的。可以发现,构造函数都以大写字母开头,当然不是强制大写。

我们可以与new关键字一起创建自己的构造函数,以创建特定类型的对象。自己的构造函数也可以与工厂函数相结合,这里我们稍微修改自己的文章——JavaScript编程范例与常见编程范式的工厂函数示例代码作为例子。此处的构造函数为MeetingRoom,与工厂函数不同,这里的构造函数首字母大写了。执行代码并在控制台打印这两个新创建的对象,发现新对象里面有会议室的各种属性,这些对象都属于我们自定义的MeetingRoom类(也是由构造函数定义的)。构造函数里的this指的是我们要创建的新对象。new关键字和Meeting构造函数一起使用时我们在内存中创建了一个新对象,然后我们可以用this引用它。

我们尝试不带new关键字调用构造函数,结果发现报错。我们发现我们没有任何东西分配给name属性(尽管参数中有'this'),然而报错的原因就是没有使用new关键字。没有new关键字JS引擎就不会为我们在内存中创建新对象,更不会向对象里添加附带的属性。

在控制台打印boardRoom,查看它的原型,可以发现该对象的原型与构造函数有关,即构造函数MeetingRoom就是原型对象的来源。当然,与new关键字一起使用的构造函数执行后不会返回任何内容(因为没有return关键字),但是会将新对象及其属性返回到被分配的变量中(boardRoom,trainingRoomA)。

用构造函数实现原型继承

创建函数时还包括该函数原型属性的创建。原型属性不是原型对象,尽管创建了函数也会有原型对象。个人认为,原型的作用与类的作用很相似。

示例——函数原型属性

创建函数testFun,随后输入命令console.dir()查看testFun函数(对象)的属性。展开输入console.dir()的返回结果,我们可以看到函数testFun的很多属性,其中有原型属性(prototype),这与函数关联的原型对象([[Prototype]])不同。打开了函数的原型对象,我们可以看到原型对象中有很多可以被函数对象直接调用的方法。而原型属性的属性值就是构造函数。默认情况下,函数原型属性都指向构造函数,这里的构造函数就是指初始函数本身。当函数本身用作构造函数时,创建的任何对象被分配的原型对象都会指向原型属性。所以在默认情况下,函数的原型对象都会接收构造函数。

在控制台执行前面的示例——用构造函数创建常用数据类型对象代码,再打印boardRoom并展开boardRoom对象,我们能看到其原型对象的构造函数,其实就是MeetingRoom本身。我们利用MeetingRoom构造函数创建了boardRoom和trainingRoomA两个对象。所以展开对象后我们能看到对象的属性与原型(链)的配置是默认完成的,但我们可以把自定义的值分配给原型。在这里我们使用构造函数将预订方法(reserve())分配给原型,即添加原型继承。因此,我们在构造函数(MeetingRoom)的原型属性中添加了reserve方法用来存预定会议室的时间和预计时长。两个被创建的对象将接收各自对象的原型属性指向的对象(构造函数)作为原型,因此其原型会有reserve方法。在控制台执行代码并打印boardRoom对象,会看到它的原型对象里面有我们添加的reserve方法。接着我们调用reserve方法(boardRoom.reserve())。再查看boardRoom的schedule属性,可以发现它返回了一个对象。当然了此时输入的日期是无效日期,不过这不重要,重要的是我们能用构造函数的原型属性向新对象的原型添加reserve方法使新对象能将预定信息添加到schedule上,这就是我们进行原型继承的方式。

在reserve方法中我们还能看到面向对象编程思想的重要特点之一——抽象,调用reserve方法并不复杂,用户仅需传入参数即可。但我们把存储预定信息的实现过程隐藏在函数体中。同时我们用构造函数创建的两个对象boardRoom和trainingRoomA封装了数据和方法。

我们可以继续利用构造函数的原型属性向即将创建的新对象的原型对象添加属性(MeetingRoom.prototype.company)。为原型对象添加属性的另一种办法是将构造函数的原型属性值被分配为对象属性(MeetingRoom.prototype={...}),新对象的原型在此方法下被设置成为全新的对象。

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值