资讯专栏INFORMATION COLUMN

【基础系列】javascript中的对象

617035918 / 1894人阅读

摘要:自定义对象是指由开发者在代码中所创建的对象。继承属性是指在对象原型链中的属性。与此同时,对象的属性还具有一些特性可写代表是否可以设置该对象所对应的该属性的值。我们可以利用来判断这个对象是否封闭,传入一个对象,返回布尔值。

</>复制代码

  1. 这次我们好好聊一聊对象这个东西,本次说的不是array,也不是function,而是object
基础概念

对象是一种特殊的数据类型,这种数据类型还有其他的很多叫法,比如“散列”,“散列表”,“字典”,“关联数组”。

对象按照创建者的角度,可以分为三类:
内置对象:是由javascript语言本身自定义的对象,大多数是一些预定好的构造函数类,比如ArrayDateFunction
宿主对象:是指javascript解释器所嵌入的宿主环境定义的对象,比如HTMLElement就是宿主对象。
自定义对象:是指由开发者在代码中所创建的对象。

我们知道对象的表达方式是:"属性":"值"

属性按照来源不同,可以分为两类:
自有属性:是指直接在对象中定义的属性。
继承属性:是指在对象原型链中的属性。

与此同时,对象的属性还具有一些特性:
可写:代表是否可以设置该对象所对应的该属性的值。
可枚举:代表是否可以通过api枚举出该属性。
可配置:代表是否可以删除或修改该属性。

记住上述概念,有助于我们进行下一步的理解。

创建对象

创建对象有三种方式:
第一种:对象直接量

</>复制代码

  1. var o = {}
  2. var obj = {
  3. a: 1,
  4. "b": 2,
  5. "min title": 3
  6. }

第二种:通过new创建对象

</>复制代码

  1. var o = new Object()

第三种:Object.create()
该方法支持传入两个参数,第一个参数是对象的原型(就是所创建出的对象的_proto_的指向),第二个参数是对属性进一步的描述(该参数可选,参数内容会在后面详解

以下三种方式是等价的:

检测对象原型的方法除了instanceof之外,还有一个isPrototypeOf(),我们来看一下使用:

对象的getter和setter

我们首先再明确一个概念:
我们常见的{a: 1}中的a叫做数据属性,除此之外还有一个叫做存取器属性,存取器属性的值的读取和设置,都是由getter和setter控制的。

</>复制代码

  1. var o = {
  2. p: 0,
  3. set q(value) {
  4. this.p = value
  5. },
  6. get q() {
  7. return this.p+=100
  8. }
  9. }
  10. o.q = 1
  11. console.log(o.q) // => 101
  12. console.log(o.q) // => 201

其中,对象中的函数定义没有使用function关键字,使用的而是getset关键字

处理可以这样定义存取器属性,我们还可以利用其他的方法定义存取器属性,就是我们熟知的Object.defineProperty()Object.definePeoperties()

首先,我们介绍一下Object.defineProperty()定义数据属性的方式

</>复制代码

  1. var o = {}
  2. // 定义属性
  3. Object.defineProperty(
  4. o,
  5. "x",
  6. {
  7. value: 1,
  8. writable: true,
  9. enumerable: true,
  10. configurable: true
  11. }
  12. )
  13. // 修改属性
  14. Object.defineProperty(
  15. o,
  16. "x",
  17. {
  18. value: 2,
  19. writable: false
  20. }
  21. )

这个函数共有三个参数:
第一个参数是,需要加属性的对象。

第二个参数是,添加的属性的名称。

第三个参数是定义的配置项:
第一个配置就是这个属性所对应的值。
剩余三个配置就是对应到文章一开始所提到属性三个特性可写可枚举可配置
这四个配置项都不是必须填写。假如对于新创建的属性,value不填,默认值就是undefined,其他配置项的缺省值是false。假如对于修改已有的属性来说,不填写的配置项就不做修改。

我们再看一下Object.defineProperty()定义存取器属性的方式
其中,需要注意的是,在定义存取器属性时无法定义,valuewritable配置项,因为定义的getset从某种意义上代替了前两个配置项。

</>复制代码

  1. var o = {y: 1}
  2. Object.defineProperty(
  3. o,
  4. "x",
  5. {
  6. set(value) {
  7. this.y = value
  8. },
  9. get() {
  10. return this.y+=100
  11. },
  12. enumerable: true,
  13. configurable: true
  14. }
  15. )

Object.defineProperty只能单个定义或修改对象属性,Object.defineProperties提供了批量解决的办法,如下:

</>复制代码

  1. var o = {}
  2. Object.defineProperties(
  3. o,
  4. {
  5. x: {
  6. set(value) {
  7. this.y = value
  8. },
  9. get() {
  10. return this.y+=100
  11. },
  12. enumerable: true,
  13. configurable: true
  14. },
  15. y: {
  16. value: 1,
  17. writable: false,
  18. enumerable: true,
  19. configurable: true
  20. }
  21. }
  22. )

Object.definePropertyObject.defineProperties对于属性的修改是有规则和要求的,如下:

如果对象是不可扩展的,则可以编辑已有的自有属性,但不能给它添加新属性。

如果属性是不可配置的,则不能修改它的可配置性和可枚举性。

如果存取器属性是不可配置的,则不能修改其getter和setter方法,也不能将它转换为数据属性。

如果数据属性是不可配置的,则不能将它转换为存取器属性。

如果数据属性是不可配置的,则不能将它的可写性从false修改为true,但可以从true修改为false。

如果数据属性是不可配置且不可写的,则不能修改它的值。然而可配置但不可写属性的值是可以修改的(实际上是先将它标记为可写的,然后修改它的值,最后转换为不可写的)。

在这里,我们再看一下上面的Object.create方法,Object.create的第二个参数是和Object.defineProperties第二个参数一样的,缺省值同样为undefinedfalse

没有提供选项去配置属性特性的方法,这些属性默认都是true,例如:new关键字和对象直接量的方式创建对象,以及最上面对象直接量的方式设置getter和setter

对象的扩展性

对象的扩展性是什么,其实就是指对象能否添加新的属性,默认情况下所有的内置对象和自定义对象都是可扩展的。除非我们人为的改变它:

Object.preventExtesions()可以传入一个参数,就是你要取消扩展功能的对象,操作后,这个对象会不能扩展(即不能添加新属性),且不能恢复,操作只影响该对象本身,不对其他原型链操作产生影响。
我们可以利用Object.esExtensible()判断这个对象是否可扩展,传入一个对象,返回布尔值。

Object.seal()可以将对象封闭,效果和上面的Object.preventExtesions()一样,增加的效果是将这个对象的自有属性设置为不可配置(即将configurable设为false),同样不能解封。
我们可以利用Object.isSealed()来判断这个对象是否封闭,传入一个对象,返回布尔值。

Object.freeze()可以将对象冰冻,效果和上面的Object.seal()一样,增加的效果是将这个对象的自有属性设置为不可写(即将writable设为false),同样不能解冻。
Object.isFrozen()可以判断这个对象是否冰冻。

根据属性查询值

根据属性查询值的方式我们当然是众所周知了,[].,当然他们也可以设置和修改可写性为true的自有属性值

</>复制代码

  1. var o = {}
  2. Object.defineProperties(
  3. o,
  4. {
  5. x: {
  6. value: 1,
  7. writable: true,
  8. enumerable: true,
  9. configurable: true
  10. },
  11. y: {
  12. value: 1,
  13. writable: false,
  14. enumerable: true,
  15. configurable: true
  16. }
  17. }
  18. )
  19. o.x // => 1
  20. o["x"] = 5
  21. o.x // => 5
  22. o.y = 5
  23. o.y // => 1
删除属性

delete可以用户删除对象属性,能删除的属性只是该对象的自有属性属性配置性为true的属性

让人感到意外的是,delete只是断开属性和宿主对象的联系,而不会去操作属性中的属性。

检测属性是否存在

检测属性共有三种方式,in操作符,hasOwnPropertypropertyIsEnumerable

in可以检测对象的自有属性继承属性,不受属性特性的影响

</>复制代码

  1. var o = {x: 1}
  2. "x" in o // true
  3. "y" in o // false
  4. "toString" in o // true

hasOwnProperty只能检测对象的自有属性,不能检测继承属性,不受属性特性的影响

</>复制代码

  1. var o = {x: 1}
  2. o.hasOwnProperty("x") // true
  3. o.hasOwnProperty("y") // false
  4. o.hasOwnProperty("toString") // false

propertyIsEnumerable只能检测自有属性,且要求这个属性的可枚举性为true

枚举全部属性

首先第一个方法是for/in,这个方法可以枚举出当前对象可枚举(属性枚举性为true)的自有属性和继承属性

</>复制代码

  1. var o = Object.create({z: 1})
  2. Object.defineProperties(
  3. o,
  4. {
  5. x: {
  6. value: 1,
  7. writable: true,
  8. enumerable: true,
  9. configurable: true
  10. },
  11. y: {
  12. value: 1,
  13. writable: false,
  14. enumerable: false,
  15. configurable: true
  16. }
  17. }
  18. )
  19. for (p in o) {console.log(p)} // => x, z

第二个方法是Object.keys(),这个方法可以枚举出当前对象的可枚举(属性枚举性为true)的自有属性,返回值是一个数组

</>复制代码

  1. var o = Object.create({z: 1})
  2. Object.defineProperties(
  3. o,
  4. {
  5. x: {
  6. value: 1,
  7. writable: true,
  8. enumerable: true,
  9. configurable: true
  10. },
  11. y: {
  12. value: 1,
  13. writable: false,
  14. enumerable: false,
  15. configurable: true
  16. }
  17. }
  18. )
  19. Object.keys(o) // => ["x"]

第三个方法是Object.getOwnPropertyNames,它可以枚举出当前对象所有的自有属性(不受枚举性影响)

</>复制代码

  1. Object.defineProperties(
  2. o,
  3. {
  4. x: {
  5. value: 1,
  6. writable: true,
  7. enumerable: true,
  8. configurable: true
  9. },
  10. y: {
  11. value: 1,
  12. writable: false,
  13. enumerable: false,
  14. configurable: true
  15. }
  16. }
  17. )
  18. Object.getOwnPropertyNames(o) // => ["x", "y"]
对象的序列化和反序列化

JSON.stringify()JSON.parse()

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93039.html

相关文章

  • Javascript学习总结 - JS基础系列

    摘要:案例每隔毫秒调用函数并显示时间。当点击按钮时,停止时间代码如下计时器每隔毫秒调用函数,并将返回值赋值给计时器计时器,在载入后延迟指定时间后去执行一次表达式仅执行一次。该值标识要取消的延迟执行代码块。 简述 本系列将持续更新Javascript基础部分的知识,谁都想掌握高端大气的技术,但是我觉得没有一个扎实的基础,我认为一切高阶技术对我来讲都是过眼云烟,要成为一名及格的前端工程师,必须把...

    zlyBear 评论0 收藏0
  • 【重温基础】15.JS对象介绍

    摘要:构造函数通常首字母大写,用于区分普通函数。这种关系常被称为原型链,它解释了为何一个对象会拥有定义在其他对象中的属性和方法。中所有的对象,都有一个属性,指向实例对象的构造函数原型由于是个非标准属性,因此只有和两个浏览器支持,标准方法是。 从这篇文章开始,复习 MDN 中级教程 的内容了,在初级教程中,我和大家分享了一些比较简单基础的知识点,并放在我的 【Cute-JavaScript】系...

    booster 评论0 收藏0
  • WebSocket系列JavaScript中数字数据如何转换为二进制数据

    摘要:以和为例,说明中的数字数据如何转换为二进制数据。对象用来表示通用的固定长度的原始二进制数据缓冲区。中的数字数据如何转换为二进制数据对和有了一个大概的了解,下面让我们来看下它是如何进行二进制数据操作的。 概述 本文主要通过对JavaScript中数字数据与二进制数据之间的转换,让读者能够了解在JavaScript中如何对数字类型(包括但不限于Number类型)进行处理。 二进制数据在日常...

    MASAILA 评论0 收藏0
  • JavaScript系列(四) - 收藏集 - 掘金

    摘要:函数式编程前端掘金引言面向对象编程一直以来都是中的主导范式。函数式编程是一种强调减少对程序外部状态产生改变的方式。 JavaScript 函数式编程 - 前端 - 掘金引言 面向对象编程一直以来都是JavaScript中的主导范式。JavaScript作为一门多范式编程语言,然而,近几年,函数式编程越来越多得受到开发者的青睐。函数式编程是一种强调减少对程序外部状态产生改变的方式。因此,...

    cfanr 评论0 收藏0
  • 前端文档收集

    摘要:系列种优化页面加载速度的方法随笔分类中个最重要的技术点常用整理网页性能管理详解离线缓存简介系列编写高性能有趣的原生数组函数数据访问性能优化方案实现的大排序算法一怪对象常用方法函数收集数组的操作面向对象和原型继承中关键词的优雅解释浅谈系列 H5系列 10种优化页面加载速度的方法 随笔分类 - HTML5 HTML5中40个最重要的技术点 常用meta整理 网页性能管理详解 HTML5 ...

    jsbintask 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<