第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图解










