第6章 对象
创建对象
使用对象字面量创建对象
- 当 value 是个变量且与 key 同名时,可简写
- 有符号时,key 需要使用引号,且访问时只能通过obj['key']的方式访问
- 方法可简写为
func() {}
js
let age = 18;
let obj = {
name: '张三',
age,
sex: '男',
'birth-data': '2020-01-01',
sayHi: function () {
console.log('hi~');
},
sayHello() {
console.log('hello~');
}
};
使用 new Object 创建对象
js
let obj = new Object();
obj.name = '张三';
obj.age = 18;
obj.sex = '男';
obj.sayHi = function () {
console.log('hi~');
};
自定义构造函数
js
function People(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
let zhangsan = new People('张三', 18, '男');
对象属性
概念
- 每个对象里的键值对都是对象的属性
- 如果键值对的值是函数,则把这个函数称作方法
js
let obj = {
// 属性
name: '张三',
age: 18,
sex: '男',
'birth-data': '2020-01-01',
// 方法
sayHi: function () {
console.log('hi~');
}
};
访问对象属性
- 方式一:
obj.key
- 方式二:
obj['key']
遍历对象属性
- 方式一:使用
Object.keys()
方法 - 方法二:使用
for...in
方法
js
// 方式一
console.log(Object.keys(obj)); // [ 'name', 'age', 'sex', 'sayHi' ]
// 方法二
for (let key in obj) {
console.log(key);
}
删除对象属性
- 使用 delete 关键字
js
delete obj.name;
console.log(Object.keys(obj)); // [ 'age', 'sex', 'sayHi' ]
getters 与 setters
概念
- JavaScript 中的 get、set 方法与 Java 等语言中的不同
- JavaScript 中通过访问属性的方式进行使用,而不是 get() set() 类似 Vue 中的计算属性
字面量创建的对象
js
let person = {
firstName: '三',
lastName: '张',
get fullName() {
return this.lastName + this.firstName;
},
// setters只能接受一个参数
set fullName(fullName) {
let [lastName, firstName] = fullName.split(' ');
this.firstName = firstName;
this.lastName = lastName;
}
};
console.log(person.fullName); // 张三
person.fullName = '李 四';
console.log(person.fullName); // 李四
构造函数创建的对象
js
function People(name, position) {
this.name = name;
this.position = position;
}
let people = new People('张三', 'CEO');
Object.defineProperty(people, 'info', {
get: function () {
return this.name + ' ' + this.position;
},
set: function (info) {
let [name, position] = info.split(' ');
this.name = name;
this.position = position;
}
});
console.log(people.info); // 张三 CEO
zhangsan.info = '李四 CFO';
console.log(people.info); // 李四 CFO
扩展运算符
在对象中使用
js
let post = {
id: 1,
title: '标题1',
content: '这是内容'
};
console.log(post); // { id: 1, title: '标题1', content: '这是内容' }
let postClone = {
...post, // 将post中的所有属性复制过来
author: '只抄'
};
console.log(postClone); // { id: 1, title: '标题1', content: '这是内容', author: '只抄' }
在数组中使用
js
let arr = [1, 2, 3];
let arrClone = [...arr, 4];
console.log(arrClone); // [1, 2, 3, 4]
在函数中使用
js
function savePost(id, title, content) {
console.log(id, title, content);
}
// 这个数组会 Spread 成三个变量
savePost(...[1, '标题', '内容']); // 1 标题 内容
解构赋值
常规用法
- 变量名需与属性名相同,需要别名时,使用冒号
- 需要默认值时,使用等号
js
let post = {
id: 1,
title: '标题1',
content: '这是内容'
};
let { id, title: headline, content, comments = '没有评论' } = post;
console.log(id, headline, content, comments); // 1 标题1 这是内容 '没有评论'
解构复杂对象、数组
js
let post = {
id: 1,
title: '标题',
content: '这是内容',
comments: [
{ userId1: 1, comment: '评论1' },
{ userId1: 2, comment: '评论2' },
{ userId1: 3, comment: '评论3' }
]
};
// 解构评论2
let {
comments: [, { comment }]
} = post;
console.log(comment); // 评论2
动态 key
js
function getId(idKey, obj) {
let { [idKey]: id } = obj; // 使用 [] 包裹 key
return id;
}
console.log(getId('userId', { userId: 3 })); // 3
改变 this 的指向
默认情况
js
let people = {
id: 1,
name: '只抄',
printInfo() {
console.log('员工姓名:', this.name);
},
department: {
name: '技术部',
printInfo() {
console.log('部门名称:' + this.name);
}
}
};
// this是点号左边的对象
people.printInfo(); // 员工姓名:只抄
people.department.printInfo(); // 部门名称:技术部
call & apply & bind
- call & apply & bind 都可用于修改函数中this的指向
- call & apply 使用后会立即执行函数
- call 传参直接跟在后面
- apply 传参需要使用数组
- bind 使用后会返回一个新的函数
- bind 传参同 call
js
function printInfo(age, sex) {
console.log('员工姓名:', this.name);
console.log('年龄:', age);
console.log('性别', sex);
}
printInfo(18, '男'); // 员工姓名:undefined 年龄:18 性别 男
printInfo.call(people, 18, '男'); // 员工姓名:只抄 年龄:18 性别 男
printInfo.apply(people, [18, '男']); // 员工姓名:只抄 年龄:18 性别 男
let newPrintInfo = printInfo.bind(people, 18, '男');
newPrintInfo(); // 员工姓名:只抄 年龄:18 性别 男
继承
构造函数
- 继承属性:子类构造函数中调用父类构造函数,并改变 this 指向
- 继承方法:子类的 prototype 指向父类的实例对象
new Father()
js
function Father(uname) {
this.uname = uname;
}
Father.prototype.sayHi = function () {
console.log('hi~');
};
function Son(uname, age) {
Father.apply(this, arguments); // 第1步
this.age = age;
}
Son.prototype = new Father(); // 第2步(组合继承)
Son.prototype = Object.create(Father.prototype); // 第2步(寄生组合继承)
Son.prototype.constructor = Son; // 第2步(寄生组合继承)
const son = new Son('xiaowang', 15);
son.sayHi(); // hi~
对象
- 使用
Object.create()
方法 Object.create()
会将原对象作为新对象的 prototype
js
let father = {
uname: 'father'
};
let son = Object.create(father);
son.name = 'son';
son.age = 18;
// Object.getOwnPropertyNames(obj) 可用于查看自身的属性
console.log(Object.getOwnPropertyNames(son)); // ['name', 'age']
console.log(son.__proto__ === father); // true
原型 & 原型链
基本概念
prototype
:函数的一个属性,它的作用是获取该函数的 prototype__proto__
:对象的一个属性,它的作用是指向所属构造函数的 prototype- 注意:函数都是由 Function 原生构造函数创建的,所以函数的
__proto__
属性指向 Function 的prototype
属性
原型
- 构造函数有一个原型对象称作 prototype
- 通过 prototype 属性可以向对象添加属性和方法
- 实例对象会可以使用构造函数与原型对象中的属性和方法
js
function Father(uname, position) {
this.name = uname;
this.position = position;
this.signIn = function () {
console.log(this.name + '打卡');
};
}
let father = new Father('father', '父亲');
Father.prototype.age = 18;
console.log(father.age); // 18
原型链
- 原型链是指每个对象的原型还有上层的原型,直到 null
- JavaScript 顶层对象是 Object,Object 原型的原型为 null,达到原型链顶端
- 可以理解为原型链通过
__proto__
属性链接起来 obj.__proto__
也可以写作Object.getPrototypeOf(obj)
js
console.log(father.__proto__ === Father.prototype); // true
console.log(Father.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true
console.log(Object.getPrototypeOf(father) === Father.prototype); // true
图解
预览: