Object
简介:在JavaScript中,我们使用最多的就是对象,但我们很少自定义一个对象去使用,更多的是使用构造函数(函数章节讲解)来new一个对象,其实我们在不知不觉中一直在使用对象,JS中大部分类型都是对象如 String/Number/Math/RegExp/Date 等等。
下面通过代码说明下:
//下面两种方式定义字符串是等价的
let st = '字符串';
//但下面这种通过构造函数,更能说明str是对象
let str = new String('字符串');
//再比如Number类型
let nu = 1;
let num = new Number(1);
其他类型类似不再代码说明。
创建(声明)对象
两种声明方式,一种是构造函数形式,一种是对象字面量。
//new Object构造函数方式
let person = new Object();//与let person = {};相同
person.name = 'Tom';
person.age = 20;
//对象字面量
let person = {
name:'Tom',
age:20
}
两种声明对象的方式,我们一般都会使用对象字面量表示法。
操作属性
操作属性也有两种方式,点语法和中括号,特别注意使用中括号操作属性,中括号里面必须是字符串形式。
let person = {
name: 'Tom',
age: 20
}
console.log(person.name);//点语法
console.log(person['name']);//中括号形式,必须是字符串
其实我们习惯使用点语法,但有时候无法使用点语法,比如属性名中有空格“first name”,我们就要使用功能更加强大的中括号形式:
let people = {
'first name': 'Tom',
age: 20
}
console.log(people['first name']);
使用中括号的主要优势是可以通过变量访问属性:
let name = 'first name';
let people = {
'first name': 'Tom',
age: 20
}
console.log(people[name]);
其实中括号里面可以是字符串,表达式,甚至是函数:
function nameStr() {
return 'first name';
}
let people = {
'first name': 'Tom',
age: 20
}
console.log('表达式:' + people['first ' + 'name']);
console.log('函数:' + people[nameStr()]);
总结:使用.点语法
操作属性更简洁,[]中括号
主要用于通过变量定义属性的场景
添加属性
let people = {
name: 'Tom'
}
people.age = 20;
console.log(people);//{name: "Tom", age: 20}
删除属性delete
let people = {
name: 'Tom',
age: 20
}
console.log(people);//{name: "Tom", age: 20}
delete people.age;
console.log(people);//{name: "Tom"}
检测属性
hasOwnProperty
检测对象自身是否包含指定的属性,不检测原型链上继承的属性。
let people = {
name: 'Tom',
age: 20
}
console.log(people.hasOwnProperty('name'));
console.log(Object.hasOwnProperty.call(people, 'name'));
使用 in
可以在原型对象上检测(原型会在下面详细讲解,这里有疑问先不要着急)
先来看下people的原型:
let person = {
age: 20
}
console.dir(person);
console.log('toString' in person);//toString是原型对象上的属性
获取属性名
使用 Object.getOwnPropertyNames
()和Object.keys()可以
获取对象的属性名集合
let person = {
name: 'Tom',
age: 20
}
console.log(Object.getOwnPropertyNames(person));//["name", "age"]
console.log(Object.keys(person));//["name", "age"]
简写
推荐简写方式:
let name = 'first name';
//属性名和对应值变量名称相同可简写为:
let people = {
name,//正常应写为:name:name
age:20
}
//对象中的方法简写:
let person = {
name:'Tom',
run(){//正常应写为:run:function(){}
console.log('跑步');
}
}
this
this主要出现在对象和构造函数中,比如:
//this在对象中的体现
let person = {
name: 'Tom',
sayName() {
console.log(this.name);
}
}
person.sayName();
//this在构造函数中的体现
function Person(name) {
this.name = name;
this.sayName = function () {
console.log(this.name);
}
}
let per = new Person('Jerry');
per.sayName();
合并对象
Object.assign()
let dest = { a: 'age' };
Object.assign(dest, { b: 'bar' }, { c: 'car' });
console.log(dest);//{a: "age", b: "bar", c: "car"}
展开语法
let bc = { b: 'bar', c: 'car' };
let dest = { a: 'age', ...bc };
console.log(dest);//{a: "age", b: "bar", c: "car"}
对象解构赋值
对象解构就是使用与对象匹配的结构来实现对象属性的赋值。
简单使用
let person = {
name: 'Tom',
age: 20
}
let { name: personName, age: personAge } = person;
console.log(personName);//Tom
console.log(personAge);//20
复杂使用
let person = {
name: 'Tom',
age: 20,
hand: {
left: 'left',
right: 'right'
}
}
//1.简写,直接使用属性名作为变量名
let { name, age } = person;
console.log(name, age);//Tom 20
//2.不完全解构,有时候我们只需要对象的部分属性值
let { name: pName } = person;
console.log(pName);//Tom
//3.默认值,如果属性不存在则该变量值为undefined,但可以赋默认值,记住一定要用等号=,不是冒号:
let { job = 'engineer' } = person;
console.log(job);//engineer
//4.嵌套解构
let { hand: { right } } = person;
console.log(right);//right
函数解构传参
数组参数和对象参数
//数组参数,默认值c=3
function arr([a, b, c = 3]) {
console.log(a, b, c);//1 2 3
}
arr([1, 2]);
//对象参数,默认值title = '对象参数'
function person({ name, age, title = '对象参数' }) {
console.log(name, age, title);//'Tom' 20 '对象参数'
}
person({ name: 'Tom', 'age': 20 });
对象浅拷贝与深拷贝
对象的浅拷贝,深拷贝是与引用类型相关联的。
浅拷贝
子对象和父对象,引用类型属性指向同一块内存地址,即浅拷贝。改变子对象引用类型属性值,也会影响父对象。
let person = {
name: 'Tom',
age: 20,
memo: {
title: '拷贝'
},
data: [1, 2]
}
let copyObj = {};
//1.遍历方式:只遍历一层
for (const key in person) {
copyObj[key] = person[key];
}
console.log(copyObj);//{"name":"Tom","age":20,"memo":{"title":"拷贝"},"data":[1,2]}
copyObj.memo.title = 'copy';
//修改copyObj中的引用属性值,person也会发生修改
console.log(copyObj);//{"name":"Tom","age":20,"memo":{"title":"copy"},"data":[1,2]}
console.log(person);//{"name":"Tom","age":20,"memo":{"title":"copy"},"data":[1,2]}
//2.Object.assign()混入
Object.assign(copyObj, person);
copyObj.memo.title = '复制';
//修改copyObj中的引用属性值,person也会发生修改
console.log(copyObj);//{"name":"Tom","age":20,"memo":{"title":"复制"},"data":[1,2]}
console.log(person);//{"name":"Tom","age":20,"memo":{"title":"复制"},"data":[1,2]}
//3.展开语法(点语法)
copyObj = { ...person };
copyObj.memo.title = '展开语法复制';
//修改copyObj中的引用属性值,person也会发生修改
console.log(copyObj);//{"name":"Tom","age":20,"memo":{"title":"展开语法复制"},"data":[1,2]}
console.log(person);//{"name":"Tom","age":20,"memo":{"title":"展开语法复制"},"data":[1,2]}
深拷贝
let person = {
name: 'Tom',
age: 20,
memo: {
title: '拷贝'
},
data: [1, 2],
run() {
console.log('run')
}
}
let copyObj = {};
//1.JSON序列化反序列化
copyObj = JSON.parse(JSON.stringify(person));
console.log(copyObj);//{"name":"Tom","age":20,"memo":{"title":"拷贝"},"data":[1,2]}
copyObj.memo.title = 'copy';
//修改copyObj中的引用属性值,person不会修改,但我们也发现了一个问题,run函数属性丢失了
console.log(copyObj);//{"name":"Tom","age":20,"memo":{"title":"copy"},"data":[1,2]}
console.log(person);//{"name":"Tom","age":20,"memo":{"title":"拷贝"},"data":[1,2],run(){}}
//2.递归
function copyFun(obj) {
let copyObj = obj instanceof Array ? [] : {};
for (const [k, v] of Object.entries(obj)) {
copyObj[k] = typeof v === 'object' ? copyFun(v) : v;
}
return copyObj;
}
copyObj = copyFun(person);
console.log(copyObj);//{"name":"Tom","age":20,"memo":{"title":"拷贝"},"data":[1,2],run(){}}
copyObj.memo.title = 'copy';
//修改copyObj中的引用属性值,person不会修改,而且run函数属性也还在。
console.log(copyObj);//{"name":"Tom","age":20,"memo":{"title":"copy"},"data":[1,2],run(){}}
console.log(person);//{"name":"Tom","age":20,"memo":{"title":"拷贝"},"data":[1,2],run(){}}
属性的类型
1.数据属性特征
属性包括以下四种特性
特性 | 说明 | 默认值 |
---|---|---|
configurable | 能否使用delete、能否需改属性特性、或能否修改访问器属性 | true |
enumerable | 对象属性是否可通过for-in循环,或Object.keys() 读取 | true |
writable | 对象属性是否可修改 | true |
value | 对象属性的默认值 | undefined |
设置特征Object.defineProperty()
接收3个参数,对象,属性,属性特征对象。
let person = {};
Object.defineProperty(person, "name", {
value: 'Tom',
Configurable: true,
Enumerable: true,
Writable: true
});
console.log(person);//{name: "Tom"}
查看属性特征
console.log(Object.getOwnPropertyDescriptor(person, "name"));
2.访问器属性
特性 | 说明 | 默认值 |
---|---|---|
configurable | 能否使用delete、能否需改属性特性、或能否修改访问器属性 | true |
enumerable | 对象属性是否可通过for-in循环,或Object.keys() 读取 | true |
get | 获取函数,在读取属性时调用。 | undefined |
set | 设置函数,在写入属性时调用。 | undefined |
let person = {
age_: 20
};
Object.defineProperty(person, "age", {
configurable: true,
enumerable: true,
get() {
return this.age_;
},
set(newValue) {
if (newValue > 130) {
throw new Error('年龄设置不合法');
}
this.age_ = newValue;
}
});
person.age = 100;
console.log(person.age);
总结:
本章讲解了对象的基础知识,在下面的Vue章节中,会结合JavaScript基础,并讲解高级应用。