JavaScript面向对象(1)—对象的创建和操作
JavaScript面向对象—对象的创建和操作
前言
虽然说在JavaScript编程语言中,函数是第一公民,但是JavaScript不仅支持函数式编程,也支持面向对象编程。JavaScript对象设计成了一组属性的无序集合,由key和value组成,key为一个标识符名称,而value可以是任意类型的值,当函数作为对象的属性值时,这个函数就可以称之为对象的方法。下面就来看看JavaScript的面向对象吧。
1.JavaScript创建对象的方式
一般地,常用于创建对象的方式有两种,早期经常使用Object类,通过new关键字来创建一个对象,有点类似于Java中创建对象,后来为了方便就直接使用对象字面量的方式来创建对象了,用法更为简洁。
-
使用
Object
类创建对象; -
使用对象字面量创建对象;
2.对象属性操作的控制
对象创建出来后,如何对该对象进行操作控制呢?这里涉及到一个很重要的方法:Object.defineProperty()。
2.1.Object.defineProperty()
该方法可以在对象上定义一个新的属性,也可修改对象现有属性,并将该对象返回。
接收三个参数:
- obj:指定操作的对象;
- prop:指定需要定义或修改的属性名称;
- description:定义或修改的属性描述符;
2.2.属性描述符的分类
什么是属性描述符?顾名思义就是对对象中的属性进行描述,简单来说就是给对象某个属性指定一些规则。属性描述符主要分为数据属性描述符和存取属性描述符两种类型。
对于属性描述符中的属性是否两者都可以设置呢?其实数据和存取属性描述符两者是有区别,下面的表格统计了两者可用和不可用的属性:
属性 | configurable | enumerable | value | writable | get | set |
---|---|---|---|---|---|---|
数据属性描述符 | 可以 | 可以 | 可以 | 可以 | 不可以 | 不可以 |
存取属性描述符 | 可以 | 可以 | 不可以 | 不可以 | 可以 | 可以 |
那么为什么有些属性可以用,有些属性又不能用呢?因为数据属性描述符和存取属性描述符所担任的角色不一样,下面就来详细介绍一下,它们两者的区别。
2.3.数据属性描述符
从上面的表格可以知道,数据属性描述符可以使用configurable、enumerable、value、writable。而这就是数据属性描述符的四个特性。
- Configurable:表示是否可以通过delete删除对象属性,是否可以修改它的特性,或者是否可以将它修改为存取属性描述符。当通过
new Object()
或者字面量的方式创建对象时,其中的属性的configurable
默认为true
,当通过属性描述符定义一个属性时,其属性的configurable
默认为false
。 - Enumerable:表示是否可以通过for-in或者Object.keys()返回该属性。当通过
new Object()
或者字面量的方式创建对象时,其中的属性的enumerable
默认为true
,当通过属性描述符定义一个属性时,其属性的enumerable
默认为false
。 - Writable:表示是否可以修改属性的值。当通过
new Object()
或者字面量的方式创建对象时,其中的属性的writable
性描述符定义一个属性时,其属性的writable
默认为false
。 - Value:属性的value值,读取属性时会返回该值,修改属性时会对其进行修改。(默认:undefined)
2.4.存取属性描述符
存取属性描述符可以使用configurable、enumerable、get、set。在获取对象某个属性值时,可以通过get来拦截,在设置对象某个属性值时,可以通过set来拦截。configurable和enumerable的用法和特性跟数据属性描述符一样。
- Get:获取属性时会执行的函数。(默认undefined)
- Set:设置属性时会执行的函数。(默认undefined)
get和set的使用场景:
-
隐藏某一个私有属性,不希望直接被外界使用和赋值。如下代码
_age
表示不想直接被外界使用,外界就可以通过使用age
的set和get来访问设置_age
了。 -
如果希望截获某一个属性它访问和设置值的过程。(Vue2的响应式原理就在这)
2.5.同时给多个属性定义属性描述符
上面使用Object.defineProperty()方法都是给单个属性进行定义描述符,想要一次性定义多个属性,那么就可以使用Object.defineProperties()方法了。写法如下:
3.Object中常用的方法
上面介绍了Object中defineProperty和defineProperties两个方法。其实Object中还有很多方法,下面介绍一些常用的。
-
获取对象的属性描述符:
- 获取单个属性:
Object.getOwnPropertyDescriptor
; - 获取所有属性:
Object.getOwnPropertyDescriptors
;
- 获取单个属性:
-
Object.preventExtensions()
:禁止对象扩展新属性,给一个对象添加新的属性会失败(在严格模式下会报错)。 -
Object.seal()
:将对象密封起来,不允许配置和删除属性。(实际还是调用preventExtensions
,并且将现有属性的configurable
设置为false
) -
Object.freeze()
:将对象冻结起来,不允许修改对象现有属性。(实际上是调用seal,并且将现有属性的writable
设置为false
)
4.JavaScript创建多个对象
上面提到的创建对象的方式仅适用于创建单个对象适用,如果有多个对象比较类似,那么一个个创建必然是很麻烦的,如何批量创建对象呢?JavaScript也给我们提供了一些方案。
4.1.方案一:工厂函数
如果我们不想在创建对象时做重复的工作,那么就可以定义一个函数为我们去做这些重复性的工作,我们只需要将属性对应的值传入函数即可。
缺点:创建出来的对象全是通过字面量创建的,获取不到对象真实的类型。
4.2.方案二:构造函数
(1)什么是构造函数?
- 构造函数也称之为构造器(constructor),通常是我们在创建对象时会调用的函数;
- 在其他面向对象的编程语言里面,构造函数是存在于类中的一个方法,称之为构造方法;
- 如果一个普通的函数被使用new操作符来调用了,那么这个函数就称之为是一个构造函数;
- 一般规定构造函数的函数名首字母大写;
(2)new操作符调用函数的作用
当一个函数被new操作符调用了,默认会进行如下几部操作:
- 在内存中创建一个新的对象(空对象);
- 这个对象内部的[[prototype]]属性会被赋值为该构造函数的prototype属性;
- 构造函数内部的this,会指向创建出来的新对象;
- 执行函数的内部代码(函数体代码);
- 如果构造函数没有返回对象,则默认返回创建出来的新对象。
(3)构造函数创建对象的过程
- 通过构造函数创建的对象就真实的类型了,如下所示的Person类型;
缺点:在每次使用new创建新对象时,会重新给每个对象创建新的属性,包括对象中方法,实际上,对象中的方法是可以共用的,消耗了不必要的内存。
4.3.方案三:原型+构造函数
在了解该方案之前,需要先简单的认识一下何为原型。
(1)对象的原型
JavaScript中每个对象都有一个特殊的内置属性[[prototype]](我们称之为隐式原型),这个特殊的属性指向另外一个对象。那么这个属性有什么用呢?
- 前面介绍了,当我们通过对象的key来获取对应的value时,会触发对象的get操作;
- 首先,get操作会先查看该对象自身是否有对应的属性,如果有就找到并返回其值;
- 如果在对象自身没有找到该属性就会去对象的[[prototype]]这个内置属性中查找;
那么对象的[[prototype]]属性怎么获取呢?主要有两种方法:
- 通过对象的
__proto__
属性访问; - 通过
Object.getPrototypeOf()
方法获取;
(2)函数的原型
所有的函数都有一个prototype属性,并且只有函数才有这个属性。前面提到了new操作符是如何在内存中创建一个对象,并给我们返回创建出来的对象,其中第二步这个对象内部的[[prototype]]属性会被赋值为该构造函数的prototype属性。将代码与图结合,来看一下具体的过程。
示例代码:
内存表现:
- p1和p2的原型都指向Person函数的prototype原型;
- 其中还有一个constructor属性,默认原型上都会有这个属性,并且指向当前的函数对象;
(3)结合对象和函数的原型,创建对象
先简单的总结一下:
- 前面使用构造函数创建对象的缺点是对象中的方法不能共用;
- 对象的属性可以通过[[prototype]]隐式原型进行查找;
- 构造函数创建出来的对象[[prototype]]与构造函数prototype指向同一个对象(同一个地址空间);
- 那么我们可以将普通的属性放在构造函数的内部,将方法放在构造函数的原型上,当查找方法时,就都会去到构造函数的原型上,从而实现方法共用;
__EOF__

本文链接:https://www.cnblogs.com/MomentYY/p/15994857.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix