人人都能学编程
English 开始学习
核心 · 前端第 6 课 / 共 8 课免费阅读

数组、对象与 JSON · 前端:HTML、CSS 与 JavaScript

怎么处理一堆东西,比如商店里的商品?

课程目录

为什么需要它

网页展示的数据,几乎都是以对象数组的形式送来的:商品、消息、搜索结果。把数据变成屏幕上的内容,就是筛选、变换、汇总,而 filter、map、reduce 每个都能用一行好读的代码做到。

直觉理解

对象把有名字的值放在一起;数组是有顺序的列表:

const lamp = { name: "Lamp", price: 30 };
const prices = [30, 120, 45];

用点来读值:lamp.price;用位置取元素:prices[0]。

数组方法接收一个小函数,作用在每个元素上,返回一个新的结果(原数组不变):

方法返回
filter(x => 条件)条件为 true 的那些元素
map(x => 新值)每个元素对应一个新值
reduce((acc, x) => …, 初始值)用所有元素算出的一个值
find(x => 条件)第一个符合的元素,或者 undefined

...(展开)用来复制:[...list, item] 是多了一个元素的新数组,{ ...obj, price: 9 } 是改了一个字段的新对象。

JSON 是对象在网络上传输的方式:JSON.stringify(obj) 把对象变成文字,JSON.parse(text) 再变回来。

定义

数组方法

A function such as filter, map or reduce that walks the array for you and returns a new result.
filter、map、reduce 这类函数,替你遍历数组并返回新结果。

展开(...)

Copies the items of an array or the fields of an object into a new one.
把数组的元素或对象的字段复制到一个新的数组或对象里。

JSON

A text format for data: objects in { }, arrays in [ ], strings in double quotes. APIs send and receive it.
一种表示数据的文字格式:对象用 { },数组用 [ ],字符串用双引号。API 收发的就是它。

示例

先筛选,再变换

动手试试

留下有货的商品,再只留下名字。

const products = [
  { name: "Lamp", price: 30, inStock: true },
  { name: "Desk", price: 120, inStock: false },
  { name: "Chair", price: 45, inStock: true },
];
const available = products.filter(p => p.inStock);
const names = available.map(p => p.name);
console.log(names);
console.log(products[1].price);
输出
[ 'Lamp', 'Chair' ]
120
逐步执行
  1. L6留下 Lamp 和 Chair:p.inStock 为 true 的那些。
  2. L7把每个商品变成它的名字。
  3. L8数组里的字符串打印时带引号。[ 'Lamp', 'Chair' ]
  4. L9原数组还是三个元素;下标 1 是桌子。120

加起来

动手试试

reduce 带着一个累计值,一个元素一个元素地往下走。

const prices = [30, 120, 45];
const total = prices.reduce((sum, price) => sum + price, 0);
console.log(total);
console.log(Math.max(...prices));
输出
195
120
逐步执行
  1. L2sum 从 0 开始,然后 0+30、30+120、150+45。195
  2. L4...prices 把数组展开成多个参数:Math.max(30, 120, 45)。120

复制与 JSON

动手试试

改副本,不改原件;再把对象变成文字。

const user = { name: "Ada", city: "London" };
const moved = { ...user, city: "Paris" };
console.log(user.city, moved.city);

const { name, city } = moved;
console.log(name, city);

const text = JSON.stringify(moved);
console.log(text);
console.log(JSON.parse(text).name);
输出
London Paris
Ada Paris
{"name":"Ada","city":"Paris"}
Ada
逐步执行
  1. L2一个新对象:先复制 user 的所有字段,再替换 city。
  2. L3原对象没有变。London Paris
  3. L5解构赋值把字段取出来放进变量。
  4. L8JSON 文字:键和字符串都用双引号。{"name":"Ada","city":"Paris"}

常见错误

有花括号却没写 return

x => x * 2 会返回值,但 x => { x * 2 } 什么都不返回(undefined)。用了花括号就要写 return。

sort() 按文字排序

[10, 9, 1].sort() 得到 [1, 10, 9]。数字要传比较函数:.sort((a, b) => a - b)。

用 === 比较对象

{a: 1} === {a: 1} 是 false:对象用 === 比较,问的是「是不是同一个对象」,不是「内容一不一样」。

小测验

1. 这段代码会输出什么?

const doubled = [1, 2, 3].map(x => { x * 2 });
console.log(doubled);
  1. A
    [ 2, 4, 6 ]
  2. B
    [ undefined, undefined, undefined ]
  3. C
    []
查看答案

答案:B

花括号让它变成了没有 return 的函数体,所以每个元素都变成了 undefined。

2. 这段代码会输出什么?

console.log([10, 9, 1].sort());
  1. A
    [ 1, 9, 10 ]
  2. B
    [ 1, 10, 9 ]
  3. C
    [ 10, 9, 1 ]
查看答案

答案:B

没有比较函数时,sort 按文字比较:"10" 排在 "9" 前面,因为 "1" < "9"。

动手练习

3 道练习,分三层:先预测程序的输出,再按新需求改程序,最后从零写一个。代码在浏览器里运行,提交马上判题。

  1. 预测输出购物车里有什么?

    准确写出它打印的内容。

  2. 改需求活跃用户的名字

    activeNames 应该返回活跃用户的名字,现在却返回一串 undefined。修好它。

  3. 从零写每个顾客的总额

    写一个 totalsByCustomer(orders)。每个订单形如 { customer: "ann", amount: 20 }。返回一个对象,记录每个顾客的总额:

    totalsByCustomer([
      { customer: "ann", amount: 20 },
      { customer: "bo", amount: 5 },
      { customer: "ann", amount: 10 },
    ])
    // { ann: 30, bo: 5 }

在互动课里练这一课

打开互动课,这些例子都能直接改、直接运行,练习题提交马上判题。免费开始,不用注册。

互动课按顺序解锁:前面的课还没学,会先带你到课程地图。

本课术语

术语中文英文定义
Array数组An ordered list of values: [1, 2, 3].
Object对象Named values grouped together: { name: "Ada" }.
JSONJSONA text format for data, used by almost every web API.
Spread展开运算符... copies the items of an array or the fields of an object.