es6
1. let 和 const
要逐渐放弃 let,在项目中多用 let 和 const,与 let 的区别:
let 有变量提升,有初始化提升,值可变
let 有变量提升,没有初始化提升,值可变
const 有变量提升,没有初始化提升,值不可变,但如果是定义对象,则属性可变
暂时性死区问题说明:其实 let 和 const 是有变量提升的,但是没有初始化提升:
let name = "柯基";
function fn() {
console.log(name);
let name = "sunshin_lin";
}
fn(); // Cannot access 'name' before initialization
块级作用域解决问题:
for (let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
});
} // 5 5 5 5 5
for (let i = 0; i < 5; i++) {
setTimeout(() => {
console.log(i);
});
} // 0 1 2 3 4
2. 默认参数
开发中曾遇到过这样的问题,如果参数不传进来,就设置默认参数
function fn(name, age) {
let name = name || "柯基";
let age = age || 18;
console.log(name, age);
}
fn(); // 柯基 18
但是这么写确实不优雅,可以使用 ES6 的默认参数
function fn(name = "柯基", age = 18) {
console.log(name, age);
}
fn(); // 柯基 18
fn("sunshine", 22); // sunshine 22
3. 扩展运算符
曾经想要拼接多个数组,只能这么做
const arr1 = [1, 2, 4];
const arr2 = [4, 5, 7];
const arr3 = [7, 8, 9];
const arr = arr1.concat(arr2).concat(arr3)[(1, 2, 4, 4, 5, 7, 7, 8, 9)];
现在可以更优雅地进行拼接
const arr1 = [1, 2, 4];
const arr2 = [4, 5, 7];
const arr3 = [7, 8, 9];
const arr = [...arr1, ...arr2, ...arr3][(1, 2, 4, 4, 5, 7, 7, 8, 9)];
4. 剩余参数
一个函数,传入参数的个数是不确定的,这就可以用 ES6 的剩余参数
function fn(name, ...params) {
console.log(name);
console.log(params);
}
fn("柯基", 1, 2); // 柯基 [ 1, 2 ]
fn("柯基", 1, 2, 3, 4, 5); // 柯基 [ 1, 2, 3, 4, 5 ]
5. 模板字符串
以前,拼接字符串只能这么做
const name = "柯基";
const age = "22";
console.log(name + "今年" + age + "岁"); // 柯基今年22岁
现在可以这么做,会更优雅
const name = "柯基";
const age = "22";
console.log(`${name}今年${age}岁`); // 柯基今年22岁
6. Object.keys
可以用来获取对象的 key 的集合,进而可以获得对应 key 的 value
const obj = {
name: "柯基",
age: 22,
gender: "男",
};
const keys = Object.keys(obj);
console.log(keys); // [ 'name', 'age', 'gender' ]
7. 箭头函数
以前使用普通函数
function fn() {}
const fn = function () {};
ES6 新加了箭头函数
const fn = () => {};
// 如果只有一个参数,可以省略括号
const fn = (name) => {};
// 如果函数体里只有一句return
const fn = (name) => {
return 2 * name;
};
// 可简写为
const fn = (name) => 2 * name;
// 如果返回的是对象
const fn = (name) => ({ name: name });
普通函数和箭头函数的区别: 1.箭头函数不可作为构造函数,不能使用 new 2.箭头函数没有的 this 3.箭头函数没有 arguments 对象 4.箭头函数没有原型对象
8. Array.forEach
ES6 新加的数组遍历方法
const eachArr = [1, 2, 3, 4, 5]
// 三个参数:遍历项 索引 数组本身
// 配合箭头函数
eachArr.forEach((item, index, arr) => {
console.log(item, index, arr)
})
1 0 [ 1, 2, 3, 4, 5 ]
2 1 [ 1, 2, 3, 4, 5 ]
3 2 [ 1, 2, 3, 4, 5 ]
4 3 [ 1, 2, 3, 4, 5 ]
5 4 [ 1, 2, 3, 4, 5 ]
9. Array.map
常用于返回一个处理过后的新数组
const mapArr = [1, 2, 3, 4, 5];
// 三个参数:遍历项 索引 数组本身
// 配合箭头函数,对每一个元素进行翻倍
const mapArr2 = mapArr.map((num, index, arr) => 2 * num);
console.log(mapArr2)[(2, 4, 6, 8, 10)];
10. Array.filter
顾名思义,用来过滤的方法
const filterArr = [1, 2, 3, 4, 5];
// 三个参数:遍历项 索引 数组本身
// 配合箭头函数,返回大于3的集合
const filterArr2 = filterArr.filter((num, index, arr) => num > 3);
console.log(filterArr2)[(4, 5)];
11. Array.some
some,意思就是只有一个是真,那就返回真
const someArr = [false, true, false, true, false];
// 三个参数:遍历项 索引 数组本身
// 配合箭头函数,只要有一个为true,就返回true,一个都true都没有,就返回false
const someArr2 = someArr.some((bol, index, arr) => bol);
console.log(someArr2);
true;
12. Array.every
every 跟 some 是相反的,some 是只有一个就行,every 是要所有为真才返回真
const everyArr = [false, true, false, true, false];
// 三个参数:遍历项 索引 数组本身
// 配合箭头函数,需要所有为true,才返回true,否则返回false
const everyArr2 = everyArr.every((bol, index, arr) => bol);
console.log(everyArr2);
13. Array.reduce
第一个参数 callback 函数: pre 为上次 return 的值,next 为数组的本次遍历的项
第二个参数为初始值,也是第一个 pre
举两个例子:
// 计算 1 + 2 + 3 + 4 + 5
const reduceArr = [1, 2, 3, 4, 5];
const sum = reduceArr.reduce((pre, next) => {
return pre + next;
}, 0);
console.log(sum); // 15
// 统计元素出现个数
const nameArr = ["柯基", "sunshine_lin", "柯基", "柯基", "科比"];
const totalObj = nameArr.reduce((pre, next) => {
if (pre[next]) {
pre[next]++;
} else {
pre[next] = 1;
}
return pre;
}, {});
console.log(totalObj); // { '柯基': 3, sunshine_lin: 1, '科比': 1 }
14. 对象属性同名简写
以前同名属性需要这么写
const name = "柯基";
const age = "22";
const obj = {
name: name,
age: age,
};
console.log(obj); // { name: '柯基', age: '22' }
ES6 新增语法,只需这么写
const name = '柯基'
const age = '22'
// 属性同名可简写
const obj = {
name
age
}
console.log(obj) // { name: '柯基', age: '22' }
15. Promise
Promise,中文名为承诺,承诺在哪呢?承诺在,一旦他的状态改变,就不会再改。这里就介绍基本使用,如果想要深入理解如何使用,请看的另一篇文章看了就会,手写 Promise 原理,最通俗易懂的版本!!!
看看基本使用
成功状态
function requestData() {
// 模拟请求
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("柯基");
}, 1000);
});
}
requestData().then(
(res) => {
console.log(res); // 一秒钟后输出 '柯基'
},
(err) => {
console.log(err);
}
);
失败状态
function requestData() {
// 模拟请求
return new Promise((resolve, reject) => {
setTimeout(() => {
reject("错误");
}, 1000);
});
}
requestData().then(
(res) => {
console.log(res);
},
(err) => {
console.log(err); // 一秒钟后输出 '错误'
}
);
all 方法
接收一个 Promise 数组,数组中如有非 Promise 项,则此项当做成功
如果所有 Promise 都成功,则返回成功结果数组
如果有一个 Promise 失败,则返回这个失败结果
// 如果全都为成功
function fn(time) {
return new Promise((resolve, reject) => {
console.log(88);
setTimeout(() => {
resolve(`${time}毫秒后成功!!!`);
}, time);
});
}
Promise.all([fn(2000), fn(3000), fn(1000)]).then(
(res) => {
// 3秒后输出 [ '2000毫秒后成功!!!', '3000毫秒后成功!!!', '1000毫秒后成功!!!' ]
console.log(res);
},
(err) => {
console.log(err);
}
);
// 如果有一个失败
function fn(time, isResolve) {
return new Promise((resolve, reject) => {
setTimeout(() => {
isResolve
? resolve(`${time}毫秒后成功!!!`)
: reject(`${time}毫秒后失败!!!`);
}, time);
});
}
Promise.all([fn(2000, true), fn(3000), fn(1000, true)]).then(
(res) => {
console.log(res);
},
(err) => {
console.log(err); // 3秒后输出 '3000毫秒后失败!!!'
}
);
race 方法
接收一个 Promise 数组,数组中如有非 Promise 项,则此项当做成功
哪个 Promise 最快得到结果,就返回那个结果,无论成功失败
function fn(time, isResolve) {
return new Promise((resolve, reject) => {
setTimeout(() => {
isResolve
? resolve(`${time}毫秒后成功!!!`)
: reject(`${time}毫秒后失败!!!`);
}, time);
});
}
Promise.race([fn(2000, true), fn(3000), fn(1000)]).then(
(res) => {
console.log(res);
},
(err) => {
console.log(err); // 1秒后输出
}
);
16. class
以前使用构造函数生成对象,这么做
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function () {
console.log(this.name);
};
const kobe = new Person("科比");
kobe.sayName(); // 科比
而有了 ES6 的 class 可以这么做
class Person {
constructor(name) {
// 构造器
this.name = name;
}
sayName() {
console.log(this.name);
}
}
const kobe = new Person("科比");
kobe.sayName(); // 科比
值得一提的是,class 本质也是 function,class 是 function 的语法糖
class Person {}
console.log(typeof Person); // function
除了以上,还需要知道 class 的以下知识点
静态属性和静态方法,使用 static 定义的属性和方法只能 class 用,实例用不了
class Person {
constructor(name) {
this.name = name;
}
static age = 22;
static fn() {
console.log("哈哈");
}
}
console.log(Person.age); // 22
Person.fn(); // 哈哈
const sunshine_lin = new Person("柯基");
console.log(sunshine_lin.age); // undefined
sunshine_lin.fn(); // fn is not a function
extend 继承
class Animal {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
class Cat extends Animal {
say() {
console.log(this.name, this.age);
}
}
const cat = new Cat("ketty", 5); // 继承了Animal的构造器
cat.say(); // ketty 5
17. 解构赋值
以前想提取对象里的属性需要这么做
const obj = {
name: "柯基",
age: 22,
gender: "男",
};
const name = obj.name;
const age = obj.age;
const gender = obj.gender;
console.log(name, age, gender); // 柯基 22 男
ES6 新增了解构赋值的语法
const obj = {
name: "柯基",
age: 22,
gender: "男",
doing: {
morning: "摸鱼",
afternoon: "摸鱼",
evening: "sleep",
},
};
const { name, age, gender } = obj;
console.log(name, age, gender); // 柯基 22 男
// 解构重名
const { name: myname } = obj;
console.log(myname); // 柯基
// 嵌套解构
const {
doing: { evening },
} = obj;
console.log(evening); // sleep
也可以进行数组的解构
const arr = [1, 2, 3];
const [a, b, c] = arr;
console.log(a, b, c); // 1 2 3
// 默认赋值
const [a, b, c, d = 5] = arr;
console.log(a, b, c, d); // 1 2 3 5
// 乱序解构
const { 1: a, 0: b, 2: c } = arr;
console.log(a, b, c); // 2 1 3
18. find 和 findIndex
find:找到返回被找元素,找不到返回 undefined
findIndex:找到返回被找元素索引,找不到返回-1
const findArr = [
{ name: "科比", no: "24" },
{ name: "罗斯", no: "1" },
{ name: "利拉德", no: "0" },
];
const kobe = findArr.find(({ name }) => name === "科比");
const kobeIndex = findArr.findIndex(({ name }) => name === "科比");
console.log(kobe); // { name: '科比', no: '24' }
console.log(kobeIndex); // 0
19. for of 和 for in
一句话概括:for in 是遍历(object)键名,for of 是遍历(array)键值。
for...in
for...in 循环只遍历可枚举属性(包括它的原型链上的可枚举属性)。像 Array 和 Object 使用内置构造函数所创建的对象都会继承自 Object.prototype 和 String.prototype 的不可枚举属性,例如 String 的 indexOf() 方法或 Object 的 toString()方法。循环将遍历对象本身的所有可枚举属性,以及对象从其构造函数原型中继承的属性(更接近原型链中对象的属性覆盖原型属性)。
let obj = { a: 1, b: 2, c: 3 };
for (let key in obj) {
console.log(key);
}
// a
// b
// c
for...of
for...of 语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句
const array1 = ["a", "b", "c"];
for (const val of array1) {
console.log(val);
}
// a
// b
// c
for of 不可以遍历普通对象,想要遍历对象的属性,可以用 for in 循环, 或内建的 Object.keys()方法
for...of 与 for...in 的区别
无论是 for...in 还是 for...of 语句都是迭代一些东西。它们之间的主要区别在于它们的迭代方式。
for...in 语句以任意顺序迭代对象的可枚举属性。
for...of 语句遍历可迭代对象定义要迭代的数据。
以下示例显示了与 Array 一起使用时,for...of 循环和 for...in 循环之间的区别。
Object.prototype.objCustom = function () {};
Array.prototype.arrCustom = function () {};
let iterable = [3, 5, 7];
iterable.foo = "hello";
for (let i in iterable) {
console.log(i); // 0, 1, 2, "foo", "arrCustom", "objCustom"
}
for (let i in iterable) {
if (iterable.hasOwnProperty(i)) {
console.log(i); // 0, 1, 2, "foo"
}
}
for (let i of iterable) {
console.log(i); // logs 3, 5, 7
}
总结:for in 一般用来遍历对象的 key、for of 一般用来遍历数组的 value
20. Set 和 Map
Set
Set 的基本用法
// 可不传数组
const set1 = new Set();
set1.add(1);
set1.add(2);
console.log(set1); // Set(2) { 1, 2 }
// 也可传数组
const set2 = new Set([1, 2, 3]);
// 增加元素 使用 add
set2.add(4);
set2.add("柯基");
console.log(set2); // Set(5) { 1, 2, 3, 4, '柯基' }
// 是否含有某个元素 使用 has
console.log(set2.has(2)); // true
// 查看长度 使用 size
console.log(set2.size); // 5
// 删除元素 使用 delete
set2.delete(2);
console.log(set2); // Set(4) { 1, 3, 4, '柯基' }
Set 的不重复性
// 增加一个已有元素,则增加无效,会被自动去重
const set1 = new Set([1]);
set1.add(1);
console.log(set1); // Set(1) { 1 }
// 传入的数组中有重复项,会自动去重
const set2 = new Set([1, 2, "柯基", 3, 3, "柯基"]);
console.log(set2); // Set(4) { 1, 2, '柯基', 3 }
// Set的不重复性中,要注意引用数据类型和NaN
// 两个对象都是不用的指针,所以没法去重
const set1 = new Set([1, { name: "柯基" }, 2, { name: "柯基" }]);
console.log(set1); // Set(4) { 1, { name: '柯基' }, 2, { name: '柯基' } }
// 如果是两个对象是同一指针,则能去重
const obj = { name: "柯基" };
const set2 = new Set([1, obj, 2, obj]);
console.log(set2); // Set(3) { 1, { name: '柯基' }, 2 }
NaN !== NaN,NaN 是自身不等于自身的,但是在 Set 中他还是会被去重
const set = new Set([1, NaN, 1, NaN]);
console.log(set); // Set(2) { 1, NaN }
利用 Set 的不重复性,可以实现数组去重
const arr = [1, 2, 3, 4, 4, 5, 5, 66, 9, 1];
// Set可利用扩展运算符转为数组哦
const quchongArr = [...new Set(arr)];
console.log(quchongArr); // [1, 2, 3, 4, 5, 66, 9]
Map
Map 对比 object 最大的好处就是,key 不受类型限制
// 定义map
const map1 = new Map();
// 新增键值对 使用 set(key, value)
map1.set(true, 1);
map1.set(1, 2);
map1.set("哈哈", "嘻嘻嘻");
console.log(map1); // Map(3) { true => 1, 1 => 2, '哈哈' => '嘻嘻嘻' }
// 判断map是否含有某个key 使用 has(key)
console.log(map1.has("哈哈")); // true
// 获取map中某个key对应的value 使用 get(key)
console.log(map1.get(true)); // 2
// 删除map中某个键值对 使用 delete(key)
map1.delete("哈哈");
console.log(map1); // Map(2) { true => 1, 1 => 2 }
// 定义map,也可传入键值对数组集合
const map2 = new Map([
[true, 1],
[1, 2],
["哈哈", "嘻嘻嘻"],
]);
console.log(map2); // Map(3) { true => 1, 1 => 2, '哈哈' => '嘻嘻嘻' }
21. weakmap 和 weakset
weakSet
WeakSet 结构与 Set 类似,也是不重复的值的集合。
成员都是数组和类似数组的对象,若调用 add() 方法时传入了非数组和类似数组的对象的参数,就会抛出错误。
const b = [1, 2, [1, 2]];
new WeakSet(b); // Uncaught TypeError: Invalid value used in weak set
成员都是弱引用,可以被垃圾回收机制回收,可以用来保存 DOM 节点,不容易造成内存泄漏。
WeakSet 不可迭代,因此不能被用在 for-of 等循环中。
WeakSet 没有 size 属性。
WeakMap
WeakMap 结构与 Map 结构类似,也是用于生成键值对的集合。
只接受对象作为键名(null 除外),不接受其他类型的值作为键名
键名是弱引用,键值可以是任意的,键名所指向的对象可以被垃圾回收,此时键名是无效的
不能遍历,方法有 get、set、has、delete
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南