对象
【对象】
对象基础
对象介绍
对象是JS中的引用数据类型
对象是一种复合数据类型,在对象中可以保存多个不同数据类型的属性
使用typeof检查一个对象时,会返回object
对象(object)是 “键值对” 的集合,表示属性和值的映射关系。
1 | var xiaoming = { |
- 属性名(键名,key): 属性值(value)
- JS 中,大括号表示对象
- 最后的属性后面不加逗号
- {} 后加上分号
对象分类
1.内建对象
- 由ES标准中定义的对象,在任何的ES的实现中都可以使用
- 比如:Math String Number Boolean Function Object…
2. 宿主对象
- 由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象
- 比如 BOM DOM
3.自定义对象
由开发人员自己创建的对象
创建对象
方式一:
1 | var obj = new Object(); |
方式二:
1 | var obj = {}; |
对象的语法
k 和 v 之间用冒号分隔,每组 k:v
之间用逗号分隔,最后一个 k:v
对后可以不书写逗号。
1 | var obj = { |
属性是否加引号
如果对象的属性键名不符合 JS 标识符命名规范,则这个键名必须用引号包裹。
注意:对象中的 key 本身就是字符串格式,只是符合 JS 标识符命名规范的可以省略引号!
1 | var xiaoming = { |
属性的增加
向对象中添加属性
语法:
对象.属性名 = 属性值;
对象[“属性名”] = 属性值; //这种方式能够使用特殊的属性名
对象的属性名没有任何要求,不需要遵守标识符的规范,但是在开发中,尽量按照标识符的要求去写。
属性值也可以任意的数据类型。
如果对象本身没有某个属性值,则用点语法赋值时,这个属性会被创建出来。
1 | var obj = { |
1 | var obj = { |
属性的删除
删除对象中的属性
语法:
1 | delete 对象.属性名 |
1 | var obj = { |
属性的更改
直接使用赋值运算符重新对某属性赋值即可更改属性。
1 | var obj = { |
属性的访问
读取对象中的属性
语法:
对象.属性名
对象[“属性名”] "属性名"
可以使字符串常量,也可以是字符串变量
如果读取一个对象中没有的属性,它不会报错,而是返回一个undefined
可以用“点语法”访问对象中指定键的值。
1 | xiaoming.name; // '小明' |
如果属性名不符合 JS 标识符命名规范,则必须用方括号的写法来访问。
方括号
[]
中只能是字符串类型!任何对象的属性名都可以通过
[]
来访问,只要把属性名写为字符串的形式。
1 | xiaoming['favorite-book']; // '舒克和贝塔' |
如果属性名以变量形式存储,则必须使用方括号形式。
1 | var obj = { |
基本数据类型和引用数据类型
基本数据类型
String Number Boolean Null Undefined
引用数据类型
Object
基本数据类型的数据,变量是直接保存的它的值。
变量与变量之间是互相独立的,修改一个变量不会影响其他的变量。
引用数据类型的数据,变量是保存的对象的引用(内存地址)。
如果多个变量指向的是同一个对象,此时修改一个变量的属性,会影响其他的变量。
比较两个变量时,对于基本数据类型,比较的就是值,
对于引用数据类型比较的是地址,地址相同才相同
1 | var a = 123; |
基本数据类型在内存中的表现
引用数据类型在内存中的表现
这个很像c语言的指针,new object是在堆内存申请了一块内存空间(malloc),并把对应的地址赋值给(指针变量)obj,然后把obj的值(地址)赋值给obj2,两个(指针)就指向同一片内存空间
对象的方法
认识方法
方法(method)
如果某个属性值是函数,则它也被称为对象的 “方法”。
1 | var xiaoming = { |
使用 “点语法” 可以调用对象的方法。
1 | xiaoming.sayHello(); |
方法和函数
方法也是函数,只不过方法是对象的 “函数属性”,它需要用对象打点调用。
在正式学习了什么是 “方法” 之后,就能深入理解之前我们学习的一些函数的书写形式了,比如:
1 | console.log(); |
对象.方法名();
函数名()
对象的遍历
和遍历数组类似,对象也可以被遍历,遍历对象需要使用 for…in… 循环。
使用 for…in… 循环可以遍历对象的每个键。
在后续的 ES6 相关课程中,还会学习新的对象遍历的方式。
【for…in…循环】
1 | 循环遍历对象自身的和继承的可枚举属性(不含Symbol属性). |
1 | // k: 循环变量,它会依次成为对象的每一个键 |
【案例】
1 | var obj = { |
1 | var zjr = { |
for…in… 循环中,每一个迭代值是对应值的字符串形式。
用的对象设置null即可
深拷贝和浅拷贝
-
首先浅拷贝和深拷贝只针对想Object,Array这样的复杂对象,简单来说,浅拷贝只复制一层对象的属性,二深拷贝则复制了所有的层级。
-
对于字符串类型,浅复制是对值的复制,对于对象来说,浅复制是对对象地址的复制,并没有开辟新的栈,也就是复制的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会改变,而深复制则是开辟新的栈,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。
复习基本类型值和引用类型值
还记得我们之前学习过的基本类型值和引用类型值吗?
举例 | 当 var a = b 变量传值时 | 当用 == 比较时 | 当用 === 比较时 | |
---|---|---|---|---|
基本类型值 | 数字、字符串、布尔、undefined、null | 内存中产生新的副本 | 比较值是否相等 | 类型相等的前提下,比较值相等 |
引用类型值 | 对象、数组等 | 内存中不产生新的副本,而是让新变量指向同一个对象 | 比较内存地址是否相同,即比较是否为同一对象 | 比较内存地址是否相同,即比较是否为同一对象 |
对于引用类型的比较来说:== 与 === 是没有区别的!
1 | var a = {}; |
对象是引用类型值
对象是引用类型值,这意味着:
不能用 var obj2 = obj1
这样的语法拷贝一个对象。
使用 == 或者 === 进行对象的比较时,比较的是它们是否为内存中的同一个对象,而不是比较值是否相同。
【案例】
1 | // 例子1 |
浅拷贝
复习什么是浅拷贝:只拷贝对象的 “表层”,如果对象的某些属性值又是引用类型值,则不进一步拷贝它们,只是传递它们的引用。
常见方法:
-
拷贝对象:
Object.assgin()
/ 展开运算符{...obj}
拷贝对象 -
拷贝数组:
Array.prototype.concat()
或者[...arr]
使用 for…in… 循环也可实现对象的浅拷贝。
【案例】
1 | // 实现浅拷贝 |
如果是简单数据类型拷贝值,引用数据类型拷贝的是地址 (简单理解: 如果是单层对象,没问题,如果有多层就有问题)
1 | 1. 直接赋值和浅拷贝有什么区别? |
深拷贝
复习什么是深拷贝:拷贝对象的全貌,不论对象的属性值是否又是引用类型值,都能将它们实现拷贝。
和数组的深拷贝类似,对象的深拷贝需要使用递归。
常见方法:
- 通过递归实现深拷贝
- lodash的cloneDeep
- 通过JSON.stringify()实现
面试时经常会考察深拷贝算法,必须掌握。
【案例】
1 | <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js |