教程

Javascript 面向对象系列(1):对象

面向对象编程可以说是 Javascript 的基础,也是一个难点。今天先来说说对象是什么,以及哪些值得注意的。

对象的定义

在 JavaScript 中,对象是一个无序的属性集合(与数组的有序元素集合相对应)。

创建对象

使用对象字面量创建对象的方式很简单:

const car = {
  color: 'blue',
  type: 'flying car',
  wheels: 4,
  1: 'test',
  'full name': 'Flying Car'
};

当然还可以通过 Object() 构造函数来创建:

const car = new Object();

需要注意的是,使用 Object() 构造函数来创建对象相对较慢,也比较冗长。

属性名称规则

可以看到上面 car 对象中的属性名称是字符串,但是省略了引号,需要注意的是在某些情况下需要包含引号,特别是如果属性名称:

  • 是保留字,如 foriflettrue 等等
  • 包含不能出现在变量名称中的空格或特殊字符,即 $_ 以外的标点符号和大部分的重音字符(重音字符是什么?见下图)

访问和修改对象属性

访问对象属性

访问对象属性有两种方式,点表示法和方括号表示法。比如访问上面 car 对象的 color 属性,car.colorcar['color'] 都可以访问到。但是两者还是有区别的,需要注意的是点表示法并不适用于所有情况:

一方面,举例说明,当对象的属性名称是数字时,使用点表示法访问会出错的

car.1; // Uncaught SyntaxError: Unexpected number
car[1]; // 返回 1 对应的属性值 'test'

另一方面,使用变量来表示属性名称的时候,使用点表示法将会返回 undefined,主要原因在于这种访问对象属性的方法中, Javascript 解释器把变量名当做属性名称去查找了。

const myVariable = 'color';
car[myVariable]; // 'blue'
car.myVariable; // undefined

对于类似上面的情况都需要使用方括号表示法,特别是最后一个情况,实际开发中经常遇到,需要特别注意。

修改对象属性

修改对象属性的方式其实和访问对象属性的方式是一致的,不再赘述。

首先,讲讲如何移除对象属性,可以通过 delete 操作符,删除成功会返回 true,如:

delete car.color; // true
car.color; // undefined

然后聊聊 Object.defineProperty(),它会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。与常规的定义和修改对象属性不同的是:使用该方法定义或修改的属性,该属性的 configurable, enumerablewritable 默认均为 false,意味着什么呢?

  • 属性描述对象中 configurable 的值设置为 false 后,以后就不能再次通过 Object.defineProperty 修改属性,也无法删除该属性。
  • 设置 enumerable 属性为 false 后,遍历对象的时候会忽略当前属性
  • writablefalse 时,该属性不能被赋值运算符改变修改

对象是引用类型

Javascript 中可分为原始类型和引用类型,所有的对象包括 Object、Array、Function、Date 和 RegExp 就是引用类型的,Undefined、Null、String、Number、Boolean 属于原始类型。那么问题来了,两者有什么区别呢?

以函数的传递参数为例子,当传递一个原始类型时,一般叫值传递,当传递一个引用类型时,一般叫引用传递。

值传递是不可变的,也就是对函数中的参数所做的更改不会影响原值,引用传递正好相反,看下面的例子:

let originalObject = {
  color: 'red'
};

function setToBlue(object) {
    object.color = 'blue';
}

setToBlue(originalObject);

originalObject.color; // blue

上面的例子,调用函数 setToBlue 并传入 originalObject 执行后,由于对象是通过引用传递的,最终原始对象也被改变了。

比较两个对象

两个一模一样的对象作比较会发生什么呢?

const car1 = {
    color: 'blue',
    type: 'flying car',
    wheels: 4
}

const car2 = {
    color: 'blue',
    type: 'flying car',
    wheels: 4
}

你可能会认为 car1 === car2 会返回 true,而实际上会返回 false,事实上,只有对同一个对象的两个引用进行比较时,才会返回 true

这个可以引生出另外三个问题:

  • 如何封装一个比较两个表面一模一样的对象,让上面的例子返回 true
  • 对象的深拷贝和浅拷贝,参考 Javascript 中的深拷贝和浅拷贝
  • 要求对对象数组 [{}, {}, {}...] 去重,要求:{ a: 1 }{ a: 1 } 引用不一样,但算重复,则如何去重效率高,参考 fast-deep-equal

遍历对象的属性名和值

  • for in 可以遍历对象属性,但是遍历的是所有可枚举属性,这个会把原型链上也带出来
  • Object.keys(),会返回一个数组,每一项是对象自身的可枚举属性名称
  • Object.values(),会返回一个数组,每一项是对象自身的可枚举属性值,2017 年刚正式加入规范,浏览器兼容性不算太好,查看 兼容性列表
  • Object.getOwnPropertyNames(),会返回一个数组,每一项是对象自身的属性名称(包括不可枚举属性但不包括Symbol值作为名称的属性)

不同类型的对象

这里说说浏览器中的 DOM API 的实现

什么是 DOM 呢,Javascript 事实上是无法直接操作 HTML 文档的,Javascript 可以通过 DOM API 去操作。DOM 就是针对 HTML 文档的一个应用程序编程接口。

要想理清楚这个问题,需要知道当我们打开一个网页时,HTML 文档在浏览器中是怎么渲染成我们看到的网页的?

  • 浏览器接受到 HTML
  • HTML 标签被转换为令牌
  • 令牌被转换为 Node 节点
  • 最终全部令牌转换完毕后,就形成了 DOM 树

一个树状结构,反映了 HTML 的内容和属性,以及节点之间的所有关系,DOM 是 HTML 的完整解析表示。因此,DOM 是所接收到的 HTML 文档的关系和属性的模型(描述)。Document Object Model(文档对象模型)可以理解成 Object Model of the Document(文档的对象模型)!

在浏览器中,可以使用浏览器提供的一个特殊对象来访问 DOM:document,它是浏览器提供的,并非 Javascript 内置原生对象,而是宿主对象

Javascript 就是对中间的 DOM 进行操作,最终修改后的 DOM 再渲染成我们看到的网页

Node

Node 有 12 种类型,常见的有 DOCUMENT_NODE ELEMENT_NODE TEXT_NODE DOCUMENT_FRSGMENT_NODE 这4种。

转载请注明:WordPress Hi » Javascript 面向对象系列(1):对象

发表评论

电子邮件地址不会被公开。 必填项已用*标注