变量声明
let
: 块级作用域(即花括号范围内)丶不存在变量提升丶不允许重复声明丶不影响作用域链
const
: 块级作用域丶常量(不能改变变量引用,引用对象内部可修改)丶需赋初值丶一般用大写
解构赋值
允许按照一定模式从数组和对象中提取值,对变量进行赋值
1.数组
const ARRAY = ['Tom','Jerry']
let [cat,mouse] = ARRAY;//解构赋值
console.log(cat); //Tom
console.log(mouse); //Jerry
2.对象
const cat = {
name: 'Tom',
skill(){
console.log('catch the mouse')
}
}
let {name,skill} = cat;//解构赋值
console.log(name);//Tom
skill();//catch the mouse
模板字符串
新的声明字符串的方式反引号:``
//可以直接出现换行符
let str = `Tom
Jerry`;
//变量拼接
let name = 'Tom'
let concat = `${name} and Jerry`;
console.log(concat) //Tom and Jerry
对象简化写法
1. 在大括号里面直接写入变量和函数
let name = 'Tom'
let from = function(){
console.log('Tom and jerry')
}
//在大括号里面直接写入变量和函数
const info = {
name,
from,
simple(){ //简化写法
console.log('eq from')
}
}
箭头函数
- 箭头函数,this始终指向函数声明所在作用域下的this的值
- 不能作为构造函数实例化对象
- 不能使用arguments变量
let fn = function(a,b){
console.log(a+b);
console.log(this.name); //Jerry
}
//箭头函数,this始终指向函数声明所在作用域下的this的值
let fns = (a,b) =>{
console.log(a+b);
console.log(this.name) //Tom
}
window.name = 'Tom';
let mouse = {
name: "Jerry"
}
fn.call(mouse,1,2);
fns.call(mouse,3,4);
//不能作为构造函数实例化对象
let Cat = (name) => {
this.name =name;
}
let Tom = new Cat('Tom'); //报错,无法实例化对象
//不能使用arguments变量
let fn = () => {
console.log(arguments);//报错
}
fn();
函数参数默认值
可以与解构赋值结合
//函数形参设置默认值
let add = (a,b = 10) => {
return a + b;
}
console.log(add(1,2)); //3
console.log(add(1)) //11
//使用解构赋值传参
function info({name,type}){
console.log(name); //Tom
console.log(type); //cat
}
info({
name: 'Tom',
type: 'cat'
});
rest参数: 即可变参数
let fn = (...args) => {
console.log(args[0]); //1
console.log(args[1]); //2
}
fn(1,2)
扩展运算符[…]
可以将
数组
转换为逗号分隔的参数序列
const arr = [1,2,3];
let fn = function(){
console.log(arguments) //参数等价与fn(1,2,3)
}
fn(...arr);
fn(1,2,3);
//合并数组
const arr1 = [1,2,3]
const arr2 = [4,5,6]
const arr3 = [...arr1,...arr2] //合并数组
console.log(arr3) //[1,2,3,4,5,6]
Symbol
//创建Symbol对象
let s = Symbol()
console.log(typeof s);//symbol
//比较
let s2 = Symbol('S');
let s3 = Symbol('S');
console.log(s2 === s3); //false
//比较
let s4 = Symbol.for('S');
let s5 = Symbol.for('S');
console.log(s4 === s5) //true
迭代器(Iterator)
具备iterator接口的类型数据(可以用for of遍历)
ES6 默认的 Iterator 接口部署在数据结构的Symbol.iterator属性,即一个数据结构只要具有Symbol.iterator属性,就可以认为是“可遍历的”(iterable)
Array
丶Arguments
丶Set
丶Map
丶String
丶TypedArray
丶NodeList
let arr = [1,2,3,4,5];
//使用for of遍历
for(let a of arr)
console.log(a);//1,2,3,4,5
//自定义迭代器
const option = {
name: 'Cartoon',
arr:[
'Tom',
'Jerry',
'Nemo',
'Simba'
],
[Symbol.iterator](){
let i = 0;
return {
next: () => {
return {value:this.arr[i++],done:this.arr.length === i - 1}
}
}
}
}
for(let s of option){
console.log(s); //Tom Jerry Nemo Simba
}
生成器
ES6提供的一种异步编程解决方案,其实就是一个特殊的函数
//生成器函数异步编程,纯回调的特殊函数,可以分段执行,通过迭代器遍历
function * it(){
yield 'a';
yield 'b';
yield 'c';
}
let iterator = it();
//可以分段执行
console.log(iterator.next()) //{value: 'a', done: false}
console.log(iterator.next()) //{value: 'b', done: false}
console.log(iterator.next()) //{value: 'c', done: false}
for(let c of it()){
console.log(c) //a //b //c
}
传参
function * it(arg){
console.log(arg); //a
let one = yield 11;
console.log(one); //b
let two = yield 22;
console.log(two); //c
}
let iterator = it('a');
iterator.next();
iterator.next('b');
iterator.next('c');
实现定时器
function one(){
setTimeout(() => {
console.log(1);
it.next();
},1000)
}
function tow(){
setTimeout(() => {
console.log(2);
it.next();
},1000)
}
function three(){
setTimeout(() => {
console.log(3);
it.next()
},1000)
}
function * gen(){
yield one();
yield tow();
yield three();
}
let it = gen();
it.next(); //1 //2 //3
Promise
使用
const p = new Promise(function(resolve,reject){
let data = "success";
let error = "error";
setTimeout(function (){
//resolve(data);//成功返回
reject(error);//失败返回
},1000);
});
//调用promise的then方法
p.then(function(value){
console.log(value); //success
},function(reason){
console.log(reason);//error
})
通过
Promise
封装AJAX
//通过Promise封装ajax
const ajax = ({method,url}) => {
return new Promise((resolve,reject) => {
const xhr = new XMLHttpRequest();
//开启
xhr.open(method,url);
//发送
xhr.send();
//处理响应
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300)
resolve(xhr.response)
else
reject(xhr.status);
}
}
})
}
//使用
ajax({
method: "GET",
url: "https://localhost/api/v3/api-docs/bioland"
}).then(value => {
console.log(value);
},
reason => {
console.log(reason);
}
)
链式调用: Promise的then方法返回值会封装为一个Promise对象
//链式调用: Promise的then方法会返回一个Promise对象
const p = new Promise((resolve, reject) => {
resolve("success");
//reject("error");
})
p.then(value => {
console.log(value); //success
return 'v: ' + value;
},reason => {
console.log(reason); //error
return "r: " + reason;
}).then(value => {
console.log(value); //v: success;
},reason => {
console.log(reason); //r: error
})
catch方法: 失败的回调: 即reject方法的回调
//catch方法: 失败的回调: 即reject方法的回调
let p = new Promise((resolve,reject) => {
//resolve("success");//成功
reject("error");//失败
})
p.then(value => {
//成功的回调
console.log("t: " + value); //t: success
}).catch(reason => {
//失败的回调
console.log("c: " + reason); //c: error
})
集合
Set
: 不重复集合,实现了iterator接口
/**
//方法
size: 返回集合元素的个数
add: 向集合中添加一个元素
delete: 删除元素,返回boolean值
has: 检测集合中是否包含某个元素,返回boolean值
*/
let set = new Set([3,4,2,3]);
//实现了iterator可以使用for-of遍历
for(let s of set) console.log(s) // 3,4,2
set.add(1);//向集合中添加元素1
for(let s of set) console.log(s); //3,4,2,1
console.log(set.has(3));//true
set.delete(3);//删除集合中的元素3
for(let s of set) console.log(s) //4,2,1
console.log(set.has(3));//false
console.log(set.size)//3
set.clear();//清空集合
console.log(set.size)//0
Map
: k-v键值对集合,也实现了iterator接口
/**
//方法
size: 返回Map的元素个数
set: 增加一个新元素,返回当前Map
get: 返回键名对象的值
has: 检测Map中是否包含某个元素
clear: 清空集合,返回undefined
*/
//map集合
let map = new Map();
map.set(1,{name:"Tom"})
map.set("array",[1,2,3])
map.set("function",() => {console.log("function")})
for(let e of map) console.log(e)
//[1, {…}]
//['array', Array(3)]
//['function', ƒ]
class 类
class
基本
//class
//1: ES5方式
function People(name,gender){
this.name = name;
this.gender = gender;
}
People.prototype.toString = function(){
console.log("name:" + this.name + " gender:" + this.gender)
}
//实例化对象
let p = new People("Tom","male")
p.toString();
//2: ES6 class方式
class User{
constructor(name,gender) {
this.name = name;
this.gender = gender;
}
toString(){
console.log("name:" + this.name + " gender:" + this.gender);
}
}
let u = new User("Jerry","male");
u.toString();
静态成员: 属于函数,不属于实例化对象
//静态成员: 只属于函数,不属于实例化对象
class People{
static name = 'Jerry';
static toStr(){
console.log('name: ' + this.name)
}
}
//实例化对象
let p = new People()
People.toStr(); //属于函数: name: Jerry
p.toStr(); //不属于实例化对象: 报错
类继承
//继承
class Base{
constructor(name) {
this.name = name;
}
toStr(){
console.log("name: " + this.name)
}
}
class BaseImpl extends Base{
constructor(name,gender) {
super(name);
this.gender = gender;
}
hello(){
console.log("Hello");
}
}
let impl = new BaseImpl("Tom","male");
impl.toStr(); //name: Tom
impl.hello(); //Hello
重写: 子类声明和父类同名方法
//重写: 子类声明和父类同名方法
class Base{
constructor(name) {
this.name = name;
}
toStr(){
console.log("name: " + this.name)
}
}
class BaseImpl extends Base{
constructor(name,gender) {
super(name);
this.gender = gender;
}
//重写父类方法
toStr(){
console.log("name: " + this.name + " gender:" + this.gender)
}
}
let impl = new BaseImpl("Jerry","male");
impl.toStr(); //name: Jerry gender:male
getter 和 setter方法
//getter 和 setter方法
class People{
get name(){
return this._name;
}
set name(name){
this._name = name;
}
toStr(){
console.log("name:" + this._name);
}
}
let p = new People();
p.name = 'Jerry';
p.toStr(); //name:Jerry
p.name = 'Tom';
p.toStr(); //name:Tom
数值扩展
// Number.EPSILON 是javascript表示的最小精度
//可用于判断小数相等
console.log(Number.EPSILON) //2.220446049250313e-16
function equals(a,b){
//取差绝对值与最小精度对比
return (Math.abs(a-b) < Number.EPSILON)
}
console.log(0.1 + 0.2 === 0.3) //false
console.log(equals(0.1+0.2,0.3)) //true
//二进制: 0b开始, 八进制: 0o开始, 十六进制: 0x开始
console.log(0b10)//2
console.log(0o10)//8
console.log(10)//10
console.log(0x10)//16
//Number.isFinite 检测一个数值是否为有限数
//Infinity : 无限数
console.log(Number.isFinite(100))//true
console.log(Number.isFinite(Infinity))//false
//Number.isNaN 检测一个数值是否为NaN
console.log(Number.isNaN(123)); //false
//Number.parseInt , Number.parseFloat 字符串转整数
console.log(Number.parseInt("10.24ab"));//10
console.log(Number.parseFloat("10.24ab"));//10.24
//Number.isInteger 判断一个数是否为整数
console.log(Number.isInteger(4));// true
console.log(Number.isInteger(4.4));// false
//Math.trunc 抹掉小数部分
console.log(Math.trunc(3.4))//3
//Math.sign 判断一个数为正=1,负=-1,零=0
console.log(Math.sign(100))//1
console.log(Math.sign(-100))//-1
console.log(Math.sign(0))//0
对象方法扩展
//Object.is() 判断两个值是否完全相等
console.log(Object.is(120,120)); //true
console.log(Object.is(NaN,NaN)); //true;
console.log(NaN === NaN); //fasle;
//Object.assign() 对象合并,同属性名会被后面替换,否则就合并
const master = {
host: 'localhost',
port: '3306',
username: 'root',
password: 'root',
charset: 'UTF-8'
}
const slave = {
host: '127.0.0.1',
port: '1521',
username: 'admin',
password: 'admin',
driver: 'o'
}
console.log(Object.assign(slave,master));
//{host: 'localhost', port: '3306', username: 'root', password: 'root', driver: 'o',charset: "UTF-8"}
//Object.setProtoTypeOf() 设置原型对象
//Object.getProtoTypeOf() 获取原型对象
const school = {
name: 'school'
}
const country = {
name: 'CN'
}
Object.setPrototypeOf(school,country);
console.log(Object.getPrototypeOf(school).name); //CN
模块化
export
暴露接口,import
导入
1. 分别暴露
1.1
a.js
//export 暴露接口
export let name = 'Tom';
export function hello(){
console.log("hello")
}
1.2 在其他文件中导入
<script type="module">
//1.通用导入方式
import * as a from "/js/a.js"
console.log(a.name);
a.hello();
//2.解构赋值方式导入: 可以用as设置别名
import {name as n,hello} from "/js/a.js"
console.log(n)
hello()
</script>
2. 统一暴露
2.1
b.js
let name = 'Tom';
function hello(){
console.log('hello');
}
//统一暴露
export {name,hello}
2.2 在其他文件中导入
<script type="module">
import * as b from "/js/b.js";
console.log(b.name);
b.hello()
</script>
3.默认暴露
3.1
c.js
//默认暴露
export default {
name: 'Tom',
hello: function(){
console.log('hello');
}
}
3.2 在其他文件中导入
<script type="module">
//1.通用导入方式
import * as c from "/js/c.js";
console.log(c.default.name);
c.default.hello();
//2.解构赋值方式: 默认暴露导入必须通过as设置别名
import {default as dc} from "/js/c.js";
console.log(dc.name);
dc.hello();
//3.简便形式: 只针对默认暴露
import sdc from "/js/c.js";
console.log(sdc.name);
sdc.hello();
</script>
4. 浏览器对模块化导入的支持
可以使用一个
js
文件作为入口文件,在里面导入所需模然后使用,最后在页面引入这个入口文件js
4.1
app.js
: 入口js文件,引入所需模块并使用
//入口文件
import * as a from "./a.js";
import * as b from "./b.js";
import * as c from "./c.js";
//使用
console.log(a.name);
console.log(b.name);
console.log(c.default.name);
a.hello();
b.hello();
c.default.hello();
4.2 在页面引入入口文件
app.js
//引入
<script src="./js/app.js" type="module"></script>
ES7新特性
Array.prototype.includes和**
幂运算
//数组的includes方法,检测数组是否包含某个元素
const arr = ['a','b','c']
console.log(arr.includes('c'))
console.log(arr.indexOf('c') > 0) //旧版本实现方式
// ** 幂运算
console.log(2 ** 10); //1024
console.log(Math.pow(2,10))//1024 //旧版本实现方式
ES8新特性
1. async 和 await
asayc作为一个关键字放到函数前面,这样普通函数就变为了异步函数
async函数配合await关键字使用(阻塞代码往下执行)
是异步方法,但是阻塞式的同步代码编写方式
: Promise使用then函数进行链式调用,一直点点点,是一种从左向右的横向写法;async/await从上到下,顺序执行,就像写同步代码一样,更符合代码编写习惯async/await是对Promise的优化
: async/await是基于Promise的,是进一步的一种优化,不过在写代码时,Promise本身的API出现得很少,很接近同步代码的写法async函数返回值为promise对象
promise对象的结果由async函数执行的返回值决定
await必须写在async函数中
await右侧的表达式一般为promise对象
await返回的是promise成功的值
await的promise失败了,就会抛出异常,需要通过try…catch捕获处理
async
函数
//async函数
async function fn(){
//返回字符串
//return 'Tom'; //1.字符串,返回结果为一个成功的promise对象
//return; //2.空,返回结果为一个成功的promise对象
//throw new Error("error"); //3.抛出错误,返回结果为一个失败的promise对象
return new Promise((resolve,reject) => {
//resolve("success");
reject("error");
}) //4.promise对象,直接返回
}
const result = fn();
result.then(value => console.log(value))
.catch(reason => console.log(reason))
//Tom //1
//undefined //2
//Error: error //3
//success //4
//error //4
await
函数
const p = new Promise((resolve,reject) =>{
resolve("success");
})
async function fn(){
let result = await p;
console.log(result);//替换掉promise的链式调用写法变成顺序调用,更符合编程习惯
}
fn()
2. 对象方法扩展
Object.keys
,Object.values
和Object.entries
: 类比java中Map集合的keys,values,和entrySetObject.getOwnPropertyDescriptors
: 对象结构属性描述
const obj = {
name: 'Tom',
arr: [1,2,3]
}
console.log(Object.keys(obj)) //['name', 'arr']
console.log(Object.values(obj)) //['Tom', Array(3)]
console.log(Object.entries(obj))//即[[keys数组],[values数组]]
console.log(Object.getOwnPropertyDescriptors(obj))
ES9新特性
扩展运算符和rest参数
rest参数
(...obj)
会将多余不配的参数放入obj中function fn({name,...obj}){ console.log(name) //Tom console.log(obj) //{num: 1, arr: Array(3), str: 'cat'} } fn({ name: 'Tom', num: 1, arr: [1,2,3], str: 'cat' })
扩展运算符
...
: 会拆开对象将其属性放入一个对象中取const a = { name: 'Tom' } const b = { arr: [1,2] } const c = { num: 3 } console.log({...a,...b,...c}) //{name: 'Tom', arr: Array(2), num: 3}
正则扩展
命名捕获分组
let url = '<a href="http://brysong.com">Bryson</a>'
const reg = /<a href="(.*)">(.*)<\/a>/;
const result = reg.exec(url);
console.log(result); //["<a href=\"http://brysong.com\">Bryson</a>","http://brysong.com","Bryson",...]
console.log(result[1])//http://brysong.com
console.log(result[2])//Bryson
//?<名字> : 分组并设置名称
let url1 = '<a href="http://brysong.com">Bryson</a>'
const reg1 = /<a href="(?<u>.*)">(?<n>.*)<\/a>/;
const result1 = reg1.exec(url1);
console.log(result1) //[groups: {u: 'http://brysong.com', n: 'Bryson'},...]
console.log(result1.groups.u)//http://brysong.com
console.log(result1.groups.n)//Bryson
断言
//正向断言 ?=
//反向断言 ?<=
let str = '123XXX前999后XXX结尾';
//正向断言
const reg = /\d+(?=后)/; //匹配 数字+`后`字的形式的数字内容
console.log(reg.exec(str)[0]) //999
//反向断言
const reg1= /(?<=前)\d+/;//匹配`前`+数字形式的数字内容
console.log(reg1.exec(str)[0])
dotAll模式
.
表示匹配任意的单个字符,但是行终止符除外,即以下四个U+000A 换行符(
\n
)U+000D 回车符(
\r
)U+2028 行分隔符(line separator)
U+2029 段分隔符(paragraph separator)
dotAll模式则表示匹配一切字符,引入新的修饰符
s
: (dotAll模式),以前有i
: (ignore)忽略大小写,g
: (global)全局匹配等
console.log(/mazey.happy/.test('mazey\nhappy')); // false
console.log(/mazey.happy/s.test('mazey\nhappy')); // true
ES10新特性
Object.fromEntries
: 可以将二维数组转为对象Object.entries
: 将对象转为二维数组ES8
字符串扩展方法
trimStart
: 清除字符串首部空白trimEnd
: 清除字符串尾部空白
数组扩展方法
flat
: 多维数组降维flatMap
: flat和map操作结合,如果map返回结果是多维数组,则降维返回
//flat const arr = [1,2,[3,4]]; console.log(arr.flat())//[1, 2, 3, 4] const arr1 = [1,[2,[3,[4]]]]; console.log(arr1.flat()) //[1, 2, [3,[4]]] console.log(arr1.flat(2))//降维两层: [1, 2, 3, [4]] console.log(arr1.flat(3))//降维3层: [1, 2, 3, 4] //flatMap: 相当于flat+map 操作结合,如果map返回结果是多维数组,则降维返回 const arr2 = [1,2,3,4]; console.log(arr2.flatMap(e => e * 10)) //[10, 20, 30, 40] console.log(arr2.map(e => [e * 10]))//[[10], [20], [30], [40]] console.log(arr2.flatMap(e => [e * 10])) //[10, 20, 30, 40] console.log(arr2.map(e => [[e * 10]]))//[[[10]], [[20]], [[30]], [[40]]] console.log(arr2.flatMap(e => [[e * 10]])) //[[10], [20], [30], [40]] console.log(arr2.flatMap(e => [[e * 10]]).flatMap(e => e * 10))//[100, 200, 300, 400]
Symbol.prototype.description
: Symbol对象描述
ES11新特性
私有属性:
#属性名
class Person{ name; #age; //只能在类内部操作 constructor(name,age) { this.name = name; this.#age = age; } info(){ console.log("name: " + this.name + " age: " + this.#age); } } const p = new Person('Tom',10); console.log(p.name)//Tom //console.log(p.#age)//报错,类外部无法获取私有属性 p.info() //name: Tom age: 10
Promise.allSettled
: 方法返回一个在所有给定的 promise 都已经fulfilled
或rejected
后的promise
,并带有一个对象数组,对象数组每个对象表示对应的 promise 结果String.prototype.matchAll
: 方法返回一个包含所有匹配正则表达式的结果及其分组捕获组的迭代器可选链操作符
?.
: 存在的话再去读取后续属性(以前.xxx)如果不存在读取会报错function fn(config){ //常规读取(需要判断对象是否存在,存在才能读取,直接读取会报错) const name = config && config.user && config.user.name; //使用可选链操作符,存在才会读取,不存在直接返回undefined const name1 = config?.user?.name; console.log(name); console.log(name1); } fn({user: undefined}) //undefined //undefined fn({user:{ name: 'Tom' }}) //Tom //Tom
动态import
d.js
function hello(){ console.log("hello"); } export {hello}
其他文件动态import导入使用
<script type="module"> //动态import导入 import('./js/d.js').then(module => { module.hello();//hello }) </script>
BigInt
: 进行更大数值运算//n结尾表示BigInt类型 let n = 520n; console.log(typeof n); //bigint //普通整数转BigInt let v = 12; console.log(BigInt(v)) //12n //更大数值运算 let max = Number.MAX_SAFE_INTEGER; console.log(max++); //9007199254740991 console.log(max++); //9007199254740992 console.log(max++); //9007199254740992 错误,无法再计算 //使用BigInt正常计算 let big = BigInt(max); console.log(big); //9007199254740992n console.log(big += BigInt(1)); //9007199254740993n console.log(big += BigInt(1)); //9007199254740994n
globalThis
: 旨在通过定义一个标准的全局属性来整合日益分散的访问全局对象的方法,浏览器中默认指向window
对象,编写可在多种环境下工作的可移植 JS 代码是很困难的。每个宿主环境都有稍微不同的对象模型。因此,要访问全局对象,需要在不同的 JS 环境中使用不同的语法。
随着
globalThis
属性的引入,访问全局对象将变得更加简单,并且不再需要检测代码运行的环境