1. JavaScript 基础

  2. Document

  3. 运算符

  4. 深入数据和类型

  5. 函数进阶

  6. 原型、继承

  7. 浏览器存储

  8. Web API

  9. 事件

  10. 错误处理

  11. 异步编程

  12. 网络请求

  13. 模块

  14. 练习

  15. 实例

  16. 工具与规范

  17. 软件架构模式

  18. 设计模式

对象

对象是 JavaScript 中功能最多,也是最复杂的一种类型。不用怕,这个章节只是简单地入门一下。

对象是一个储存着多个键值对的类型,键是一个对象内唯一的字符串,而值可以是任意类型任意值,键与值一一对应,通过键可以找到对应的值。

比如下面的例子定义了包含人相关信息的对象,包含了姓名和身份证两个键值对。

let person = {
    name: "小明", // 姓名
    "identity card": 123456789123, // 身份证件
}

在以下的例子中定义了一个有着属性与方法(一般将属性值为函数的属性称之为方法)的对象。

$$edit$$
$$jsdemo$$
let mingren = {
    name: "鸣人",
    height: 1.8,
    eat: function () {
        alert("吃拉面。")
    },
    fight: function () {
        alert("螺旋丸。")
    },
}
alert(mingren.name)
mingren.fight()

$$tip

在其他语言中也有类似对象的类型,被称为字典(dict)。

$$

定义对象

定义一个对象的语法如下:

let object = {
    key: value,
    key2: value2,
}

由冒号分割的键值对被放在大括号当中,每一个键值对之间用逗号分隔。

  • key:键(属性名),键为字符串类型(如果属性符合变量命名规范或是可默认转换为字符串的数据值,则可省略引号),键名不能重复。
  • value:值(属性值),属性值可以为任意类型。

以下是一个小例子:

let person = {
    name: "鸣人",
    height: 1.8,
}
  • 定义了 person 对象。
  • person 对象中有 nameheight 键,分别对应 "鸣人"1.8

以下这个例子中,使用对象来组织数据明显比使用多个变量来得清晰明了。

$$edit$$
// 多个变量组织数据
let mingrenName = "鸣人"
let mingrenHeight = 1.8
let mingrenFight = function () {
    alert("螺旋丸")
}

let lufeiName = "路飞"
let lufeiHeight = 1.75
let lufeiFight = function () {
    alert("橡胶子弹")
}

// 使用对象组织数据

let mingren = {
    name: "鸣人",
    height: 1.8,
    fight: function () {
        alert("螺旋丸")
    },
}

let lufei = {
    name: "路飞",
    height: 1.75,
    fight: function () {
        alert("橡胶子弹")
    },
}

属性简写

在定义一个对象时,如果用已存的变量作为属性值,并且属性名与变量名相同的情况下则可以省略属性值。

$$jsdemo$$
$$edit$$
let name = "鸣人"
let person = {
    name, // 等同于 name: name
    height: 1.8,
}

alert(person.name)

获取与赋值

点操作符

只要在对象后接点操作符再接属性名即可获取属性值。

$$jsdemo$$
$$edit$$
let person = {
    name: "鸣人",
    height: 1.8,
}
alert(person.name)

同样的点操作符也可以修改属性值或赋新值。

$$jsdemo$$
$$edit$$
let person = {
    name: "鸣人",
    height: 1.8,
}
person.name = "路飞"
alert(person.name)
person.address = "木叶村"
alert(person.address)

方括号操作符

方括号操作符与点操作符类似,也可以取值与赋值。

$$jsdemo$$
$$edit$$
let person = {
    name: "鸣人",
    height: 1.8,
}
person["name"] = "路飞"
alert(person["name"])

点操作符与方括号操作符的区别在于:

  • 点操作符的属性名必须符合变量命名规范
  • 方括号操作符可以采用任何字符串属性名(非字符串类型会被默认转成字符串)或者变量。
$$jsdemo$$
$$edit$$
let person = {
    name: "鸣人",
    height: 1.8,
}
person[123] = 123
person["a b"] = 456

let str = "key"
person[str] = 789

alert(person["123"]) // 123
alert(person["a b"]) // 456
alert(person[str]) // 789

// person.123 = 123 // Unexpected number

获取所有的键

Object.keys() 方法可以数组的形式返回所有给定对象的键。

$$jsdemo$$
$$edit$$
let mingren = {
    name: "鸣人",
    height: 1.8,
    fight: function () {
        alert("螺旋丸")
    },
}
let keys = Object.keys(mingren)
console.log(keys) // ['name', 'height', 'fight']

获取所有的值

Object.values() 方法可以数组的形式返回所有给定对象的值。

$$jsdemo$$
$$edit$$
let mingren = {
    name: "鸣人",
    height: 1.8,
    fight: function () {
        alert("螺旋丸")
    },
}
let values = Object.values(mingren)
console.log(values) // ['鸣人', 1.8, ƒ]

获取所有的键值对

Object.entries() 方法可以数组的形式返回所有给定对象的键值对。

$$jsdemo$$
$$edit$$
let mingren = {
    name: "鸣人",
    height: 1.8,
    fight: function () {
        alert("螺旋丸")
    },
}
let entries = Object.entries(mingren)
console.log(entries) // [['name', '鸣人'], ['height', 1.8], ['fight', ƒ]]

for in 作用于对象

for in 作用于对象时,会循环对象的所有键。

$$jsdemo$$
$$edit$$
let mingren = {
    name: "鸣人",
    height: 1.8,
    fight: function () {
        alert("螺旋丸")
    },
}

for (let key in mingren) {
    alert(key)
    alert(mingren[key])
}

$$tip

与数组不同, for of 不能作用于对象。

$$

判断属性是否存在

in 操作符可以判断对象中是否存在对应的属性。

$$jsdemo$$
$$edit$$
let mingren = {
    name: "鸣人",
    height: 1.8,
    fight: function () {
        alert("螺旋丸")
    },
}

alert("name" in mingren) // true
alert("sex" in mingren) // false

删除属性

delete 操作符可以帮助我们删除对象中的属性。

$$jsdemo$$
$$edit$$
let person = {
    name: "鸣人",
    height: 1.8,
}
delete person.name
alert(person.name)

实例

对象最常用场景之一就是用来保存一些具有相同属性,同一类型的数据,并在之后批量处理。

$$jsdemo$$
$$edit$$
// 学生信息收集程序
let students = []
while (true) {
    let name = prompt("输入同学的姓名(空为退出)")
    if (!name) break
    let skill = prompt("输入同学的技能(空为退出)")
    if (!skill) break

    students.push({
        name,
        skill,
    })
}

alert(`共收集了${students.length}名同学的信息。`)
for (let item of students) {
    alert(`${item.name}同学的技能是${item.skill}。`)
}

console.log(students)

练习

  1. 写一个 函数 showScore,显示每个学生的姓名和分数,如果未及格则不显示分数。
let students = [
    {
        name: "佐助",
        score: 98,
    },
    {
        name: "小樱",
        score: 88,
    },
    {
        name: "鸣人",
        score: 28,
    },
]

showScore(students)

$$demo <button onclick="work()">显示分数</button> <script> function work() { function showScore(students) { for (let student of students) { if (student.score >= 60) { alert(姓名:${student.name}\n分数:${student.score}) } else { alert(姓名:${student.name}\n分数:不及格) } } }

    let students = [
        {
            name: "佐助",
            score: 98,
        },
        {
            name: "小樱",
            score: 88,
        },
        {
            name: "鸣人",
            score: 28,
        },
    ]

    showScore(students)
}

</script> $$

$$answer

$$jsdemo$$
$$edit$$
function showScore(students) {
    for (let student of students) {
        if (student.score >= 60) {
            alert(`姓名:${student.name}\n分数:${student.score}`)
        } else {
            alert(`姓名:${student.name}\n分数:不及格`)
        }
    }
}

let students = [
    {
        name: "佐助",
        score: 98,
    },
    {
        name: "小樱",
        score: 88,
    },
    {
        name: "鸣人",
        score: 28,
    },
]

showScore(students)

$$

  1. 写一个函数 sum,接收一个属性值全为数字的对象,并求出所有属性值的和。
let damages = {
    悟空: 800,
    贝吉塔: 660,
    农夫: 5,
}

alert(sum(damages)) // 1465

$$answer

$$jsdemo$$
$$edit$$

function sum(obj) {
    let values = Object.values(obj)

    let total = 0
    for (let value of values) {
        total += value
    }

    return total
}

let damages = {
    悟空: 800,
    贝吉塔: 660,
    农夫: 5,
}

alert(sum(damages)) // 1465

$$

  1. 写一个函数 isEmpty,接收一个对象作为参数,如果对象为空时返回 true ,否则返回 false
let mingren = {}
alert(isEmpty(mingren)) // true
mingren.name = "鸣人"
alert(isEmpty(mingren)) // false

$$answer

$$jsdemo$$
$$edit$$
function isEmpty(obj) {
    return Object.keys(obj).length === 0
}

let mingren = {}
alert(isEmpty(mingren)) // true
mingren.name = "鸣人"
alert(isEmpty(mingren)) // false

$$

  1. 写一个函数 highestFreq ,接收一个字符数组作为参数,返回出现频率最高的字符,比如:
let array = ["B", "B", "C", "I", "G", "A", "E", "E", "C", "C"]

alert(highestFreq(array)) // C

$$answer

$$jsdemo$$
$$edit$$
function highestFreq(array) {
    let mark = {}

    // 循环数组
    // 用对象标记出现的次数
    // 键为字母,值为出现的次数
    for (let letter of array) {
        if (letter in mark) {
            // 已经出现过,次数加 1
            mark[letter]++
        } else {
            // 第一次出现,记为一次
            mark[letter] = 1
        }
    }

    // 最高频的字母
    let highestLetter
    // 最大出现的次数
    let maxCount = 0
    for (let letter in mark) {
        if (mark[letter] > maxCount) {
            maxCount = mark[letter]
            highestLetter = letter
        }
    }

    return highestLetter
}

let array = ["B", "B", "C", "I", "G", "A", "E", "E", "C", "C"]

alert(highestFreq(array)) // C

$$

  1. 通过以下题库,完成首都问答的程序。
// 题库
let items = [
    {
        question: "中国的首都是?",
        answers: ["上海", "广州", "北京"],
        rightIdx: 2,
    },
    {
        question: "美国的首都是?",
        answers: ["纽约", "华盛顿", "伦敦"],
        rightIdx: 1,
    },
    {
        question: "新加坡的首都是?",
        answers: ["后港", "新加坡市", "裕华"],
        rightIdx: 1,
    },
    {
        question: "越南的首都是?",
        answers: ["河内", "胡志明市", "海防"],
        rightIdx: 0,
    },
    {
        question: "印度的首都是?",
        answers: ["新德里", "巴黎", "孟买"],
        rightIdx: 0,
    },
]

// 补全代码

$$demo <button onclick="work()">首都问答</button> <script> function work() { let items = [ { question: "中国的首都是?", answers: ["上海", "广州", "北京"], rightIdx: 2, }, { question: "美国的首都是?", answers: ["纽约", "华盛顿", "伦敦"], rightIdx: 1, }, { question: "新加坡的首都是?", answers: ["后港", "新加坡市", "裕华"], rightIdx: 1, }, { question: "越南的首都是?", answers: ["河内", "胡志明市", "海防"], rightIdx: 0, }, { question: "印度的首都是?", answers: ["新德里", "巴黎", "孟买"], rightIdx: 0, }, ]

    alert("首都问答~")

    let rightCount = 0

    for (let item of items) {
        let idx
        while (true) {
            let answer = prompt(
                `${item.question}\nA: ${item.answers[0]}\nB: ${item.answers[1]}\nC: ${item.answers[2]}`
            )
            switch (answer) {
                case "A":
                case "a":
                    idx = 0
                    break
                case "B":
                case "b":
                    idx = 1
                    break
                case "C":
                case "c":
                    idx = 2
                    break
                default:
                    // 如果是无效输入则让用户重新输入
                    // 用 continue 跳过当前循环
                    alert("无效输入,请重新输入。")
                    continue
            }
            // 有效输入的情况下最终会 break 结束循环
            break
        }

        if (idx === item.rightIdx) {
            alert("恭喜答对了~")
            rightCount++
        } else {
            alert(`很遗憾答错了,正确答案是:${item.answers[item.rightIdx]} 。`)
        }
    }

    alert(`共回答了 ${items.length} 题,答对了 ${rightCount} 题。`)
}

</script> $$

$$answer

$$jsdemo$$
$$edit$$
let items = [
    {
        question: "中国的首都是?",
        answers: ["上海", "广州", "北京"],
        rightIdx: 2,
    },
    {
        question: "美国的首都是?",
        answers: ["纽约", "华盛顿", "伦敦"],
        rightIdx: 1,
    },
    {
        question: "新加坡的首都是?",
        answers: ["后港", "新加坡市", "裕华"],
        rightIdx: 1,
    },
    {
        question: "越南的首都是?",
        answers: ["河内", "胡志明市", "海防"],
        rightIdx: 0,
    },
    {
        question: "印度的首都是?",
        answers: ["新德里", "巴黎", "孟买"],
        rightIdx: 0,
    },
]

alert("首都问答~")

let mark = {
    A: 0,
    a: 0,
    B: 1,
    b: 1,
    C: 2,
    c: 2,
}

let rightAmount = 0

for (let item of items) {
    let idx
    while (true) {
        let answer = prompt(
            `${item.question}\nA: ${item.answers[0]}\nB: ${item.answers[1]}\nC: ${item.answers[2]}`
        )

        idx = mark[answer]

        if (idx === undefined) {
            // 输入错误
            alert("无效输入,请重新输入。")
        } else {
            break
        }
    }

    if (idx === item.rightIdx) {
        alert("恭喜答对了~")
        rightAmount++
    } else {
        alert(`很遗憾答错了,正确答案是:${item.answers[item.rightIdx]} 。`)
    }
}

alert(`共回答了 ${items.length} 题,答对了 ${rightAmount} 题。`)