本文参考各位大佬的优秀文章,提取其中经常用到的一些方法,记录为笔记,便于自查和复习。文末的参考资料中附上原文链接,便于大家进一步学习。
本篇介绍的是前端数据处理中,对象的相关操作,涉及的内容请看下图:
创建对象
在JavaScript中,对象的键值,既可以是一个函数(称为方法),也可以是基本数据类型(称为属性)。
创建对象的方法有很多种,下面展示几种常见的方法。
对象字面量
使用对象字面量来创建一个对象,这也是开发中经常用到的方式。
javascript
let person = {
name: 'John',
age: 30,
sayHello: function() {
console.log('Hello!');
}
};
构造函数
构造函数允许你定义一个对象模板,然后使用该模板创建多个具有相似结构和行为的对象。因此,当需要创建多个相似的对象时,可以使用这种方式来创建对象。
javascript
function Person(name, age) {
this.name = name;
this.age = age;
this.sayHello = function() {
console.log('Hello!');
};
}
let person = new Person('John', 30);
Object 构造函数
javascript
let person = new Object();
person.name = 'John';
person.age = 30;
person.sayHello = function() {
console.log('Hello!');
};
上述两种方法的区别:
- 构造函数是自定义的: 构造函数是由程序员创建的函数,用于创建自定义对象类型。你可以定义构造函数的属性和方法,使其适应特定的需求。
Object
构造函数是内建的:Object
是JavaScript的内建构造函数之一,用于创建通用对象。当你使用new Object()
时,它创建一个空对象。- 构造函数可以有自定义行为: 构造函数可以包含自定义的行为,例如在对象创建时执行特定的初始化操作。
Object
构造函数相对简单:Object
构造函数相对简单,它主要用于创建基本的空对象,没有额外的自定义行为。总的来说,构造函数用于创建具有自定义结构和行为的对象,而
Object
构造函数用于创建基本的空对象。如果只是需要一个简单的空对象,那么使用Object
构造函数就足够了。
工厂函数
工厂函数 是一个能返回对象的函数,它既不是类也不是构造函数。在 JavaScript 中,任何函数都可以返回一个对象,如果函数前面没有使用 new
关键字,却又返回一个对象,那这个函数就是一个工厂函数。
javascript
function createPerson(name, age) {
return {
name: name,
age: age,
sayHello: function() {
console.log('Hello!');
}
};
}
let person = createPerson('John', 30);
属性访问&赋值
在 JavaScript中,几乎所有的事物都是对象。对象包含了属性、方法。
点表示法
点表示法可以用于读取和设置对象的属性值。
点表示法在属性名是合法标识符的情况下更方便。
javascript
let person = { name: 'John', age: 30 };
// 读取属性值
console.log(person.name); // 输出: John
// 设置属性值
person.age = 31;
console.log(person.age); // 输出: 31
对象的方法,可以通过点表示法来访问。通过添加 () 调用 (作为一个函数)。
javascript
var person = {
fullName: function () {
console.log("hello");
}
};
person.fullName(); // 输出:hello
// 如果不加 ()
console.log(person.fullName); // 输出:[Function: fullName]
console.log(typeof person.fullName); // 输出:function
方括号表示法
方括号表示法更灵活,可以处理包含特殊字符或空格的属性名,也可以使用变量作为属性名的引用。
javascript
let person = { name: 'John', age: 30 };
// 读取属性值
console.log(person['name']); // 输出: John
// 设置属性值
let propertyName = 'age';
person[propertyName] = 32;
console.log(person.age); // 输出: 32
对象的方法,也可以通过方括号表示法来访问。
javascript
var person = {
fullName: function () {
console.log("hello");
}
};
person['fullName'](); // 输出:hello
拷贝对象
解构赋值
解构赋值主要用于从对象或数组中提取值,并赋值给变量。
javascript
let person = {};
({ name: person.name, age: person.age } = { name: 'John', age: 30 });
// 或者简写为:
let { name, age } = { name: 'John', age: 30 };
let person = { name, age };
当使用对象解构赋值时,它会创建一个新的对象,其中包含被提取的属性的副本。这是一个浅拷贝的过程,因此对于对象中包含的引用类型(如嵌套对象或数组),它们仍然是原始对象和新对象共享的。
javascript
let originalObject = { name: 'John', age: 30, address: { city: 'New York', zip: '10001' } };
// 使用对象解构赋值创建新对象
let { name, age, address } = originalObject;
// 修改新对象的属性值
name = 'Jane';
address.city = 'San Francisco';
console.log(originalObject); // 输出: { name: 'John', age: 30, address: { city: 'San Francisco', zip: '10001' } }
在上面的例子中,name
和 age
是原始对象属性的副本,修改它们不会影响原始对象。然而,address
是原始对象中引用类型的属性,因此修改新对象中的 address
属性实际上会影响原始对象,因为它们引用的是相同的对象。
扩展运算符
ES6 的扩展运算符(...
)可以用于对象属性的复制,但是,只有第一层是深拷贝,第二层及更深层是浅拷贝。
javascript
let originalObject = { name: 'John', age: 30 };
// 使用展开运算符创建对象副本
let copiedObject = { ...originalObject };
// 修改副本的属性值
copiedObject.name = 'Jane';
console.log(originalObject); // 输出: { name: 'John', age: 30 }
console.log(copiedObject); // 输出: { name: 'Jane', age: 30 }
Object.assign()
可以使用ES6提供的Object.assign()
方法。该方法第一个参数是目标对象,后面为一个或多个源对象。
javascript
let person = {};
Object.assign(person, { name: 'John', age: 30 });
JSON方法
通过使用 JSON.stringify
将对象转换为 JSON 字符串,然后使用 JSON.parse
将 JSON 字符串转换回对象,可以得到对象的深层次拷贝。
但是,这种方法适用于对象中不包含函数、undefined
等不支持 JSON 的特殊值。
javascript
let originalObject = { name: 'John', age: 30, address: { city: 'New York', zip: '10001' } };
// 使用 JSON.stringify 将对象转换为 JSON 字符串
let jsonString = JSON.stringify(originalObject);
// 使用 JSON.parse 将 JSON 字符串转换回对象
let copiedObject = JSON.parse(jsonString);
// 修改副本的属性值
copiedObject.name = 'Jane';
copiedObject.address.city = 'San Francisco';
console.log(originalObject); // 输出: { name: 'John', age: 30, address: { city: 'New York', zip: '10001' } }
console.log(copiedObject); // 输出: { name: 'Jane', age: 30, address: { city: 'San Francisco', zip: '10001' } }
删除属性
在JavaScript中,可以使用 delete
操作符来删除对象的属性。
使用 delete
操作符:
javascript
let person = { name: 'John', age: 30 };
// 删除属性
delete person.age;
// 或者用方括号表示法
delete person['age'];
console.log(person); // 输出: { name: 'John' }
需要注意的是,使用 delete
删除对象的属性并不会删除对象本身,它只是删除了属性和属性值。删除对象的属性后,该属性将变成 undefined
。如果属性不存在,则 delete
操作不会报错,而是返回 true
。
javascript
let person = { name: 'John' };
// 删除不存在的属性,不会报错
let result = delete person.age;
console.log(result); // 输出: true
console.log(person); // 输出: { name: 'John' }
console.log(person.age);// 输出: undefined
需要注意的是,有些情况下,使用 delete
可能并不是最佳的选择。在某些情况下,更好的做法是将属性值设置为 null
或 undefined
,以保留属性,但将其值清空。
判断对象中是否含有某个属性
这在开发中经常会遇到,若对象中某个属性不存在,但是代码中引用了,那么就会报错!
对象.属性 + undefined
- 通过点或者方括号可以获取对象的属性值,如果对象上不存在该属性,则会返回 undefined。
- 这种方式可以判断指定对象的自有属性和继承属性,如果对象自身没有检测的属性,而原型链上有该属性,则会返回原型链上的属性值。
javascript
// 创建对象
let obj = {
name: 'Scarlett',
age: 37
}
console.log(obj.name !== undefined) // true 自身属性存在
console.log(obj['name'] !== undefined) // true
console.log(obj.gender) // 输出:undefined
// 在原型上添加一个可枚举属性
Object.prototype.nationality = 'America'
// 在obj对象上添加一个不可枚举属性
Object.defineProperty(obj, 'occupation', {
value: 'actress',
enumerable: false
})
console.log(obj.nationality !== undefined) // true
console.log(obj['occupation'] !== undefined) // true
in 运算符
上述使用undefined
方法判断,存在一个缺点:属性名存在,属性值为 undefined 的情况下,就不能返回想要的结果。
javascript
let obj = {}
// 新增一个值为undefined的属性
obj.birthday = undefined
console.log(obj.birthday) // undefined
console.log(obj.birthday !== undefined) // false
这个时候,就需要用到 in 运算符。
- in运算符希望它的左操作数是一个字符串或可以转换为字符串,希望它的右侧操作数是一个对象。
- 可以判断指定对象的自有属性和继承属性中是否存在某属性,如果存在则返回 true。 in 运算符也能检测到原型链上的属性。
- 值为 undefined 的属性也可以正常判断。
javascript
let obj = {
name: 'Scarlett',
age: 37
}
// 新增一个值为undefined的属性
obj.birthday = undefined
console.log('birthday' in obj); // true
console.log('name' in obj); // true
console.log('toString' in obj); // true 继承属性
Object.hasOwnProperty()
hasOwnProperty()
用来判断一个对象是否有你给出的名称的属性或对象。有则返回true,没有返回false,
不过需要注意的是,此方法无法检查 该对象的原型链中是否具有该属性,该属性必须是对象本身的一个成员。
javascript
let obj = {
name: 'Scarlett',
age: 37
}
// 新增一个值为undefined的属性
obj.birthday = undefined
console.log(obj.hasOwnProperty('birthday')); // true
console.log(obj.hasOwnProperty('name')); // true
console.log(obj.hasOwnProperty('toString')); // false 继承属性
遍历对象属性
在JavaScript中,有多种方法可以遍历对象。以下是一些常见的遍历对象的方法:
for...in 循环
使用 for...in
循环遍历对象的可枚举属性,包括原型链上的属性。
javascript
let person = { name: 'John', age: 30 };
for (let key in person) {
console.log(key, person[key]);
}
// 输出:
// name John
// age 30
需要注意的是,for...in
循环不仅会遍历对象本身的属性,还会遍历其原型链上的可枚举属性。为了避免遍历原型链上的属性,可以使用 hasOwnProperty
方法进行过滤。
javascript
for (let key in person) {
if (person.hasOwnProperty(key)) {
console.log(key, person[key]);
}
}
Object.keys() 键
使用 Object.keys()
方法获取对象所有可枚举属性的数组,然后进行遍历。
javascript
let person = { name: 'John', age: 30 };
console.log(Object.keys(person));
// 输出:[ 'name', 'age' ]
Object.keys(person).forEach(key => {
console.log(key, person[key]);
});
// name John
// age 30
Object.values() 值
使用 Object.values()
方法获取对象所有可枚举属性的值的数组,然后进行遍历。
javascript
let person = { name: 'John', age: 30 };
console.log(Object.values(person));
// 输出:[ 'John', 30 ]
Object.entries() 键&值
使用 Object.entries()
方法获取对象所有可枚举属性的键值对的数组,然后进行遍历。
javascript
let person = { name: 'John', age: 30 };
console.log(Object.entries(person));
// 输出: [ [ 'name', 'John' ], [ 'age', 30 ] ]
Object.entries(person).forEach(([key, value]) => {
console.log(key, value);
});
// name John
// age 30
这些方法可以根据具体的需求选择使用。for...in
循环是最基本的遍历方法,而 Object.keys()
、Object.values()
和 Object.entries()
提供了更灵活的方式来处理对象的键、值和键值对。
合并对象
Object.assign()
Object.assign()
方法既可以用作对象的复制,也可以用于对象的合并。
- 同名属性会被覆盖
- Object.assign种第一个值是目标对象,第二个值是源对象
javascript
var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };
var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 } 注意目标对象自身也会改变。
let obj_1 = { name: 'A', age: 37 }
let obj_2 = { name: 'B', age: 35 }
console.log(Object.assign(obj_1, obj_2));
// 输出:{ name: 'B', age: 35 }
扩展运算符
- 同名属性会被覆盖
- 使用...扩展运算符合并对象obj1对象在前和在后最后打印的结果是不同的
javascript
let obj_1 = { name: 'A', age: 37 };
let obj_2 = { name: 'B', age: 35 };
let result1 = { obj_1, obj_2 }
let result2 = { ...obj_1, obj_2 }
let result3 = { ...obj_1, ...obj_2 }
console.log(result1);
// 输出:{ obj_1: { name: 'A', age: 37 }, obj_2: { name: 'B', age: 35 } }
console.log(result2);
// 输出:{ name: 'A', age: 37, obj_2: { name: 'B', age: 35 } }
console.log(result3);
// 输出:{ name: 'B', age: 35 }
手写函数
通过手写函数,可以实现对象的合并。
推荐一篇文章:js中合并多个对象的方法 - 掘金 (juejin.cn)
文中通过手写函数实现深拷贝、浅拷贝!
参考资料
有些资料的链接附在文中,有些放在此处:
- JavaScript 对象 | 菜鸟教程 (runoob.com)
- JavaScript对象详解,js对象属性的添加_js对象添加属性-CSDN博客
- ES6+ 中的 JavaScript 工厂函数
- js对象复制_js复制对象的方法有哪几种-CSDN博客
- js 克隆对象4种方法汇总_js克隆对象的方法-CSDN博客
- js 扩展运算符... 与 Object.assign()是深拷贝还是浅拷贝
- 删除对象属性的三种方法_删除对象中的某个属性-CSDN博客
- JS遍历对象的七种方法 - 掘金 (juejin.cn)
- hasOwnProperty用来干嘛的-CSDN博客
- JavaScript:对Object对象的一些常用操作总结 - 前端开发随笔 - SegmentFault 思否
- JavaScript 判断对象中是否含有某个属性 - 个人文章 - SegmentFault 思否