对像-操作方法
对象冻结
冻结对象,使其不能修改、删除、新增属性
1 | const o1={x:10,y:10} |
冻结不是深度冻结,如果属性值还是对象的话,还是可以修修改的
1 | const o3={x:{y:1}} |
对象遍历
将对象变成数组,对象属性变成子数组
返回一个给定对象自身可枚举属性的键值对数组,数组每个元素是一个包含键和值的数组
1 | let obj = {x:1,y:2} |
Object.keys()
返回对象自身
可枚举
属性属性名组成的数组,不包含 Symbol 类型的属性for… in
遍历返回对象的
自身和原型链
上的可枚举属性(不包含 Symbol 属性)Object.getOwnPropertyNames()
返回对象的所有自身属性的属性名(包括不可枚举属性但不包括 Symbol 值属性)组成的数组
Object.getOwnPropertySymbols(obj)
返回对象的所有 Symbol 类型属性的 key 组成数组
Reflect.ownKeys()
返回对象自身的所有属性,不管属性名是 Symbol 或字符串,也不管是否可枚举.
判断对象是否含有某属性
key in obj
:检测指定对象(obj)原型链上是否有对应的属性值。obj.hasOwnProperty(key)
判断 key 是不是 obj 的私有属性。
在 ES5 里,如果此方法的参数不是对象(而是一个原始值),那么它会抛出 TypeError。在 ES2015 中,非对象的参数将被强制转换为一个对象。
对象浅拷贝
Object.assign({}, obj)
将 obj 拷贝到空对象,返回目标对象
Object.assign(target, ...source)
方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象,返回目标对象。会修改原对象。扩展运算符
1
let newObj={...obj}
Array.prototype.concat()
Array.prototype.slice()
注意:
Array 的 slice 和 concat 方法不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。手写
1 | function shadowClone(obj) { |
对象深拷贝
缺点:
- 时间对象拷贝后不是时间对象而是字符串
- 正则表达式、Error 对象拷贝后变成空对象
- 函数、
undefined
拷贝后会丢失 NaN
、Infinity
、-Infinity
,拷贝后会变成 null- 只能序列化对象的可枚举的自有属性,如果 obj 中的对象是由构造函数生成的,则使用 JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的 constructor。
- 如果对象中存在循环引用的情况也无法正确实现深拷贝。
总结
JSON.parse(JSON.stringify(X)),其中 X 只能是 Number, String, Boolean, Array, 扁平对象,即那些能够被 JSON 直接表示的数据结构
JSON.stringify()的其他用法
判断数组是否包含某对象
1
2
3
4
5
6
7
8
9let data = [
{name:'John'},
{name:'Mary'},
{name:'Lucky'},
],
val = {name:'Mary'};
console.log(JSON.stringify(data).indexOf(JSON.stringify(val)) !== -1);//true
console.log(data.indexOf(val) !== -1)//false
//因为两个对象是引用值不同,所以需要序列化一下转成字符串判断对象/数组是否相等
1
2let a=[1,2,3],b=[1,2,3];
JSON.Stringify(a)===JSON.stringify(b);//true
与 toString()的区别
1 | let arr = [1,2,3]; |
手写深拷贝
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28function isObject(target) {
const type = typeof target;
return target !== null && (type === 'object' || type === 'function');
}
function deepClone(obj) {
//递归终止条件
if (obj === null) return null;
if (!isObject(obj)) return obj;
if (obj instanceof RegExp) return new RegExp(obj);
if (obj instanceof Date) {
return new Date(obj)
}
//测试了一下,貌似还是拷贝了引用地址,未找到替换方法
if (typeof obj === 'function') {
return new Function("return " + JSON.stringify(obj))();
}
if (obj instanceof TypeError) {
return new TypeError(obj)
}
//保证新对象与原对象是相同的构造函数的实例,比如原对象是[]
let newObj = new obj.constructor;
for (let key in obj) {
if (obj.hasOwnProperty(key)) { //只拷贝私有属性,不拷贝原型链上的属性
newObj[key] = deepClone(obj[key])
}
}
return newObj
}
问题
如果存在循环引用递归终止条件就无法执行,陷入死循环。
解决循环引用问题
1 | const deepClone = (value, hash = new WeakMap) => { |
更完善的深拷贝
1 | const mapTag = '[object Map]'; |