let
1
2
3
4
1. 变量不能重复声明
2. 块级作用域(只在代码块{}里有效)
3. 不存在变量提升
4. 不影响作用域链
const
1
2
3
4
5
6
1. 一定要赋初始值
2. 一般常量使用大写(潜规则) // 并没有
3. 不存在变量提升
4. 常量的值不能修改
5. 块级作用域(只在代码块{}里有效)
6. 对于数组和对象内的元素修改,不算做对常量的修改,不会报错

let,const 声明的变量不会和window挂钩

globalThis

可以拿到顶层对象

解构赋值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 按照一定模式从数组和对象中提取值,对变量进行赋值
// 这被称为解构赋值
1. 数组的结构
const F4 = ['a','b','c','d'];
let [e,f,g,h] = F4;

2. 对象的结构
const zhao = {
name:'a',
age:'b',
xiaoping:function(){
console.log('我可以演小品');
}
}
let {name,age,xiaopin} = zhao
let {name:a,age:b,xiaopin:c} = zhao // 使用别名
数组解构赋值
1
2
let [ , , third] = ["foo", "bar", "baz"];
third // "baz"
1
2
3
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
1
2
3
4
5
// 解构不成功
let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
1
2
3
4
5
6
7
8
9
// 不完全解构
let [x, y] = [1, 2, 3];
x // 1
y // 2

let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
1
2
3
//  Set 结构,也可以使用数组的解构赋值
let [x, y, z] = new Set(['a', 'b', 'c']);
x // "a"
1
2
3
4
5
6
// 解构赋值允许指定默认值
let [foo = true] = [];
foo // true

let [x, y = 'b'] = ['a']; // x='a', y='b'
let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'

只要某种数据结构具有 Iterator(迭代器) 接口,都可以采用数组形式的解构赋值。

对象解构赋值
1
2
3
4
5
6
7
// 对象解构赋值
let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"

let { baz } = { foo: 'aaa', bar: 'bbb' };
baz // undefined
1
2
3
4
5
6
7
8
9
10
11
// 嵌套对象
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};

let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"
1
2
3
4
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first // 1
last // 3
字符串的解构赋值
1
2
3
4
5
6
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
1
2
let {length : len} = 'hello';
len // 5
数值和布尔值的解构赋值
1
2
3
4
5
6
// 解构赋值时,如果等号右边是数值和布尔值,则会先转为对象
let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true
函数参数的解构赋值
1
2
3
4
5
function add([x, y]){
return x + y;
}

add([1, 2]); // 3
1
2
[[1, 2], [3, 4]].map(([a, b]) => a + b);
// [ 3, 7 ]
用途

交换变量的值

1
2
3
4
let x = 1;
let y = 2;

[x, y] = [y, x];

提取 JSON 数据

解构赋值对提取 JSON 对象中的数据,尤其有用。

1
2
3
4
5
6
7
8
9
10
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};

let { id, status, data: number } = jsonData;

console.log(id, status, number);
// 42, "OK", [867, 5309]

函数参数的默认值

1
2
3
4
5
6
7
8
9
10
11
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
} = {}) {
// ... do stuff
};

遍历 Map 结构

任何部署了 Iterator 接口的对象,都可以用for...of循环遍历。Map 结构原生支持 Iterator 接口,配合变量的解构赋值,获取键名和键值就非常方便。

1
2
3
4
5
6
7
8
9
const map = new Map();
map.set('first', 'hello');
map.set('second', 'world');

for (let [key, value] of map) {
console.log(key + " is " + value);
}
// first is hello
// second is world

按需导入模块的指定方法

加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。

1
const { SourceMapConsumer, SourceNode } = require("source-map");
模板字符串
1
2
3
let str = ``;  // 可以在里面直接写HTML代码 

let str = `${value}`; // 变量拼接
对象的简写
1
2
3
4
5
6
7
8
9
10
11
12
let name = 'a';
let change = function(){
console.log('我们可以改变你!');
}

const school = {
name,
change,
improve(){
console.log('我们可以提高你的技能');
}
}
箭头函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 箭头函数是用来简化函数定义语法的
let fn = function(a,b){
return a + b;
}
let fn = (a,b) => {
return a + b;
}
1. this 是静态的 this 始终指向函数声明时所在作用域下的 this 的值
2. 不能作为构造函数实例化对象
3. 不能使用 arguments 变量
4. 简写
1) 省略小括号, 当形参有且只有一个的时候
let add = n =>{}
2) 省略花括号, 当代码体只有一条语句的时候, 此时return 必须省略
而且语句的执行结果就是函数的返回值
let pow = n => n*n;

// 箭头函数适合与this无关的回调,定时器,数组的方法回调
// 箭头函数不适合与this有关的回调,事件回调,对象的方法

参数默认值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1. 形参初始值 具有默认值的参数,一般位置要靠后(潜规则)
function add(a,b,c=10){
return a + b + c;
}

2. 与解构赋值结合
function connect({host="127.0.0.1",username,password,port}){
console.log(host)
console.log(username)
console.log(password)
console.log(port)
}
connect({
host:'localhost',
username:'root',
password:'root',
port:3306
})
rest参数(剩余参数)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// ES6获取实参的方式
function date(...args){
console.log(args);
}
date('a','b','c');

// rest 参数必须要放到参数最后
function fn(a,b,...args){
console.log(a);
console.log(b);
console.log(args);
}
fn(1,2,3,4,5,6);


// 解构赋值和剩余参数配合
let arr = ['a','b','c'];
let [x,...y] = arr; // y =['b','c']
spread扩展运算符
1
2
3
4
5
6
7
// ... 扩展运算符能将数组转换为逗号分隔的参数序列
const arr = ['a','b','c'];
function fn(){
console.log(arguments);
}
fn(arr); // fn(['a','b','c'])
fn(...arr); // fn('a','b','c')
扩展运算符应用
1
2
3
4
5
6
7
8
9
10
11
12
13
// 数组的合并
const a = ['x','y'];
const b = ['z','h'];
const ab = [...a,...b]; // ['x','y','z','h'];
const a.push(...b);

// 数组的克隆
const a = ['x','y','z'];
const b = [...a]; // 浅拷贝

// 将伪数组转为真正的数组
const divs = document.querySelectorAll('div');
const divArr = [...divs]; // arguments
Array的扩展方法
Array.from
1
2
3
4
5
6
7
8
// 将类数组对象转换为真正数组
let arr = Array.from(类数组);
1、该类数组对象必须具有length属性,用于指定数组的长度。如果没有length属性,那么转换后的数组是一个空数组。
2、该类数组对象的属性名必须为数值型或字符串型的数字,如果不是 结果是长度为4,元素均为undefined的数组
ps: 该类数组对象的属性名可以加引号,也可以不加引号

let arr = Array.from(类数组,item => item + 1);
Array.from还可以接受第二个参数,用来对每个元素进行处理
Array.find()
1
2
3
4
5
6
7
// 用于查找满足条件的第一个元素的值,无则返回 undefined
const array1 = [5, 12, 8, 130, 44];

const found = array1.find(element => element > 10);

console.log(found);
// expected output: 12
Array.findIndex()
1
2
3
4
5
6
7
// 找到数组中满足条件的第一个元素,然后把该项的索引号返回,无则返回 -1
const array1 = [5, 12, 8, 130, 44];

const isLargeNumber = (element) => element > 13;

console.log(array1.findIndex(isLargeNumber));
// expected output: 3
Array.includes()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 判断数组是否包含某个值 精确匹配
const array1 = [1, 2, 3];

console.log(array1.includes(2));
// expected output: true

const pets = ['cat', 'dog', 'bat'];

console.log(pets.includes('cat'));
// expected output: true

console.log(pets.includes('at'));
// expected output: false

String 的扩展方法
startsWith方法和endWith方法
1
2
str.startsWith(''); // 判断字符串是否以 开头 返回布尔值
str.endsWith(''); // 判断字符串是否以 结尾
repeat方法
1
str.repeat(n); // 把字符串重复n次返回
Set数据结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const s = new Set([1,2,3]); // 没有重复的项 可以用来给数组去重 ...s
s.size // 存储了几个值

s.add() // 向set结构中添加值
s.delete() // 删除值
s.has() // 判断是否有这个值
s.clear() // 清空值

s.forEach(item=>{
console.log(item);
});

for(let item of s){
console.log(item)
}

其他(了解)

Object.freeze(obj)

方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象。

Symbol基本使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 新的原始数据类型Symbol,表示独一无二的值,是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型
1. Symbol 的值是唯一的,用来解决命名冲突的问题
2. Symbol 值不能与其他数据进行运算
3. Symbol 定义的对象属性不能使用for...in 循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名

let s = Symbol(); // 创建Symbol
let s1 = Symbol('a'); // 里面只是标识 s1 != s2
let s2 = Symbol('a');

let s3 = Symbol.for('a'); // s3 == s4
let s4 = Symbol.for('a');

// USONB you are so niubility
// u undefined
// s string symbol
// o object
// n null number
// b boolean
Symbol创建对象属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 向对象中添加方法 up down
let game = {}

// 声明一个对象
let methods = {
up:Symbol(),
down:Symbol()
};
game[methods.up] = function(){
console.log('我可以改变形状');
}
game[methods.up] = function(){
console.log('我可以快速下降');
}

let youxi = {
name:'狼人杀',
[Symbol('say')]:function(){
console.log('我可以发言')
};
[Symbol('zibao')]:function(){
console.log('我可以自爆')
};
}

Symbol内置属性

11个(在特定场景下的表现)

迭代器
1
2
3
4
5
6
7
8
9
10
// 迭代器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口,就可以完成遍历操作。

1. ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费
2. 原生js具备iterator接口的数据(可用for of遍历)
Array Arguments Set Map String TypedArray NodeList

const arr = ['a','b','c','d'];
for(let v of arr){
console.log(v);
} // for in 是键名 for of 是键值
迭代器自定义遍历对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 声明一个对象
const banji = {
name:"终极一班",
stus:[
'小明',
'小红',
'小李',
'小赵'
],
[Symbol.iterator](){
// 索引变量
let index = 0;
//
let _this = this;
return {
next:function(){
if(index < _this.stus.length){
const result = {value:_this.stus[index],done:false};
// 下标自增
index++;
// 返回结果
return result;
}else{
return {value:undefined,done:true};
}
}
};
}
}

// 遍历这个对象
for(let v of banji){
console.log(v);
}
生成器函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 生成器其实就是一个特殊的函数
// yield 函数代码的分隔符
function * gen(){
console.log(111);
yield '一只没有耳朵';
console.log(222);
yield '一只没有眼睛';
console.log(333);
yield '真奇怪';
console.log(444);
}
let iterator = gen();
console.log(iterator.next()); // 执行里面的一段代码
console.log(iterator.next('ccc')); // 作为第二段yield执行的返回参数
console.log(iterator.next());
console.log(iterator.next());

//遍历
for(let v of gen()){
console.log(v);
}
生成器函数实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function one(){
setTimeout(()=>{
console.log(111);
iterator.next();
},1000)
}

function two(){
setTimeout(()=>{
console.log(222);
iterator.next();
},2000)
}

function three(){
setTimeout(()=>{
console.log(333);
iterator.next();
},3000)
}

function * gen(){
yield one();
yield two();
yield three();
}

let iterator = gen();
iterator.next();
实例化Promise对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const p = new Promise(function(resolve,reject){
setTimeout(function(){
let data = '数据库中的用户数据';
resolve(data); // 调用then第一个函数

let err = '数据读取失败';
reject(err); // 调用then第二个函数
},1000);
})

p.then(function(value){
console.log(value);
},function(reason){
console.log(reason);
})
Promise读取文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const p = new Promise(function(resolve,reject){
fs.readFile("./resources/为学.md",(err,data)=>{
// 判断如果失败
if(err) reject(err);
// 如果成功
resolve(data);
});
});

p.then(function(value){
console.log(value.toString());
},function(reason){
console.log("读取失败!!");
});
Map
1
2
3
4
5
6
7
8
9
Map数据结构.类似于对象,也是键值对的集合,但是键的范围不限于字符串
let m = new Map();

m.size // 返回元素个数
m.set('键','值') // 增加一个新元素,返回当前Map
m.get('键') // 返回键名对象的键值
m.has('') // 检测Map中是否包含
m.delete('键')
m.clear() // 清空集合,返回undefined
class 类
1
2
3
4
5
6
7
8
9
10
11
class Phone{
constructor(brand,price){
this.brand = brand;
this.price = pricel
}
call(){
console.log('我可以打电话!')
}
}

let onePlus = new Phone('1+',1999)
static
1
2
3
4
5
6
7
8
9
10
11
12
13
static 标记的就是静态成员

class Phone {
// 静态属性
static name = '手机';
static change(){
console.log('我可以改变世界');
}
}

let nokia = new Phone();
console.log(nokia.name); // undefined
console.log(Phone.name); // 手机
类继承
1
2
3
4
5
class Son extends Father{
constructor(a,b){
super(a,b); // Father.call(this,a,b);
}
}
get和set
1
2
3
4
5
6
7
8
9
10
11
12
13
class Phone{
get price(){
console.log('我被读取了');
return 'iloveyou';
}
set price(newVal){
console.log('价格属性被修改了');
}
}
// 实例化对象
let s = new Phone();
console.log(s.price); // 我被读取了
s.price = 'free'; // 价格属性被修改了
数值扩展
1
2
3
4
5
6
7
8
0. Number.EPSILONJavaScript 表示的最小精度
1. 二进制和八进制
2. Number.isFinite 检测一个数值是否为有限数
3. Number.isNaN 检测一个数值是否为NaN
4. Number.parseInt Number.parseFloat字符串转整数
5. Number.isInteger 判断一个数是否为整数
6. Math.trunc 将数字的小数部分抹掉
7. Math.sign 判断一个数到底为正数 负数 还是零
对象方法扩展
1
2
3
1. Object.is 判断两个值是否完全相等
2. Object.assign 对象的合并
3. Object.setPrototypeOf 设置原型对象 Object getPrototypeOf
模块化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
1. 防止命名冲突
2. 代码复用
3. 高维护性

ES6之前的模块化规范有:
1. CommonJS => NodeJSBrowserify
2. AMD => requireJS
3. CMD => seaJS

export 用于规定模块的对外接口
import 用于输入其他模块提供的功能

m1.js
export let school = '';
export function teach(){}

<script type="module">
// 引入 m1.js 模块内容
import * as m1 from "m1.js";
</script>


// 统一暴露
export{school,teach}

// 默认暴露
export default{
school:'',
change:function(){}
}


1. 通用的导入方式
import * as m1 from "m1.js";
2. 解构赋值形式
import {school,teach} from "m1.js";
import {school as guigu,teach} from "m2.js";
import {default as m3} from "m3.js";
3.简便形式 针对默认暴露
import m3 from "m3.js";


// 使用模块化的方式
app.js
import * as m1 from "m1.js";

<script src="app.js" type="module"></script>
babel对ES6模块化代码转换
1
2
3
1. 安装工具 babel-cli babel-preset-env browserify(webpack)
npx babel src/js -d dist/js --presets=babel-preset-env // 局部使用转换
npx browserify dist/js/app.js -o dist/bundle.js // 打包
使用jquery
1
2
npm i jquery
import $ from 'jquery'
**
1
2 ** 10 // Math.pow(2,10)
async
1
2
3
4
5
6
async function fn(){
return new Promise((resolve,reject)=>{
// resolve('成功的数据');
reject('失败的错误');
})
}
ES8对象方法扩展
1
2
Object.keys(); // 获取键
Object.entries(); // 获取值
ES9对象展开
1
2
...剩余参数
...展开
命名捕获分组
1
2
3
4
5
6
7
8
9
10
11
12
let str = '<a href="http://www.atguigu.com">尚硅谷</a>'
const reg = /<a href="(.*)">(.*)</a>/;
const result = reg.exec(str);
// result[0] <a href="http://www.atguigu.com">尚硅谷</a>
// result[1] http://www.atguigu.com
// result[2] 尚硅谷

const reg = /<a href="(?<url>.*)">(?<text>.*)</a>/;
const result = reg.exec(str);

result.groups.url // http://www.atguigu.com
result.groups.text // 尚硅谷
正则扩展-反向断言
1
2
3
4
5
6
let str = 'JS5211314你知道么555啦啦啦';
// 正向断言
const reg = /\d+(?=啦)/; // 555

// 反向断言
const reg = /(?<=么)\d+/; // 555
正则扩展-dotAll模式
1
2
3
4
// dot . 元字符

const reg = /<li>\s+<a>(.*?)</a>\s+<p>(.*?)<\/p>/;
const reg = /<li>.*?<a>(.*?)</a>.*?<p>(.*?)<\/p>/gs;
ES10
1
2
3
4
5
6
Object.fromEntries	// 二维数组转为对象
.trimStart() // 清除字符串左侧空白
.trimEnd() // 清除字符串右侧空白

.flat() // 将多维数组转换为低位数组
.flatMap() // 两个的结合
私有属性
1
2
3
4
class Person{
#name:'张三', // 私有属性 只能在Class里面使用
age:18
}
matchAll
1
正则批量提取
可选链操作符
1
?. // 和三元表达式差不多
大整形
1
2
let n = 521n;
BigInt(123);
globalThis
1
始终指向全局对象