1.key,value,entries
const obj = {"name": 'zhaohui', "age": 18}
Object.keys(obj) // ["name", 'age']
Object.values(obj) // ['zhaohui', 18]
var obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]
2. Object.fromEntries()
是Object.entries()的逆操作,用于将一个键值对数组转为对象
Object.fromEntries([
['foo', 'bar'],
['baz', 42]
])
// { foo: "bar", baz: 42 }
对象遍历
(1)for…in
for…in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
(2)Object.keys/values/entries(obj)
Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
let obj = { name: 'zhaohui' }
Object.setPrototypeOf(obj, { age: 18 })
for (let key in obj) {
console.log(key) // 打印 name age
}
console.log(Object.keys(obj)) // ['name']
如果想要轮询出来Symbol的值,就ownKeys
let obj = {
[Symbol('my_key')]: 1,
enum: 2,
nonEnum: 3
};
Reflect.ownKeys(obj)
// ["enum", "nonEnum", Symbol(my_key)]
Object.keys(obj)
// ["enum", "nonEnum"]
(3)Object.getOwnPropertyNames(obj)
Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。/可以得到class里面的constructor和定义的方法。
(4)Object.getOwnPropertySymbols(obj)
Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。
(5)Reflect.ownKeys(obj)
Reflect.ownKeys返回一个数组,包含对象自身的(不含继承的)所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
----所以尽量不用for in 用keys ,因为一般不要继承的属性吧
链判断运算符
之前写的
// 正确的写法
const firstName = (message
&& message.body
&& message.body.user
&& message.body.user.firstName) || 'default';
const fooInput = myForm.querySelector('input[name=foo]')
const fooValue = fooInput ? fooInput.value : undefined
简化
const firstName = message?.body?.user?.firstName || 'default';
const fooValue = myForm.querySelector('input[name=foo]')?.value
?? – ES2020
它的行为类似||,但是只有运算符左侧的值为null或undefined时,才会返回右侧的值。
|| 和 ?? 区别
双竖杠||,只要前面的值转为布尔值为false时,就取后面,否则取前面,如undefined、null、false、空字符串和数值0,而双问号则为:前面的值为null、undefined,则取后面的值,否则都取前面的值。由此可以发现,双问号??更加适合在不知道变量是否定义时,或者是否赋值时的场景来使用。
Object.is()比较两个值一样
ES5 比较两个值是否相等,只有两个运算符:相等运算符(==)和严格相等运算符(===)。它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0。JavaScript 缺乏一种运算,在所有环境中,只要两个值是一样的,它们就应该相等。
基本跟===差不多
+0 === -0 //true
NaN === NaN // false
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
Object.is('foo', 'foo')
// true
Object.is({}, {})
// false
assign()
Object.assign()方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
const target = {name: '100'}
const obj1 = {age: 18}
const obj2 = {sex: 'man'}
const newObj = Object.assign(target, obj1, obj2)
console.log(newObj, target) // 两个都是{ "name": "100", "age": 18, "sex": "man" }
**注意,
**如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
Object.assign()方法实行的是浅拷贝,而不是深拷贝。也就是说,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用。
const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1);
obj1.a.b = 2;
obj2.a.b // 2
Object.setPrototypeOf() /getPrototypeOf()往对象原型上加/读属性
let obj = { name: "moni" }
Object.setPrototypeOf(obj, { age: 20 })
console.log(obj, Object.getPrototypeOf(obj))
对象包含什么属性 --in、hasOwnProperty
主流的两种
// in .继承属性都为true
let obj = { x: 1, y: undefined };
console.log('x' in obj) // true
console.log('y' in obj) // true
console.log('z' in obj) // false
console.log('toString' in obj) // true
// hasOwnProperty() 自有属性
let obj = { x: 1, abc: 2 };
let a = 'a';
let b = 'bc';
obj.hasOwnProperty('x'); // true 包含
obj.hasOwnProperty('y'); // false 不包含
obj.hasOwnProperty('toString'); // false 继承属性
obj.hasOwnProperty(a + b); // true 判断的是属性abc
比较两个对象指定的属性那几个不同
const obj1 = {
name: 'zhaohui',
age: 21,
sex: 'nu',
like: {
run: true,
lala: {
id: '11111'
}
}
}
const obj2 = {
name: 'chang',
age: 21,
sex: 'nan',
like: {
run: false,
lala: {
id: '112'
}
}
}
// 比较两个对象属性值不同的属性名数组
const judgeAttr = ['name', 'age', 'sex', 'run', 'id'] // 需要判断的属性名
let attrArr = []
function handleCompare(obj1, obj2) {
for(const key1 in obj1) {
if (typeof obj1[key1] === 'object') {
handleCompare(obj1[key1], obj2[key1])
} else {
if (judgeAttr.includes(key1) && obj1[key1] !== obj2[key1]) {
attrArr.push(key1)
}
}
}
}
handleCompare(obj1, obj2)
console.log('attrArr', attrArr) // ["name", "sex", "run", "id"]
拼接对象、浅拷贝
1 …拼接
const obj = { name: 'zhaohui', age: 18 }
const obj1 = { hobby: { item: 'nihao' } }
var newObj = { ...obj, ...obj1 }
console.log(newObj) // {name: 'zhaohui', age: 18, hobby: {item: 'nihao'}}
2.assign()
深度克隆
详细: https://blog.youkuaiyun.com/huang3513/article/details/144358859
1.JSON.parse(JSON.stringify(obj))
let obj = { name: 'lala', sex: { option1: '男', option2: '女' }}
let cloneObj = JSON.parse(JSON.stringify(obj))
obj.name = 'cloneLala'
obj.sex.option1 = 'clone男'
console.log(obj,cloneObj) // obj更改了,cloneObj还是{ name: 'lala', sex: { option1: '男', option2: '女' }}
缺点:
无法克隆函数、undefined、Symbol、Date 等类型。
会丢失对象中的循环引用,无法处理循环结构。
对象中的 prototype 链、getter/setter 等特殊属性会被忽略。
2. 使用 StructuredClone (现代浏览器支持)
StructuredClone 是一种浏览器原生支持的方法,能够克隆对象及其内部结构,包括 Date、Map、Set、ArrayBuffer 等。但它仍然不支持函数或某些特殊对象(如 RegExp)。
const clonedObj = structuredClone(originalObj);
3.手动递归克隆
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') {
return obj; // 如果是原始类型,直接返回
}
// 处理特殊情况:Date 和 RegExp 等类型
if (obj instanceof Date) {
return new Date(obj); // 克隆 Date 对象
}
if (obj instanceof RegExp) {
return new RegExp(obj); // 克隆 RegExp 对象
}
// 处理数组和对象
const clonedObj = Array.isArray(obj) ? [] : {};
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clonedObj[key] = deepClone(obj[key]); // 递归克隆每个属性
}
}
return clonedObj;
}
const originalObj = {
name: 'Bob',
age: 30,
dateOfBirth: new Date('1994-12-25'),
address: {
city: 'New York',
zip: '10001'
},
hobbies: ['reading', 'coding'],
greet: function() { console.log('Hello'); }
};
const clonedObj = deepClone(originalObj);
console.log(clonedObj);
console.log(clonedObj.dateOfBirth instanceof Date); // true
console.log(clonedObj.hobbies === originalObj.hobbies); // false
prop为’..'转化成对象obj..**
let obj = { sex: { hobby: 'nv'}, name: 'zhaohui', three: {nihao: {sha: 'sha'}} }
console.log(splitProp(obj, 'sex.hobby'), splitProp(obj, 'name'), splitProp(obj, 'three.nihao.sha')) // nv zhaohui sha
function splitProp(obj, prop) {
const propArr = prop.split('.')
let ret
propArr.forEach((p, index) => {
ret = index === 0 ? obj[p] : ret[p]
})
return ret
}