佛山涌
西樵山
2019年1月29日,岩手県交通株式会社宣布将在2月1日上午10:00举行比亚迪K9纯电动巴士的发车仪式,这是该地区首台纯电动巴士。将投放于全长3.2公里的永旺购物中心南线,从盛岡站东口至永旺购物中心南每天运营9个来回。新车长12米,宽2.5米,高3.4米,可载客56人,几乎与现有的大型燃油客车相同;续航里程达250km,单次充电需5小时,夜间可前往矢巾町的充电站进行充电。
无意间在 B 站刷到,广州 13 路公交即将停运。作为一名公交迷,心里瞬间涌上许多感慨。这条线路从我孩童时代就陪伴左右,藏着太多散碎的童年记忆。
我印象里,它是广州第一条无人售票线路。小时候坐 13 路,紧紧攥着几毛钱硬币,小心翼翼投进投币箱,听见 “咔嚓” 一声清脆落币,只觉得无比新奇。那时的 13 路,还是经典的广州造 GZK6100,后置引擎、蓝白涂装,在满大街还是通道车的年代,显得格外 “高大上”。
得知它即将停运的消息,下班后我特意和太太来到文德路,再完整坐一遍 13 路的全程。从文德路总站出发,驶过海珠桥,途经工业大道、江南大道…… 每一个站名、每一段路,都熟悉得刻在心里。
熟悉的街景缓缓掠过耳边,是亲切的粤语报站;身旁是匆匆归家的上班族、带着孩子的家长,还有不少和我一样专程来告别的公交迷。大家举着手机、相机,安静地记录着这条线路最后的时光,没有太多言语,却都藏着同一份不舍。
特此纪念一趟车,一座城,一段回不去的时光。
广客巴士GZK6100系列是由广州客车厂于20世纪90年代生产的经典城市公交车型,采用后置发动机布局,方正外观具有鲜明时代特征。该系列涵盖多种改型(如A、AD、ED等),曾广泛服务于广州、深圳等城市,是中国早期无人售票公交的重要代表,承载一代城市公共交通记忆。
GZ644系列是80-90年代广州公交的主力,以皮实耐用著称,部分车辆直到2005年“广州牌”全面退市才正式告别街头。
toFixed 取后几位小数for…in 和 for…of 的区别for-in 历遍对象,通常获取 key(类似 Object.keys)for-of 历遍可迭代对象,如 Array、Map、Set 等setTimeout、setInterval、I/O 等Promise 回调(.then / .catch/ .finally)、MutationObserver 回调等fetch 会同步执行并立即返回一个 promisecall | apply | bind均用于改变函数内部 this 的指向
const obj = { name: "Alice" };
function greet() {
console.log(`Hello, ${this.name}!`);
}
greet.call(obj); // Hello, Alice!
greet.apply(obj); // Hello, Alice!
const boundGreet = greet.bind(obj);
boundGreet(); // Hello, Alice!
let 和 const
简化函数语法,自动绑定 this
`Hello ${name}`
const { age, name } = user;
const [first, second] = [1, 2];
const arr1 = [1, 2];
const arr2 = [...arr1, 3]; // [1, 2, 3]; // 合并数组
const objCopy = { ...originalObj }; // 合并对象
Promise 和 异步处理Promise.all – 等待所有 Promise 对象都执行完成
Promise.race – 返回第一个完成的 Promise(无论成功失败)
Promise.any – 返回第一个成功的 Promise
import 和 exportSet, Maplet s = new Set(); s.add(‘a’).add(‘b’)
let m = new Map(); m.set(’age’, 16)
底层实现机制: async/await 的核心是通过 Generator 函数和自动执行器实现的:
Generator 函数的语法糖,省去手动 next() 的步骤
Object.values({ a: 1, b: 2 }); // [1, 2]
Object.entries({ a: 1, b: 2 }); // [["a", 1], ["b", 2]]
"5".padStart(2, "0"); // "05"
const value = input ?? "default";
const module = await import('./module.js')
"a.b.c".replaceAll(".", "-"); // "a-b-c"
require 动态加载,运行时解析import 静态加载,编译时解析Proxy
set 拦截属性赋值,触发副作用(如重新渲染)OpenID
wx.login() 获取 code,后端用 code 调用微信接口换取 OpenIDUnionID
wx.getUserInfo() 获取 encryptedData, iv,发送到后端解密,或者通过按钮触发授权CSS3 新增了许多强大的选择器,可以更精确地匹配元素。
| 选择器 | 示例 | 描述 |
|---|---|---|
| 属性选择器 | input[type="text"] |
匹配具有特定属性的元素 |
| 结构伪类 | :nth-child(n) |
匹配第 n 个子元素 |
:first-of-type |
匹配同类型的第一个元素 | |
:last-child |
匹配最后一个子元素 | |
:not(selector) |
排除匹配的元素 | |
| UI 伪类 | :checked |
匹配被选中的表单元素(如复选框) |
:disabled |
匹配禁用的表单元素 | |
:enabled |
匹配可用的表单元素 | |
| 目标伪类 | :target |
匹配当前 URL 的锚点目标元素 |
CSS3 提供了更灵活的盒模型控制方式。
| 属性 | 描述 |
|---|---|
box-sizing: border-box |
使 width 和 height 包含 padding 和 border |
resize |
允许用户调整元素大小(both、horizontal、vertical) |
outline-offset |
设置轮廓(outline)与边框的偏移距离 |
CSS3 增强了背景和边框的样式控制。
背景(Background)
| 属性 | 描述 |
|---|---|
background-size |
控制背景图片大小(cover、contain、100% 100%) |
background-clip |
定义背景绘制区域(border-box、padding-box、content-box) |
background-origin |
定义背景定位的基准区域 |
background-attachment: local |
背景随内容滚动 |
background: url(img1.png), url(img2.png); |
多背景 |
边框(Border)
| 属性 | 描述 |
|---|---|
border-radius |
圆角边框(border-radius: 10px;) |
box-shadow |
盒子阴影(box-shadow: 5px 5px 10px #888;) |
border-image |
使用图片作为边框(border-image: url(border.png) 30 round;) |
CSS3 支持线性渐变和径向渐变。
| 类型 | 示例 | 描述 |
|---|---|---|
| 线性渐变 | background: linear-gradient(to right, red, blue); |
从左到右渐变 |
| 径向渐变 | background: radial-gradient(circle, red, yellow); |
从中心向外渐变 |
| 重复渐变 | background: repeating-linear-gradient(45deg, red, red 10px, blue 10px, blue 20px); |
重复渐变 |
CSS3 过渡允许属性在一定时间内平滑变化。
| 属性 | 描述 |
|---|---|
transition-property |
指定过渡的属性(如 width、opacity) |
transition-duration |
过渡持续时间(如 1s) |
transition-timing-function |
过渡速度曲线(ease、linear、cubic-bezier()) |
transition-delay |
过渡延迟时间 |
| 简写 | transition: width 1s ease 0.5s; |
CSS3 动画比过渡更强大,支持关键帧控制。
| 属性 | 描述 |
|---|---|
@keyframes |
定义动画关键帧 |
animation-name |
指定动画名称 |
animation-duration |
动画持续时间 |
animation-timing-function |
动画速度曲线 |
animation-delay |
动画延迟时间 |
animation-iteration-count |
动画播放次数(infinite 表示无限循环) |
animation-direction |
动画方向(normal、reverse、alternate) |
animation-fill-mode |
动画结束后保持状态(forwards、backwards) |
| 简写 | animation: move 2s ease infinite; |
示例:
@keyframes move {
0% { transform: translateX(0); }
100% { transform: translateX(100px); }
}
div {
animation: move 2s ease infinite;
}
CSS3 变形允许对元素进行 2D/3D 变换。
2D 变形:
| 属性 | 描述 |
|---|---|
transform: translate(x, y) |
移动元素 |
transform: rotate(45deg) |
旋转元素 |
transform: scale(1.5) |
缩放元素 |
transform: skew(30deg) |
倾斜元素 |
| 组合变换 | transform: rotate(45deg) scale(1.2); |
3D 变形:
| 属性 | 描述 |
|---|---|
transform: translate3d(x, y, z) |
3D 移动 |
transform: rotateX(45deg) |
绕 X 轴旋转 |
transform: perspective(500px) |
设置 3D 透视距离 |
CSS3 Flexbox 提供更灵活的布局方式。
| 属性 | 描述 |
|---|---|
display: flex |
启用 Flex 布局 |
flex-direction |
主轴方向(row、column) |
justify-content |
主轴对齐方式(center、space-between) |
align-items |
交叉轴对齐方式(center、stretch) |
flex-wrap |
是否换行(wrap、nowrap) |
flex-grow |
定义项目的放大比例 |
flex-shrink |
定义项目的缩小比例 |
flex-basis |
定义项目的初始大小 |
CSS3 Grid 提供二维布局系统。
| 属性 | 描述 |
|---|---|
display: grid |
启用 Grid 布局 |
grid-template-columns |
定义列宽(如 1fr 2fr) |
grid-template-rows |
定义行高 |
grid-gap |
定义行列间距 |
grid-column / grid-row |
定义项目占据的网格区域 |
<!DOCTYPE html>
<html>
<head>
<style>
.grid-container {
display: grid;
grid-template-columns: 100px 200px auto; /* 三列:固定100px,固定200px,剩余空间 */
gap: 10px;
background-color: #2196F3;
padding: 10px;
}
.grid-item {
background-color: rgba(255, 255, 255, 0.8);
border: 1px solid rgba(0, 0, 0, 0.8);
padding: 20px;
font-size: 30px;
text-align: center;
}
</style>
</head>
<body>
<div class="grid-container">
<div class="grid-item">1</div>
<div class="grid-item">2</div>
<div class="grid-item">3</div>
<div class="grid-item">4</div>
<div class="grid-item">5</div>
<div class="grid-item">6</div>
<div class="grid-item">7</div>
<div class="grid-item">8</div>
<div class="grid-item">9</div>
</div>
</body>
</html>
CSS3 媒体查询允许针对不同设备应用不同样式。
/* 屏幕宽度小于 600px 时生效 */
@media (max-width: 600px) {
body { background: lightblue; }
}
BEM(Block-Element-Modifier)是一种流行的 CSS 命名方法论,旨在提高代码可读性、可维护性和可复用性。其核心思想是通过模块化的方式组织 CSS 类名,避免样式冲突。
| BEM 将界面拆分为三个部分: | 部分 | 描述 | 示例 |
|---|---|---|---|
| Block | 独立的、可复用的组件(如按钮、卡片、导航栏)。 | .btn、.card |
|
| Element | 属于 Block 的子元素,不能单独使用(如按钮的图标、卡片的标题)。 | .btn__icon、.card__title |
|
| Modifier | 表示 Block 或 Element 的状态或变体(如禁用按钮、大号卡片)。 | .btn--disabled、.card--large |
-)的命名方式。 .header { ... } /* 页眉 */
.menu { ... } /* 菜单 */
.search-box { ... } /* 搜索框 */
Block名称__Element名称(双下划线 __ 连接)。 .menu__item { ... } /* 菜单项 */
.search-box__input { ... } /* 搜索框的输入框 */
.card__title { ... } /* 卡片的标题 */
Block--Modifier 或 Block__Element--Modifier(双短横线 -- 连接)。 .button--primary { ... } /* 主要按钮 */
.button--disabled { ... } /* 禁用按钮 */
.menu__item--active { ... } /* 当前选中的菜单项 */
<!-- Block: card -->
<div class="card card--highlight">
<!-- Element: card 的子元素 -->
<h2 class="card__title">标题</h2>
<p class="card__content">内容...</p>
<!-- 带 Modifier 的 Element -->
<button class="card__button card__button--large">点击</button>
</div>
/* Block */
.card {
border: 1px solid #ccc;
padding: 16px;
}
/* Modifier: 高亮卡片 */
.card--highlight {
background: #f5f5f5;
}
/* Element: 卡片标题 */
.card__title {
font-size: 18px;
color: #333;
}
/* Element: 卡片按钮 */
.card__button {
padding: 8px 16px;
}
/* Modifier: 大号按钮 */
.card__button--large {
padding: 12px 24px;
}| 标签类别 | 具体标签 |
|---|---|
| 语义化结构标签 | header、footer、nav、main、article、section、aside、figure、figcaption、time、mark |
| 多媒体标签 | audio、video、source、track、canvas、svg |
| 表单增强元素 | datalist、output、meter、progress |
| 新增 Input 类型 | input(date)、input(datetime)、input(email)、input(number)、input(range)、input(tel)、input(color)、input(time)、input(url)、input(search) |
| 其它标签 | details、summary、dialog、template |
生命周期:
cookie 可设置过期时间localStorage 永久存储sessionStorage 关闭标签页自动清除存储大小:
cookie 4KBsessionStorage 5MB – 10MBlocalStorage 5MB – 10MB作用域:
cookie:可设置 Domain 和 Path,控制哪些域名和路径可以访问localStorage:同源策略下的所有窗口和标签页共享sessionStorage:仅当前标签页有效,即使同源的其他标签页也无法访问以下是整理成 Markdown 表格的浏览器存储特性对比:
| 特性 | Cookie | localStorage | sessionStorage |
|---|---|---|---|
| 生命周期 | 可设置过期时间(Expires/Max-Age) |
永久存储,除非手动清除 | 关闭标签页后自动清除 |
| 存储大小 | 约 4KB | 5MB – 10MB(不同浏览器可能有差异) | 5MB – 10MB(同 localStorage) |
| 作用域 | 通过 Domain 和 Path 控制访问范围 |
同源策略下的所有窗口/标签页共享 | 仅当前标签页有效,同源其他标签页不可访问 |
| 数据发送 | 每次请求自动携带在 HTTP 头部 | 不自动发送,仅客户端存储 | 不自动发送,仅客户端存储 |
| API 易用性 | 需手动解析字符串 | 直接使用 setItem()/getItem() 等操作 |
同 localStorage |
补充说明
HttpOnly 和 Secure 属性。localStorage 或 sessionStorage。sessionStorage 适合临时数据(如表单填写中途防止丢失)。<script> 加载方式<!-- 默认加载:同步阻塞 HTML 解析 -->
<script src="script.js"></script>
<!-- defer 加载:延迟执行,直至 DOM 解析完成后 -->
<script defer src="script.js"></script>
<!-- async 加载:异步引入,下载完成后立即执行 -->
<script async src="script.js"></script>
加载说明:
<script> 同步加载,阻塞 HTML 解析和渲染<script> 延迟执行,DOM 解析完成后按顺序执行<script> 异步加载,下载完成后立即执行(执行顺序不固定)TypeScript的核心原则之一是对值所具有的结构进行类型检查。
interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
interface SquareConfig {
width: number
height: number
color?: string // 可选属性
}
只能在刚创建时修改其值
interface Point {
readonly x: number;
readonly y: number;
}
如果 SquareConfig带有上面定义的类型的color和width属性,并且还会带有任意数量的其它属性,可以这样定义:
interface SquareConfig {
width: number
color?: string
[propName: string]: any
}
interface SearchFunc {
(source: string, subString: string): boolean
}
// 对于函数类型的类型检查来说,函数的参数名不需要与接口里定义的名字相匹配。
let mySearch: SearchFunc;
mySearch = function(src: string, sub: string): boolean {
let result = src.search(sub);
return result > -1;
}
interface StringArray {
[index: number]: string;
}
let myArray: StringArray;
myArray = ["Bob", "Fred"];
let myStr: string = myArray[0];
interface ClockInterface {
currentTime: Date;
setTime(d: Date);
}
// 通过 implements 描述
class Clock implements ClockInterface {
currentTime: Date;
setTime(d: Date) {
this.currentTime = d;
}
constructor(h: number, m: number) { }
}
interface Shape {
color: string;
}
interface PenStroke {
penWidth: number;
}
interface Square extends Shape, PenStroke {
sideLength: number;
}
let square =
<Square>{};
square.color = "blue"
square.sideLength = 10
square.penWidth = 5
一个对象可以同时做为函数和对象使用,并带有额外的属性
interface Counter {
(start: number): string;
interval: number;
reset(): void;
}
function getCounter(): Counter {
let counter =
<Counter>function (start: number) { };
counter.interval = 123;
counter.reset = function () { };
return counter;
}
let c = getCounter();
c(10);
c.reset();
c.interval = 5.0;
class Animal {
move(distanceInMeters: number = 0) {
console.log(`Animal moved ${distanceInMeters}m.`);
}
}
class Dog extends Animal {
bark() {
console.log('Woof! Woof!');
}
}
const dog = new Dog();
dog.bark();
dog.move(10);
dog.bark();
通过 extends 关键字
class Animal {
name: string;
constructor(theName: string) { this.name = theName; }
move(distanceInMeters: number = 0) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
class Snake extends Animal {
constructor(name: string) { super(name); }
move(distanceInMeters = 5) {
console.log("Slithering...");
super.move(distanceInMeters);
}
}
在TypeScript里,成员都默认为 public。
class Animal {
public name: string;
}
当成员被标记成private时,它就不能在声明它的类的外部访问。
class Animal {
private name: string
constructor(theName: string) { this.name = theName; }
}
new Animal('Cat').name // 错误: 'name' 是私有的.
protected与private修饰符的行为很相似,但有一点不同, protected成员在派生类中仍然可以访问。
class Person {
protected name: string
constructor(name: string) { this.name = name }
}
class Employee extends Person {
private department: string
public getElevatorPitch() {
return `my name is ${this.name} and I work in ${this.department}.`
}
}
let dick = new Employee("Howard", "Sales")
console.log(dick.getElevatorPitch());
console.log(dick.name); // 错误
readonly关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化。
class Octopus {
readonly name: string;
constructor (theName: string) {
this.name = theName;
}
}
let dad = new Octopus("Man with the 8 strong legs");
dad.name = "Man with the 3-piece suit"; // 错误! name 是只读的.
TypeScript支持通过getters/setters来截取对对象成员的访问。
let passcode = "secret passcode";
class Employee {
private _fullName: string;
get fullName(): string {
return this._fullName;
}
set fullName(newName: string) {
if (passcode && passcode == "secret passcode") {
this._fullName = newName;
}
else {
console.log("Error: Unauthorized update of employee!");
}
}
}
let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
alert(employee.fullName);
}
抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。
abstract class Department { ... }
class AccountingDepartment extends Department { ... }
let department: Department // 允许创建一个对抽象类型的引用
department = new Department() // 错误: 不能创建一个抽象类的实例
department = new AccountingDepartment() // 允许对一个抽象子类进行实例化和赋值JavaScript 使用 IEEE 754 双精度浮点数表示所有数字,这会导致一些常见的小数精度问题,例如 0.1 + 0.2 !== 0.3。以下是处理 JavaScript 小数精度的常用技巧:
// toFixed方法(返回字符串)
let num = 0.1 + 0.2; // 0.30000000000000004
let fixed = num.toFixed(2); // "0.30"
// 使用Math.round四舍五入
function round(value, decimals) {
return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
}
round(1.005, 2); // 1.01
使用专门的数学库处理精确计算:
// 使用decimal.js示例
import Decimal from 'decimal.js';
let sum = new Decimal(0.1).add(new Decimal(0.2)); // 0.3
将小数转换为整数进行计算,再转换回去:
function add(num1, num2) {
const multiplier = Math.pow(10, Math.max(getDecimalLength(num1), getDecimalLength(num2)));
return (num1 * multiplier + num2 * multiplier) / multiplier;
}
function getDecimalLength(num) {
const decimalStr = num.toString().split('.')[1];
return decimalStr ? decimalStr.length : 0;
}
function numbersEqual(a, b, tolerance = 1e-10) {
return Math.abs(a - b) < tolerance;
}
// 使用Intl.NumberFormat
const formatter = new Intl.NumberFormat('en-US', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
formatter.format(0.1 + 0.2); // "0.30"
对于简单的显示问题,toFixed可能足够;对于复杂的财务计算,建议使用专门的库。