对象

对象是 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) {
        while (true) {
            let answer = prompt(
                `${item.question}\nA: ${item.answers[0]}\nB: ${item.answers[1]}\nC: ${item.answers[2]}`
            )

            let idx
            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
            }

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

            // 有效输入的情况下最终会 break 结束循环
            break
        }
    }

    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 rightCount = 0

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

        let idx
        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
        }

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

        // 有效输入的情况下最终会 break 结束循环
        break
    }
}

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

$$