14

JavaScript中几乎所有东西都是一个对象,除了六种基本类型数据 - null,undefined,strings,numbers,boolean和symbols。

任何不是原始值的东西都是Object。这包括数组,函数,构造函数和对象本身。

对象

从概念上讲,对象在所有编程语言中都是相同的。它们使用具有属性和方法的代码来表示真实世界。

例如,如果您的对象是学生,则它将具有名称,年龄,地址,ID等属性以及updateAddress,updateName等方法。

在JavaScript中,将对象视为包含元素项的列表,并且列表中的每个项(属性或方法)都由内存中的键值对存储。

让我们看一个对象的例子。

firstObj 是一个对象,有2个属性:1,age;value 为 foo 和 28。

JavaScript对象在创建方式上有所不同。不需要非得用class创建,并且可以使用字面量表示法声明。

对象创建

我们可以在JavaScript中以多种方式创建对象,让我们来看看都有哪些。

1. 对象字面量(最直接的方式)。对象字面量是用大括号括起来的以逗号分隔的键值对列表。对象字面量属性值可以是任何数据类型,包括数组文字,函数,嵌套对象字面量或基本数据类型。

`
注意:上面的学生对象键可以通过点表示法访问,即student.id,student.name或通过方括号表示法,即学生['id'],学生['姓名']等
`

2. Object.create()。该方法使用指定的原型和旧对象的属性创建一个新对象。

`
注意:默认情况下,每个JavaScript函数都有一个原型对象属性(默认情况下它是空的)。方法或属性可以附加到此属性。
`

下面是对象__proto__的输出:

我们现在可以使用Object.create()方法向newStudent对象添加新属性和数据。

`
注意:newStudent能够访问student对象的键和值,因为它已被添加到newStudent的原型链中,这是我们在javascript中继承的一种方式。也就是说,newStudent将存储一个指向student对象的链接。读取属性时也会查询此父对象。
`

父母可以有父母,依此类推。重复这一过程,直到我们到达一个没有任何父项的对象,即父项为空。

3. 对象实例。将Object constructor与“new”关键字结合使用可以让我们初始化新对象。

我们来看一个例子吧。

但是,new Object() 不适合需要创建同一类型的多个对象的情况,因为它需要为每个这样的对象重复编写上面的代码。

为了解决这个问题,我们可以使用下一个方法。

4. 对象构造器。当我们需要一种可以多次创建对象“类型”的方法时,构造函数非常有用,而无需每次都重新定义对象,这可以使用Object Constructor函数来实现。

我们来看一个例子吧。

我们创建了两个具有相同属性但具有不同值的对象。

5. Object.assign()。这是从其他对象创建新对象的另一种方法。

它将所有可枚举的自有属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。让我们通过一个例子来理解:

Object.assign() 有很多用例,比如对象克隆,合并对象等。

6. Object.fromEntries()。方法将键值对列表转换为对象。我们来看一个例子吧

`
注意:创建对象的最佳方法是通过字面量表示法,因为它在源代码中占用的空间更少。它可以清楚地识别出发生了什么,所以使用new Object(),你实际上只是输入更多(理论上,如果没有被JavaScript引擎优化)和进行不必要的函数调用。此外,字面量表示法创建对象,并在同一行代码中分配属性,而其他代码则不然。
`

如何添加/更新和删除对象的属性

如前所述,可以通过点 或 括号表示法添加对象的属性。让我们看一个例子

这里,name 和 city 是对象属性。

对象只能包含一个且具有一个值的键,也就是说同一个键只能有一个值。

属性名称可以是字符串,数字或特殊字符,也可以是动态属性,但如果属性名称不是字符串,则必须使用括号表示法访问它。因此,如果我们需要访问上面示例中的属性1,我们可以执行a[1],但是a.1将返回语法错误。而a.name或[“name”]则都可以。

要更新属性,我们可以再次使用上述两种表示法。如果我们为已创建的属性添加值,则会更新这个属性的值。

我们还可以通过Object函数方法( 如Object.defineProperties() 或 Object.defineProperty() )创建和更新对象的属性。

要删除对象的属性,我们可以使用delete关键字,来执行此操作。

如果成功删除属性,则返回值delete为true。否则,它将是错误的。

如何迭代对象属性?

如果我们想要访问所有对象键值对的情况下,会出现这种需求。

使用循环 - for in 和 for of

在 for in 的情况下,它迭代一个对象并逐个返回属性。

Key将逐个对应对象的属性,[key]返回该值。对于for in循环也迭代原型链并返回父键,所以如果你看到更多的键,不要感到惊讶。为了避免看到更多的键,我们可以执行hasOwnProperty 检查以仅获取当前对象键。

在 for of 情况下,它迭代遍历可迭代对象,仅获取当前对象的key。这点也是和 for in 的区别。更多详细解释,可以参考MDN for...of。

Object函数中有各种方法,它们只会访问当前对象的属性和值,而不是其原型链。

1. Object.keys()Object.getOwnPropertyNames()。 返回字符串键数组。

2. Object.values(). 返回一个值数组。

3. Object.entries(). 返回 [key, value] 为元素的二维数组

从输出结果看,上面的属性顺序是不固定的。

如何检查对象中的属性是否存在

有三种方法可以检查对象中是否存在属性。

1. 使用hasOwnProperty。此方法返回一个布尔值,表示对象本身是否具有指定的属性,而不是父/继承属性。

注意:即使属性的值为 null 或 undefined,hasOwnProperty 也会返回true。

如果我们将hasOwnProperty作为对象中的属性名称怎么办?这个值得思考。

2. 使用in运算符 - 如果指定的属性位于指定的对象 或 其原​​型链中(即在其父级内),则 in 运算符返回true。

注意:hasOwnProperty仅检查当前对象属性,而 in 运算符中检查当前+父属性

3. 使用自定义功能

有多种方式可以通过自定义方法检查属性是否存在。其中一个是通过 Object.keys。

什么是按引用/共享复制和按值复制,它如何应用于对象?

不同之处在于,通过值,我们的意思是每次创建内容时都会执行新的内存分配,而在引用的情况下,我们指向已经创建的内存空间。

在javascript的上下文中,所有原始数据类型都是通过值方法分配的内存,对于一个对象,可以进行值或引用传递,根据具体操作情况。

什么是浅层和深层复制/克隆对象?

浅层和深层副本之间的核心区别在于如何将属性复制到新对象。

在浅拷贝中,新对象与旧对象共享数据,即在上述示例的情况下使用 = 创建对象的浅拷贝b。因此,在大多数情况下,通过引用传递是浅层复制。

此外,浅拷贝将复制顶级属性,但嵌套对象在原始(源)和副本(目标)之间共享。

浅拷贝的另一种方法是使用Object.assign()。我们来看看这个例子

正如我们在上面看到的 obj.b.c = 30,这是 Object.assign() 的一个陷阱。 Object.assign 只生成浅拷贝。 newObj.b 和 obj.b共享对象的相同引用,没有制作单独的副本,而是复制了对象的引用。

在Deep copy中,新对象将拥有自己的一组键值对(与原始对象具有相同的值)而不是共享。

让我们看看做一些深层复制的方法

1. JSON.parse(JSON.stringify(object))

我们无法复制自定义的对象函数,以及键对应的值是undefined 或 Symbol的情况,如下:

此外,此方法不适用于循环对象。

`
注意:循环对象是具有引用自身属性的对象。
`

上面将抛出一个错误,converting circular structure to JSON.

2. 使用ES6展开运算符


但是,nested对象仍然是浅层复制的。

如何比较两个对象?

对象的等式 == 和 严格相等 === 运算符完全相同,即只有两个对象的内存引用相同时才相等。

例如,如果两个变量引用同一个对象,它们是相等的:

未完待续


相关文章:

使用Array.isArray更好地检查数组

JS扩展运算符(Spread Operator)的5种用法

JavaScript中如何反转数组

如何使用ES6语法给数组去重


还可以关注头条号:「前端知否」


前端知否
714 声望49 粉丝

to be is to do