01 · NOTES / WebGIS 开发
第 12 节 · 对象与数组
2026 年 9 月 1 日
第 12 节 · 对象与数组
📌 版本信息:基于 ECMAScript 2025(基础语义多年稳定;2026-08-29 核对) 📚 来源:现代 JS 教程 · 对象 | 现代 JS 教程 · 数组 | MDN 解构赋值
一、这一节的目标
- 精通对象的读写:点、方括号、嵌套、可选链
?. - 精通数组常用操作与可变/不可变两种思路
- 掌握解构与展开运算符(现代 JS 代码的"方言",读不懂它们就读不懂 AI 写的代码)
- 理解引用类型的赋值/比较行为(一个必踩的坑提前拆掉)
- 能读懂 GeoJSON 的结构——你未来天天打交道的地图数据格式
二、对象:键值对的集合
// 字面量写法:GIS 数据建模的第一形态
const wuhan = {
name: '武汉',
location: { lat: 30.5929, lng: 114.3052 }, // 嵌套对象
population: 1233, // 万人
tags: ['省会', '江城'], // 值也可以是数组
};
// 读:点运算符(常用)/ 方括号(键是变量时必须用)
wuhan.name // '武汉'
wuhan.location.lat // 30.5929
const key = 'name';
wuhan[key] // '武汉'(点写法在这里会找名为 'key' 的属性,错)
wuhan['na' + 'me'] // 拼出来的键只能用方括号
// 写与增:直接赋值
wuhan.area = 8569; // 新增属性
wuhan.population = 1373; // 修改
// 删
delete wuhan.area;
// 可选链 ?:安全地读"可能不存在"的深层属性
const beijing = { name: '北京' };
beijing.location?.lat // undefined(不报错!没有 ?。 则直接 TypeError)
// 读外部 GeoJSON 数据时的保命符:别人的数据字段未必齐全
// 遍历
Object.keys(wuhan) // ['name', 'location', 'population', 'tags']
Object.values(wuhan) // 值的数组
Object.entries(wuhan) // [['name','武汉'], [...]] 键值对数组
三、数组:有序列表
const cities = ['武汉', '西安', '成都'];
cities.length // 3
cities[0] // '武汉'(下标从 0 开始!最后一个:length - 1)
cities[cities.length - 1] // '成都'
// 尾部操作(最高频)
cities.push('北京'); // 尾部加,返回新长度
cities.pop(); // 尾部删,返回删掉的元素
cities.unshift('上海'); // 头部加
cities.shift(); // 头部删
// 查找与判断
cities.includes('武汉') // true
cities.indexOf('西安') // 1(找不到返回 -1)
// 切片与拼接(都不改原数组!)
const a = [1, 2, 3, 4, 5];
a.slice(1, 3) // [2, 3]:切出 [1,3) 段
const b = a.concat([6]); // [1,2,3,4,5,6]
// 排序:注意!sort 默认按字符串排,数字要传比较函数
const nums = [30, 100, 4];
nums.sort() // [100, 30, 4] ← 字典序,经典坑
nums.sort((x, y) => x - y) // [4, 30, 100] ✓ 升序
nums.sort((x, y) => y - x) // 降序
// ⚠️ sort() 默认会改原数组!不想改就先 [...nums].sort(...)
四、解构与展开:现代 JS 的方言
读 AI 写的代码,这两个符号出现率 100%:
// ── 解构:从对象/数组里"按形状"拆值 ──
const city = { name: '武汉', lat: 30.59, lng: 114.3 };
const { name, lat } = city; // name='武汉', lat=30.59(按属性名拆)
const { name: cityName } = city; // 重命名:cityName='武汉'
const { zoom = 10 } = { }; // 带默认值:zoom=10
const [first, second] = cities; // 数组按位置拆:first='武汉'
// 函数参数解构(第 11 节的"对象参数"就是它)
function moveMarker({ lat, lng }) { /* ... */ }
moveMarker({ lat: 30, lng: 114 });
// ── 展开运算符 ...:把"打包的"拆开铺平 ──
const base = { name: '武汉' };
const updated = { ...base, population: 1373 };
// { name:'武汉', population:1373 } —— 常用:不改原对象,造一个改好的新对象(不可变更新)
const more = [...cities, '北京']; // 数组拼接新写法
const [head, ...rest] = cities; // rest = ['西安','成都']
💡 不可变更新的意义:React(第 03 模块)依赖"数据变没变"来决定界面更新不更新,
{...obj, key: value}这种"造新的而不是改旧的"写法是 React 状态更新的标准动作,现在先养成手感。
五、引用类型的坑:数组/对象是"地址"
原始类型(number/string/bool)存"值本身";对象/数组存的是地址:
let a = 5;
let b = a; // b 复制了值 5
b = 10; // a 还是 5,互不相干 ✓
const arr1 = [1, 2, 3];
const arr2 = arr1; // arr2 复制的是"地址"——指向同一个数组!
arr2.push(4);
console.log(arr1); // [1, 2, 3, 4] ← arr1 也变了!!
const obj1 = { name: '武汉' };
const obj2 = { ...obj1 }; // 展开 = 浅拷贝,造了个新对象
obj2.name = '西安';
console.log(obj1.name); // '武汉' ✓ 这次没受影响
- 浅拷贝(
{...obj}/[...arr]):复制第一层;如果属性里还有嵌套对象,里面仍是共享地址 - 深拷贝:
structuredClone(obj)(现代内置,推荐)彻底复制所有层
六、读懂 GeoJSON(本节的高潮)
GeoJSON 就是"对象 + 数组"的套娃,现在你已经具备读懂它的全部知识:
const quake = {
type: 'FeatureCollection', // 顶层固定写法:要素集合
features: [ // 数组:装着一堆"要素"
{
type: 'Feature',
geometry: { // 几何:在哪
type: 'Point',
coordinates: [114.3052, 30.5929], // ⚠️ 经度在前,纬度在后!(数学里 xy 的习惯)
},
properties: { // 属性:是什么
mag: 5.1, // 震级
place: '湖北武汉',
time: 1756444800000, // 时间戳(毫秒)
},
},
// ... 还可以有第二个、第 n 个 Feature
],
};
// 现在用你刚学的知识取值:
quake.features[0].properties.mag // 5.1
quake.features[0].geometry.coordinates[0] // 114.3052(经度)
quake.features[0]?.properties?.place // '湖北武汉'(可选链保平安)
第 04 模块会把 GeoJSON 规范完整过一遍;USGS 地震数据(m00 练习用过的)就是这个形状——你已经能徒手解剖它了。
七、动手跟练:12 · 学生成绩管理
配套文件:02-web-basics/examples/12-学生成绩管理.html(Console 驱动的数据练习,DOM 只负责展示)
步骤:
- Live Server 打开,F12 看 Console,对照代码读每一步输出
- 数据是一组"学生对象数组"(和 GeoJSON 的形状神似)
- 完成 6 个 TODO:查不及格人数、找最高分学生、给某人加一门课成绩、展开运算造新数组不改原数据、structuredClone 深拷贝、把学生列表渲染成表格
通关标准:
- 不查资料说出引用类型的赋值坑现象
- 能解释"浅拷贝后嵌套对象仍共享"的原因
- 能徒手画出 GeoJSON 的结构树(type → features → geometry/properties)
八、自测题
city['na'+'me']和city.name都能取到 name,什么时候必须用方括号?[100, 30, 4].sort()的结果是什么?为什么?{...obj, age: 18}做了什么?为什么 React 时代偏好这种写法?- 浅拷贝和深拷贝的区别?现代深拷贝用哪个内置函数?
- GeoJSON 的
coordinates里经度和纬度谁在前?
参考答案
- 键是变量/表达式拼出来的、或键含特殊字符时,必须方括号。
[100, 30, 4]——sort 默认按字符串字典序,'100' < '30' < '4'。- 浅拷贝出一个新对象并把 age 覆盖/新增为 18,原对象不动;React 靠"引用是否变化"判断是否重渲染,改旧对象会骗过它。
- 浅拷贝只复制第一层,嵌套引用类型仍共享;深拷贝用
structuredClone()。 - 经度在前(GeoJSON 规定 [lng, lat],与日常"纬度,经度"的习惯相反,地图库对接时的高频事故点)。
九、下一步
数据会组织了,但处理数据还在用 for 循环裸写 → 第 13 节:数组高阶方法,map/filter/reduce 三板斧让你像写句子一样处理数据。
TAGSweb