# JS 一个重要数据结构:对象

# 课程目标

  • 学习对象基础知识
  • 掌握对象创建方式 读取动态属性方法
  • 学习对象的基本操作
  • 掌握对象的克隆合并方法

# 对象基础

对象是一种数据类型,允许您将多个变量组合成一个包含键和值的变量。这通常用于表示或描述实体。例如,一个人、一个用户、一个产品等。

创建对象的方法如下:

const student = {
    id: 1,
    name: "Jackson",
    age: 20,
    requiredCourses:['Linear Alberia ','Intorduction of Computer',' Avanced Mathematics'],
    optionalCourses:['Software Engineering',' Signal and System','Principle of Compiling',' Data Structure']
};

对象命名最好用驼峰命名规则,比如必修课程命名为 requiredCourses,而不是 required_courses

读取/更新对象属性值

要读取或者更新对象中属性的值,可以使用点表示法如下:

const student = {
    id: 1,
    name: "Jackson",
    age: 20,
    requiredCourses:['Linear Alberia ','Intorduction of Computer',' Avanced Mathematics'],
    optionalCourses:['Software Engineering',' Signal and System','Principle of Compiling',' Data Structure']
};
//读取属性值
student.id  //1
student.name //Jackson
student.age //20
student.requiredCourses //['Linear Alberia ','Intorduction of Computer',' Avanced Mathematics']
student.optionalCourses //['Software Engineering',' Signal and System','Principle of Compiling',' Data Structure']

//更新对象属性值
student.id = 2
student.age = 21
console.log(student.id) //2
console.log(student.age) //20

读取动态属性值

现在,如果您想要读取的属性存储在一个变量中呢?例如:

const key = "id"; //属性名保存在变量 key 里面

student.key; // undefined

我们不能在这里使用点语法,因为属性是动态的。当您编写 student.key 时,JavaScript 将查找名为 key 的属性,student 中并没有 key 这个属性,所以返回 undefine。

为此,您必须使用方括号,如下所示:

const student = {
    id: 1,
    name: "Jackson",
    age: 20,
    requiredCourses:['Linear Alberia ','Intorduction of Computer',' Avanced Mathematics'],
    optionalCourses:['Software Engineering',' Signal and System','Principle of Compiling',' Data Structure']
};

const key = "id";
student[key]; // 1

对象简写

JavaScript 对象中有一个漂亮的特性是对象简写。假设您有一个变量 id,并且您想创建一个带有键的对象 student , 并且它的 id 值是一个变量 id

const id = 1;
const student = {
  name: "John",
  id: id,
};

这 id: id 有点多余,因此您可以如下编写:

const id = 1;
const student = {
  name: "John",
  id,
};

对象简写调试技巧

对象速记可以用作非常有用的调试技巧。假设您有以下代码:

const sum = (num1, num2) => {
  console.log(num1); // 10
  console.log(num2); // 8
  let total = num1 + num2;
  console.log(total); // 18
  return total;
};

// 用例
sum(10, 8);

以上是您在用 console.log 调试代码,希望在控制台打印出每一步骤的值,但是我们不知道这些值的对应关系

这时,对象简写可以巧妙解决此问题,您调用 console.log 打印变量时,可以将每个变量包装{}中 ,代码如下所示:

const sum = (num1, num2) => {
  console.log({ num1 }); // {num1: 1}
  console.log({ num2 }); // {num2: 3}
  let total = num1 + num2;
  console.log({ total }); // {total: 4}
  return total;
};

// 用例
sum(1, 3);

# 阅读

# 编码

  1. 创建一个叫做 bankAcount 的银行账户对象。

    该对象应该包含 4 个属性:

    • 你的名称 name
    • 你的存款 balance
    • 你的财富排行 rank
    • 你的银行利率 interestRatePercent

    该对象还应该具有 2 个方法:

    • deposit(amount) - 向存款中存入 amount 数量的钱
    • withdraw(amount) - 向存款中取出 amount 数量的钱
  2. 添加一个返回账户消息的 printAccountInfo() 方法,在控制台打印出用户的存款,财富排名以及银行利率

<script>
  //your complement console.log(savingsAccount.printAccountSummary());
  //您的存款总值:¥1000 ,您的财富排名为:1,您的银行利率为:1%
</script>
  1. 封装一个函数,检验 bankAcount 是否有 vip 这个属性,如果有就返回 true ,如果没有就返回 false
  2. 封装一个函数,遍历 bankAcount 的属性,并且控制台中打印出来
  3. 封装一个 isEmpty(obj) 判空函数,当对象没有属性的时候返回 true,否则返回 false。

# 对象遍历

# 编码

编码实现以下方法

let shoppingList = {
  hamburger: 12,
  milk: 5,
  orange: 25,
  banana: 49,
  ipad: 10111,
};

/**
 * @description 获取购物清单所有的商品
 * @method getKeys
 * @param {Object} obj 对象
 * @return {Array} 返回包含对象所有键名的数组
 */
function getKeys(obj) {
  // your complement
}

/**
 * @description 获取购物清单所有商品的价格
 * @method getVals
 * @param {Object} obj 对象
 * @return {Array} 返回包含对象所有键值的数组
 */
function getVals(obj) {
  // your complement
}

/**
 * @description 计算购物清单总价
 * @method sumshoppingList
 * @param {Object} obj 对象
 * @return {Number} 返回购物清单的总价
 */
function sumshoppingList(obj) {
  // your complement
}

/**
 * @description 给购物清单排序
 * @method sumshoppingList
 * @param {Object} obj 对象
 * @param {Boolean} ascendingOrder 如果值为true,就从小到大排序,值为false,就从大到小排序
 * @return {Object} 返按从大到小或者从小到大规律排序的购物清单列表
 */
function sumshoppingList(obj, ascendingOrder) {
  // your complement
}

# 对象解构赋值

# 编码

  1. 使用解构赋值实现交换 num1,和 num2 的值
let num1 = 1
let num2 = 0

//your complement

console.log(num1,num2) // - > 0 , 1
  1. 使用解构赋值实现对象的解构
/*
 * 解构要求
 * name 属性赋值给变量 name。
 * years 属性赋值给变量 age。
 * math 属性复制给变量 mathScore。
 * chemistry 属性复制给变量 chemistryScore。
 * biology 属性复制给变量 biologyScore。
 * sport 属性复制给变量 hobby1。
 * dance 属性复制给变量 hobby2。
 * marriageStaus 属性赋值给变量 marriageStaus(如果属性缺失则取默认值 false)
 */

let person = {
  name: "Amy",
  years: 30,
  score: {
    math: 99,
    chemistry: 80,
    biology: 78,
  },
  hobbies: ["sport", "dance"],
};

// your complement

console.log(name); // Amy
console.log(age); // 30
console.log(mathScore); // 99
console.log(chemistryScore); // 80
console.log(biologyScore); // 78
console.log(hobby1); // sport
console.log(hobby2); // dance

# 对象引用和复制

# 编码

了解值类型和引用类型的区别,了解各种对象的读取、遍历方式,并在 util.js 中实现以下方法:

// 使用递归来实现一个深度克隆,可以复制一个目标对象,返回一个完整拷贝
// 被复制的对象类型会被限制为数字、字符串、布尔、日期、数组、Object对象。不会包含函数、正则对象等
function deepClone(src) {
    // your implement
}

// 测试用例:
var srcObj = {
    a: 1,
    b: {
        b1: ["hello", "hi"],
        b2: "JavaScript"
    }
};
var abObj = srcObj;
var tarObj = deepClone(srcObj);

srcObj.a = 2;
srcObj.b.b1[0] = "Hello";

console.log(abObj.a);
console.log(abObj.b.b1[0]);

console.log(tarObj.a);      // 1
console.log(tarObj.b.b1[0]);    // "hello"

如果您完成速度较快,可以试着使用不同的方法实现一下对象的深拷贝

# 对象属性配置

# 编码一

了解 Object.defineProperty(),实现一个简易的数据双向绑定

<label>姓名:</label><input type="text" class="name" onchange="changeName()" />
<button onclick="changeInput()">恢复姓名为rose</button>
//利用通过 Object.defineProperty()来实现简易的双向数据绑定 //创建person对象 var
person = { name:'' } function changeName(){
//修改person对象中的name的值为输入框中的值 } Object.defineProperty(person,
'name', { // 这里实现双向绑定,监听name值变化,input也跟着变化 }) function
changeInput(){ //按钮事件 修改person对象中的name的值为rose }

题目要求

  • 当改变姓名输入框的值敲击回车,console 打印 person.name 的值与姓名输入框的值一致
  • 当在调试环境代码行输入 person.name = amber,姓名输入框的值自动变成 amber ,如下图所示
  • 点击恢复姓名为rose按钮,修改 person.name 的值为 rose (不要直接修改姓名输入框的值),输入框的值自动变成 rose。

# 编码二

在上一个任务的基础上,完成如下要求

function addID(id){
    //给person对象添加一个ID属性
    //值为'1'
    //不可重写,只可读
    //不可删除
    //不可枚举

}

//测试用例
addID(1)
console.log(persion.id); // logs 1
delete persion.id; // Nothing happens
console.log(persion.id); // logs 1
person.propertyIsEnumerable('id'); // false
person.id = 2; // throws TypeError: "id" is read-only

# 自测问题

  1. 与原始类型相比,对象和它们的区别是什么?
  2. 不用将代码粘贴到控制台中,能判断出这段代码的输出内容吗?
let a = {};
let b = a;
let c= {};

console.log( a == b );
console.log( a === b );
console.log( a == c )
  1. 下面这段代码会输出什么内容?
let animal = { species : "fish" };

Object.assign(user, { species: "dog" });

console.log(animal.species);
  1. 什么是浅拷贝?什么是深拷贝?请说说它们的区别
  2. 下面这段代码输入什么结果?怎么将它修改正确?
function makeAccount() {
  return {
    name: "Amy",
    ref: this
  };
}

let user = makeAccount();

console.log( user.ref.name ); // 结果是什么?