## 前言
ES6 学习笔记整理,主要记录一些最常用、最适合初学者先掌握的语法。
## 1. 变量声明:var、let、const
以前写 JavaScript 时,经常使用 `var` 声明变量。
```js
console.log(a); // undefined
var a = 10;
```
`var` 会发生变量提升,所以变量在声明前访问不会直接报错,而是得到 `undefined`。这种行为有时候会让代码变得不好理解。
ES6 新增了 `let` 和 `const`。
```js
let age = 25;
age = 26;
const name = "xiepei";
```
它们的区别可以简单理解为:
- `let`:声明普通变量,可以重新赋值。
- `const`:声明常量,不能重新赋值。
- `let` 和 `const` 都不能在同一作用域中重复声明。
- `let` 和 `const` 都有块级作用域。
例如:
```js
if (true) {
let a = 10;
}
console.log(a); // 报错,a 只在 if 代码块中有效
```
需要注意的是,`const` 限制的是“变量指向不能变”,不是对象里面的内容完全不能变。
```js
const user = {};
user.name = "xiepei";
console.log(user); // { name: "xiepei" }
```
这个例子中,`user` 仍然指向同一个对象,只是给对象添加了属性,所以不会报错。
## 2. 解构赋值
解构赋值可以从对象或数组中快速取值。
### 对象解构
```js
const obj = {
name: "xiepei",
age: 25,
a: 1,
b: 2
};
const { name, age } = obj;
console.log(name); // xiepei
console.log(age); // 25
```
如果想给取出来的变量换个名字,可以使用别名。
```js
const { name: xpName } = obj;
console.log(xpName); // xiepei
```
这里的意思是:从 `obj` 中取出 `name` 属性,但是保存到 `xpName` 这个变量里。
如果对象中没有某个属性,还可以设置默认值。
```js
const { c = 100 } = obj;
console.log(c); // 100
```
### 数组解构
数组也可以解构。
```js
const arr = "miaov".split("");
const [first, second, ...rest] = arr;
console.log(first); // m
console.log(second); // i
console.log(rest); // ["a", "o", "v"]
```
`...rest` 表示把剩下的内容收集起来,组成一个新数组。
## 3. Set:不重复的数据集合
`Set` 类似数组,但是它里面的值不能重复。
```js
const set = new Set(["a", "b", "c", "d"]);
console.log(set.size); // 4
set.add("e"); // 添加
set.delete("a"); // 删除
console.log(set.has("c")); // true
```
`Set` 常用方法:
- `add()`:添加值。
- `delete()`:删除值。
- `has()`:判断是否存在。
- `clear()`:清空。
- `size`:获取长度。
最常见的用途是数组去重。
```js
const arr = [13, 324, 545, 66, 66, 23, 23];
const result = [...new Set(arr)];
console.log(result); // [13, 324, 545, 66, 23]
```
这里先用 `new Set(arr)` 去掉重复值,再用 `...` 展开成数组。
## 4. Map:更灵活的键值对
对象也可以保存键值对,但对象的键一般是字符串或 Symbol。
`Map` 更灵活,它的 key 可以是任意类型,甚至可以是对象。
```js
const map = new Map();
map.set("name", "xiepei");
map.set("age", 25);
const objKey = { id: 1 };
map.set(objKey, "对象也可以作为 key");
console.log(map.get("name")); // xiepei
console.log(map.get(objKey)); // 对象也可以作为 key
```
常用方法:
- `set(key, value)`:添加或修改数据。
- `get(key)`:根据 key 获取 value。
- `has(key)`:判断 key 是否存在。
- `delete(key)`:删除某个 key。
- `clear()`:清空。
- `size`:获取数量。
如果只是普通结构,用对象就够了;如果 key 需要支持对象,就可以考虑 `Map`。
## 5. 遍历:for...in 和 for...of
`for...in` 和 `for...of` 看起来很像,但它们遍历出来的东西不一样。
`for...in` 遍历的是下标或键名。
```js
const arr = [10, 20, 30];
for (const index in arr) {
console.log(index);
}
```
输出:
```text
0
1
2
```
`for...of` 遍历的是值。
```js
const arr = [10, 20, 30];
for (const item of arr) {
console.log(item);
}
```
输出:
```text
10
20
30
```
简单记:
- 要下标或键名,用 `for...in`。
- 要具体的值,用 `for...of`。
## 6. class:更清晰的面向对象写法
ES6 之前,JavaScript 通常用构造函数和原型来模拟类。
```js
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.say = function () {
console.log("说话");
};
const p = new Person("xiepei", 25);
p.say();
```
ES6 提供了 `class` 写法,让面向对象代码更直观。
```js
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
say() {
console.log("我叫" + this.name + ",今年" + this.age + "岁");
}
static eat() {
console.log("这是静态方法");
}
}
const p = new Person("xiepei", 25);
p.say();
Person.eat();
```
说明:
- `constructor` 是构造方法,创建对象时自动执行。
- 普通方法写在类里面,不需要写 `function`。
- `static` 修饰的是静态方法,需要通过类本身调用。
### class 继承
继承使用 `extends`。
```js
class Coder extends Person {
constructor(name, age, money) {
super(name, age);
this.money = money;
}
say() {
console.log("我叫" + this.name + ",今年" + this.age + "岁,一个月赚" + this.money);
}
}
const coder = new Coder("xp", 25, 8000);
coder.say();
```
子类中如果写了 `constructor`,必须先调用 `super()`,因为 `super()` 会执行父类的构造方法。
## 7. Symbol:创建唯一值
`Symbol` 可以创建一个独一无二的值。
```js
const s1 = Symbol("a");
const s2 = Symbol("a");
console.log(s1 === s2); // false
```
即使描述文字一样,两个 Symbol 也不相等。
Symbol 常用来给对象添加不容易冲突的属性。
```js
const obj = {
a: "1",
b: "2"
};
const key = Symbol("a");
obj[key] = "symbol value";
console.log(obj);
```
如果要获取对象中的 Symbol 属性,可以使用:
```js
const symbols = Object.getOwnPropertySymbols(obj);
console.log(symbols);
```
## 8. 字符串新增方法
ES6 给字符串增加了一些很实用的方法。
```js
const str = "xiepei";
console.log(str.includes("xie")); // true
console.log(str.startsWith("xie")); // true
console.log(str.endsWith("i")); // true
console.log(str.repeat(3)); // xiepeixiepeixiepei
```
常用方法:
- `includes()`:判断是否包含某个字符串。
- `startsWith()`:判断是否以某个字符串开头。
- `endsWith()`:判断是否以某个字符串结尾。
- `repeat()`:重复字符串。
## 9. 模板字符串
模板字符串使用反引号。
```js
const name = "classname";
const html = `
<ul>
<li class="red"></li>
<li></li>
<li class="${name}"></li>
</ul>
`;
console.log(html);
```
模板字符串有两个优点:
1. 可以直接换行。
2. 可以使用 `${}` 插入变量、表达式或函数返回值。
```js
const n = 5;
const m = 6;
console.log(`n + m = ${n + m}`);
```
还可以写三元表达式。
```js
const weather = false;
console.log(`今天天气是:${weather ? "晴天" : "雨天"}`);
```
也可以调用函数。
```js
function fn() {
return "hello ES6";
}
console.log(`fn 函数返回值是:${fn()}`);
```
## 10. 数组新增方法
### Array.of()
`Array.of()` 可以更明确地创建数组。
```js
const arr = Array.of(10);
console.log(arr); // [10]
```
这和 `new Array(10)` 不一样。
```js
const arr = new Array(10);
console.log(arr); // 创建长度为 10 的空数组
```
### Array.from()
`Array.from()` 可以把类数组转换成真正的数组。
```js
const divs = document.querySelectorAll("div");
const arr = Array.from(divs);
console.log(Array.isArray(arr)); // true
```
### find() 和 findIndex()
`find()` 返回符合条件的第一个元素。
```js
const arr = [10, 20, 30, 40, 50];
const value = arr.find(function (item) {
return item > 30;
});
console.log(value); // 40
```
`findIndex()` 返回符合条件的第一个下标。
```js
const arr = [10, 20, 30, 40, 50];
const index = arr.findIndex(function (item) {
return item > 30;
});
console.log(index); // 3
```
## 11. 对象新增语法
### 属性简写
当对象的属性名和变量名相同时,可以简写。
```js
const a = 10;
const obj = {
a
};
console.log(obj); // { a: 10 }
```
等价于:
```js
const obj = {
a: a
};
```
### 方法简写
ES5 中常见写法:
```js
const obj = {
fn: function () {
console.log("加油");
}
};
obj.fn();
```
ES6 可以简写:
```js
const obj = {
fn() {
console.log("加油");
}
};
obj.fn();
```
### 变量作为属性名
属性名也可以通过变量传入。
```js
const attrName = "height";
const obj = {
[attrName]: "200px"
};
console.log(obj.height); // 200px
```
## 12. Object.is()
`Object.is()` 可以做更精确的比较。
```js
console.log(1 == "1"); // true
console.log(1 === "1"); // false
console.log(NaN === NaN); // false
console.log(Object.is(NaN, NaN)); // true
```
大多数情况下使用 `===` 就够了,但遇到 `NaN` 这种特殊值时,`Object.is()` 更准确。
## 13. Object.assign()
`Object.assign()` 可以合并对象。
```js
function move(options) {
const defaults = {
a: 1,
b: 2
};
const params = Object.assign({}, defaults, options);
console.log(params);
}
move({
a: 100,
b: 200
});
```
这里的意思是:
1. 先准备默认参数 `defaults`。
2. 再把用户传入的 `options` 覆盖进去。
3. 最后得到一个新的 `params` 对象。
注意第一个参数写 `{}`,是为了避免直接修改默认对象。
## 14. Object.keys()、Object.values()、Object.entries()
这三个方法可以把对象中的数据取出来。
```js
const obj = {
a: 1,
b: 2
};
console.log(Object.keys(obj));
console.log(Object.values(obj));
console.log(Object.entries(obj));
```
输出:
```text
["a", "b"]
[1, 2]
[["a", 1], ["b", 2]]
```
也可以配合 `for...of` 遍历。
```js
const obj = {
a: 1,
b: 2
};
for (const [key, value] of Object.entries(obj)) {
console.log(key, value);
}
```
## 15. 展开运算符
展开运算符是 `...`,可以把数组或对象“打散”。
### 数组展开
```js
const arr = [1, 2, 3];
const newArr = [...arr, 4, 5];
console.log(newArr); // [1, 2, 3, 4, 5]
```
### 对象展开
```js
const obj = {
a: 1,
b: 2,
c: 3
};
const result = {
...obj
};
console.log(result); // { a: 1, b: 2, c: 3 }
```
展开运算符也经常和 `Set` 搭配做数组去重。
```js
const arr = [13, 324, 545, 66, 66, 23, 23];
const result = [...new Set(arr)];
console.log(result);
```
## 16. 函数默认参数
ES6 允许给函数参数设置默认值。
```js
function add(a, b = 100) {
return a + b;
}
console.log(add(1)); // 101
console.log(add(1, 2)); // 3
```
当调用函数时没有传入第二个参数,就使用默认值 `100`。
## 17. 箭头函数
箭头函数可以让函数写法更简洁。
```js
const fn = () => {
console.log("你好");
};
fn();
```
如果只有一个参数,可以省略小括号。
```js
const double = num => {
return num * 2;
};
console.log(double(10)); // 20
```
如果函数体只有一句返回值,还可以继续简写。
```js
const double = num => num * 2;
console.log(double(10)); // 20
```
箭头函数需要注意 `this`。
普通函数的 `this` 通常取决于调用方式,而箭头函数没有自己的 `this`,它会使用外层作用域中的 `this`。
所以箭头函数适合写回调函数,但在对象方法、构造函数、事件处理等需要动态 `this` 的地方,要谨慎使用。
## 总结
ES6 的重点不是背语法,而是理解它解决了什么问题。
可以这样记:
- `let`、`const`:让变量声明更安全。
- 解构赋值:让取值更方便。
- `Set`:适合处理不重复的数据。
- `Map`:适合保存更灵活的键值对。
- `for...of`:适合遍历数组的值。
- `class`:让面向对象写法更清晰。
- `Symbol`:创建唯一值,避免属性名冲突。
- 模板字符串:让字符串拼接更舒服。
- 数组和对象新增方法:减少重复代码。
- 箭头函数:让回调函数写法更简洁,但要注意 `this`。
学习 ES6 最好的方法不是一次把所有语法背完,而是每个语法都写一个小例子,看清楚输入、执行过程和输出结果。只要能把这些常用语法用起来,后面学习 Vue、Node.js 或前端工程化时就会顺很多。
