ECMAScript 6.0 (以下简称ES6)是JavaScript语言的下一代标准,已经在2015年6月正式发布了。它的目标,是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言
ES6既是一个历史名词,也是一个泛指,含义是5.1版以后的JavaScript的下代标准,涵盖了ES2015、ES2016、ES2017等等,而 ES2015则是正式名称,
特指该年发布的正式版本的语言标准
案例:
console.log(a)
var a = 2
输出:
undefined
Process finished with exit code 0
var关键字出现在console后却能打印undefined,这就是变量提升
以上案例等同于如下代码,变量提升
即将变量提升到前面,先声明,后赋值:
var a;
console.log(a)
a = 2
显然,在es5之前频繁使用var声明变量,需要大量考虑变量提升
的影响,因此es6引入了let和const
如用var声明一个for循环,其变量提升会导致i成为全局变量,因此无论输出数组哪个成员,其调用函数的结果都是返回i=10
//for循环
var arr = [];
for (var i = 0; i < 10; i++) {
arr[i] = function () {
return i;
}
}
console.log(arr[5]())
输出:
10
如果使用let
,则能够避免:
//for循环
var arr = [];
for (let i = 0; i < 10; i++) {
arr[i] = function () {
return i;
}
}
console.log(arr[5]())
输出:
5
let不会污染全局变量
定义一个与系统函数同名的变量,系统函数会被var变量覆盖
var RegExp = 10;
console.log(RegExp);
console.log(window.RegExp)
输出:
10
10
改用let声明:
let RegExp = 10;
console.log(RegExp);
console.log(window.RegExp)
输出:
10
ƒ RegExp() { [native code] }
const在拥有let的特性之外,还有一条自己的特性,即声明变量不可变,但声明的变量其成员属性可变
案例:
const person = {
name: "acerola"
}
const person = 1;
person.name = "zhangsan"
console.log(person)
输出:
Uncaught SyntaxError: Identifier 'person' has already been declared
{name: 'zhangsan'}
案例:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<div class="box">
div>
<script>
const box = document.querySelector('.box');
let id = 1, name = "acerola";
let htmlStr = `
-
${id}
">${name}
`
box.innerHTML = htmlStr;
script>
body>
html>
函数入参可以直接初始化值,也可以直接调用函数初始化值
function bValue() {
return 20;
}
function f(a, b = bValue(), c = 30) {
return a + b + c;
}
console.log(f(10))
输出:
60
剩余参数可以使用...
+具名参数的形式指代,替代了es5以前不太好用的arguements
function pick(obj, ...keys) {
let result = Object.create(null);
for (let i = 0; i < keys.length; i++) {
result[keys[i]] = obj[keys[i]];
}
return result;
}
let book = {
title: "es6学习",
author: 'acerola',
year: 2022
}
let bookData = pick(book, 'year', 'author');
console.log(bookData);
输出:
[Object: null prototype] { year: 2022, author: 'acerola' }
剩余运算符:把多个独立数组合并
将一个运算符分割,并将各个项作为分离的参数传给函数
const arr = [10, 20, 30, 40];
//es5做法
console.log(Math.max.apply(null,arr))
//es6做法,使用运算符分割数组
console.log(Math.max(...arr))
箭头函数
//es5
let add = function (a, b) {
return a + b;
}
//es6
let add = (a, b) => {
return a + b;
}
//更简洁的版本
let add = (a, b) => (a + b)
console.log(add(10, 20))
//es6只有一个参数时
let single = val => val
console.log(single(10));
注意事项:
扩展的对象的功能
is()
,等价于===
console.log(Object.is(1,2))
assign(), 对象合并
let obj1 = {
name: "莫",
age: 18,
family: {
dady: "爸爸",
mom: "妈妈"
}
}
let obj2 = {
name: "园",
age: 18,
sex: "女"
}
let result = Object.assign({}, obj1, obj2);
console.log(result);
对象解构:
let obj = {
a: {
name: "张园",
age: 18
},
b: [],
c: "你好世界"
}
//es5完全解构
let aName = obj.a.name;
console.log(aName)
//es6不完全解构
let {name} = obj.a
console.log(name)
数组解构:
let arr = [1,2,3,4,5]
let [a,b,c] = arr
console.log(c);
Symbol是ES6中引入的一种新的基本数据类型,用于表示一个独一无二的值。它是JavaScript中的第七种数据类型,与undefined、null、Number(数值)、String(字符串)、Boolean(布尔值)、Object(对象)并列。
const a = Symbol('s1');
console.log(a); //Symbol(s1)
尽管再创建一个Symbol(‘s1’),a和b也不相等,他们在内存中的地址是唯一的,可以使用is()验证
const a = Symbol('s1');
const b = Symbol('s1');
console.log(Object.is(a,b)); //false
只有通过引用他们自身,才能得到他们的地址,没有别的途径
const c = a;
Map 是 ES6 中新增的数据结构,Map 类似于对象,但普通对象的 key 必须是字符串或者数字
,而 Map 的 key 可以是任何数据类型
Map的操作方法:
const map = new Map();
const obj = {p: 'Hello World'};
map.set(obj, 'OK')
map.get(obj) // "OK"
map.has(obj) // true
map.delete(obj) // true
map.has(obj) // false
Map 实例的遍历方法有:
const map = new Map();
map.set('aaa', 100);
map.set('bbb', 200);
for (let key of map.keys()) {
console.log(key);
}
// "aaa"
// "bbb"
for (let value of map.values()) {
console.log(value);
}
// 100
// 200
for (let item of map.entries()) {
console.log(item[0], item[1]);
}
// aaa 100
Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用
Set的操作方法:
add(value):添加某个值,返回Set结构本身。
delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
has(value):返回一个布尔值,表示该值是否为Set的成员。
clear():清除所有成员,没有返回值
set转数组
let a = new Set([1,2,3]);
let arr = [...a];
console.log(arr)
还可以取交集并集差集
let a = new Set([1,2,3]);
let b = new Set([2,3,4]);
//并集
let union = new Set([...a,...b]);
console.log(union);//Set(4) {1, 2, 3, 4}
//交集
let intersect = new Set([...a].filter(x => b.has(x)));
console.log(intersect);//Set(2) {2, 3}
//差集
let difference = new Set([...a].filter(x => !b.has(x)));
console.log(difference);//Set(1) {1}
Iterator 是es6引入的一种新的遍历机制:
Symbol.iterator
的方法来实现;const items = ["zero", "one", "two"];
const it = items[Symbol.iterator]();
it.next();
//{value: "zero", done: false}
it.next();
//{value: "one", done: false}
it.next();
//{value: "two", done: false}
it.next();
//{value: undefined, done: true}
生成器是ES6中新增的一种函数控制、使用的方案,它可以让我们更加灵活的控制函数什么时候继续执行、暂停执行等。平时我们会编写很多的函数,这些函数终止的条件通常是返回值或者发生了异常。
生成器函数也是一个函数,但是和普通的函数有一些区别:
首先,生成器函数需要在function的后面加一个符号:*
其次,生成器函数可以通过yield关键字来控制函数的执行流程:
最后,生成器函数的返回值是一个Generator(生成器):
生成器事实上是一种特殊的迭代器,最简单的用法就是用yield把流程分段,然后使用next一段一段执行方法
案例:
function* foo() {
console.log("函数开始执行~")
const value1 = 100
console.log("第一段代码:", value1)
yield
const value2 = 200
console.log("第二段代码:", value2)
yield
const value3 = 300
console.log("第三段代码:", value3)
yield
console.log("函数执行结束~")
}
// 调用生成器函数时, 会给我们返回一个生成器对象
const generator = foo()
// 开始执行第一段代码
generator.next()
// 开始执行第二端代码
console.log("-------------")
generator.next()
generator.next()
console.log("----------")
generator.next()
同时,分段也可以有不同的参数传入,可以通过在next()加入参数向yield传递参数,这个参数作为yield的返回值,也就是可以作为下一段代码的参数使用
function* foo(num) {
console.log("函数开始执行~")
const value1 = 100 * num
console.log("第一段代码:", value1)
const n = yield value1
console.log("n的值是" + n)
const value2 = 200 * n
console.log("第二段代码:", value2)
const count = yield value2
const value3 = 300 * count
console.log("第三段代码:", value3)
yield value3
console.log("函数执行结束~")
return "123"
}
// 生成器上的next方法可以传递参数
const generator = foo(5)
console.log(generator.next())
// // 第二段代码, 第二次调用next的时候执行的
console.log(generator.next(10))
// console.log(generator.next(25))
输出:
函数开始执行~
第一段代码: 500
{ value: 500, done: false }
n的值是10
第二段代码: 2000
{ value: 2000, done: false }
使用return提前终止
function* foo(num) {
console.log("函数开始执行~")
const value1 = 100 * num
console.log("第一段代码:", value1)
const n = yield value1
console.log("n的值是" + n)
const value2 = 200 * n
console.log("第二段代码:", value2)
const count = yield value2
const value3 = 300 * count
console.log("第三段代码:", value3)
yield value3
console.log("函数执行结束~")
return "123"
}
// 生成器上的next方法可以传递参数
const generator = foo(5)
console.log(generator.next())
console.log(generator.return(15))
// // 第二段代码, 第二次调用next的时候执行的
console.log(generator.next(10))
// console.log(generator.next(25))
输出:
函数开始执行~
第一段代码: 500
{ value: 500, done: false }
{ value: 15, done: true }
{ value: undefined, done: true }
try-catch的异常抛出
function* foo() {
console.log("代码开始执行~")
const value1 = 100
try {
yield value1
} catch (error) {
console.log("捕获到异常情况:", error)
yield "abc"
}
console.log("第二段代码继续执行")
const value2 = 200
yield value2
console.log("代码执行结束~")
}
const generator = foo()
const result = generator.next()
generator.throw("error message")
// const result = generator.next()
Promise是ES6异步编程的一种解决方案(目前最先进的解决方案是async和await的搭配(ES8),但是它们是基于promise的),从语法上讲,Promise是一个对象或者说是构造函数,用来封装异步操作并可以获取其成功或失败的结果。
let pro = new Promise((resolve, reject) => {
if (Math.random() > 0.5) {
resolve("i'm resolve");
} else {
reject("i'm reject");
}
})
pro.then((res) => {
console.log(res);
}).catch((err) => {
console.log(err);
})
目标:拿到关于 狙击手 电影的描述
过程:
1.先登录
2.请求 导演信息 找到张导的id
3.请求 电影信息 找到描述
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
// 1.登录
// let myLogin = () => new Promise()
function myLogin() {
return new Promise((resolve, reject) => {
$.ajax({
type: 'get',
url: '../json/login.json',
success(res) {
resolve(res);
},
error(err) {
reject(err);
}
})
})
}
// 2.导演列表
function myDirector() {
return new Promise((resolve, reject) => {
$.ajax({
type: 'get',
url: '../json/director.json',
success(res) {
resolve(res);
},
error(err) {
reject(err);
}
})
})
}
// 3.电影信息
function myFilm(id) {
return new Promise((resolve, reject) => {
$.ajax({
type: 'get',
url: '../json/' + id + '.json',
success(res) {
resolve(res);
},
error(err) {
reject(err);
}
})
})
}
myLogin().then(res => {
return myDirector();
}).then(res => {
return myFilm(3);
}).then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
</script>
处理多个异步任务,所有任务都执行完成才能得到结果
Promise.all( [p1,p2,p3] ) .then ( (result) => {
consoleog (result)
})
并发处理多个异步任务,只要有一个任务完成就能得到结果
Promise.race ( [p1,p2,p3] ).then ( (result)=>{
console. log (result)
})
async函数是使用async关键字声明的函数。 async函数是AsyncFunction构造函数的实例, 并且其中允许使用await关键字。async和await关键字让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需刻意地链式调用promise。
Async函数是generator函数的语法糖,在generator函数的基础上添加了一些更加方便用户操作的新特性。Async函数的执行和普通函数一致,只需要一行代码即可,因为他具有内置的执行。async与await对比*与yield有更好的语义
。
async 函数中可能会有 await 表达式,async 函数执行时,如果遇到 await 就会先暂停执行 ,等到触发的异步操作完成后,恢复 async 函数的执行并返回解析值。primise写法:await关键字只在async函数内有效。如果你在async函数体之外使用它,就会抛出语法错误 SyntaxError 。
function foo() {
return Promise.resolve(1)
}
async写法:
//async函数返回一个 Promise 对象。
async function foo() {
return 1
}
项目中常见用法
async function foo(){
return await $.get("http://47.106.244.1:8099/manager/category/findAllCategory");
}
let f = foo();
// f就是获取到的后台接口的数据
某些时候,我们需要多个异步任务保证顺序执行,使用await控制:
async function getTitle(url) {
//抓取网页
let response = await fetch(url);
//提取文本
let html = await response.text();
//匹配页面标题
return html.match(/([\s\S]+)<\/title> /i)[1];
}
getTitle('https://tc39.github.io/ecma262/').then(console.log)
function getFoo() {
console.log("getFoo")
}
function getBar() {
console.log("getBar")
}
async function test() {
//异步执行
let [foo, bar] = await Promise.all([getFoo(), getBar()]);
}
跟java一毛一样,不想记录了(我是搞后端的捏)
分别暴露
export let school = 'gc';
export function teach() {
console.log("分别暴露");
};
统一暴露
let school = 'gc';
function findJob() {
console.log("统一暴露");
};
export {school, findJob};
默认暴露
export default {
school: 'ATLUCA',
change: function(){
console.log("默认暴露");
}
}
通用导入
import * as _m1 from "js/m1.js";
_m1.teach();
import * as _m2 from "js/m2.js";
_m2.findJob();
console.log(_m2.school);
import * as _m3 from "js/m3.js";
console.log(_m3);
_m3.default.change();
解构赋值
import {school, teach} from "js/m1.js";
import {school as gc, findJob} from "js/m2.js";
console.log(findJob);
import {default as _m3} from "js/m3.js";
console.log(_m3);
只针对默认暴露的导入
import _m3 from "js/m3.js";
console.log(_m3);