第一章:ES6语法
第一节:ES6的概念
ES 的全称是 ECMAScript , 它是由 ECMA 国际标准化组织,制定的一项脚本语言的标准化规范。
ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 等等,而 ES2015 则是正式名称,特指该年发布的正式版本的语言标准。
第二节:为什么使用ES6
每一次标准的诞生都意味着语言的完善,功能的加强。JavaScript语言本身也有一些令人不满意的地方。
- 变量提升特性增加了程序运行时的不可预测性
- 语法过于松散,实现相同的功能,不同的人可能会写出不同的代码
第三节:新增let变量
1.3.1 let
let声明的变量只在所处于的块级有效。
var b=2;//全局变量
if(1==1){
let a=1;
console.log("块内a值是:",a);//1
console.log("块内b值是:",b);//2
}
console.log("a值是:",a);//ReferenceError: a is not defined.
console.log("b值是:",b);//2
1.3.2 For循环使用let变量
举例1:
for(let i=1;i<=10;i++){
console.log(i);//正常打印
}
console.log(i);// ReferenceError: i is not defined
举例2:
for (let i = 0; i < 3; i++) {//父作用域
let i = 'a'; //子作用域
console.log(i);
}
1.3.3 let不存在变量提升
var 变量 可以在变量声明前使用,多少有点奇怪,为了纠正这个现象,let改变了这个语法。
console.log(a);//undefined
var a=1;
console.log(b);
let b=2;////ReferenceError: a is not defined.
总结: var声明的变量会在作用域内变量提升,但赋值不会提升,所以是undefined。而let的声明的变量不会提升,所以抛出语法错误。
1.3.4 let暂时性死区
只要块级作用域内存在let命令,它所声明的变量就“绑定”这个区域,不再受外部的影响。
var a = 1;
if (true) {
a = 2;// ReferenceError
let a = 1;
}
总结:
在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”。该变量在声明之前使用都属于“暂时性死区“。
1.3.5 不允许重复声明
// 报错
function func() {
let a = 10;
var a = 1;
}
function func() {
let a = 10;
let a = 1;
}
function func(arg) {
let arg;
}
func()
// 不报错
function func(arg) {
{
let arg;
}
}
func()
1.3.6 let案例
var arr = [];
for (var i = 0; i < 3; i++) {
arr[i] = function () {
console.log(i);
}
}
当用var和let时下方三个值是?
arr[0]();
arr[1]();
arr[2]();
提示:var声明的变量是全局作用域,每次for循环都会产生一个块级作用域,每个块级作用域都声明了一个let变量,互不干扰。
1.3.7 总结
-- let 关键字用来声明块级变量。
-- 特点就是在{}声明具有块级作用域,var变量无此特点。
-- 防止循环变量编程全局变量。
-- let 关键词无变量提升。
-- let 关键词有暂时性死区的特点。{先声明后使用}
第四节:新增const变量
声明常量,常量就是值(内存地址)不能变化的量。
1.4.1 const 具有块级作用域
var a=1;
if(true){
const a=2;
console.log(a);//2
}
1.4.2 const 声明常量必须赋值
if(true){
const a;
console.log(a);// Missing initializer in const declaration
}
1.4.3 常量赋值不能修改
if(true){
const a=2;
a=3;
console.log(a);// Missing initializer in const declaration
}
const person = {};
person.name ="张三";
person.age=18;
person = {};//报错
总结:对象的本身是可变的,所以可以添加属性,但是地址不可改变。
1.4.4 let、const、var 的区别
- 使用 var 声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象
- 使用 let 声明的变量,其作用域为该语句所在的代码块内,不存在变量提升
- 使用 const 声明的是常量,在后面出现的代码中不能再修改该常量的值
- 使用let,const的声明的变量不属性顶层对象,返回undefined。
第五节:解构赋值
ES6中允许从数组中提取值,按照对应位置,对变量赋值,对象也可以实现解构。
1.5.1 数组解构
举例1:
let[a,b,c] = [1,2,3];
console.log(a);//1
console.log(b);//2
console.log(c);//3
本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
举例2:
let [a, [[b], c]] = [1, [[2], 3]];
a// 1
b// 2
c// 3
举例3:
let[a,,c] = [1,2,3]; #省略变量
console.log(a);//1
举例4:
let[a,...c] = [1,2,3];//合并运算符可以展开数组也可合并数组
console.log(c);//[2, 3]
console.log(...c);//2 3
举例5:
let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
举例6:
let [x,y='2'] = ['a',undefined];
console.log(y);//如果没有定义,可以用默认值
说明:ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效。
1.5.2对象解构
-- 根据key解构
let person = {name:"小帅",age:18};
let {name,age,height} = person;
console.log(name);//小帅
console.log(age);//18
console.log(height);//undefined
说明:对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值,否则解构失败就是undefined。
//根据key更改变量名
let { realname: myname,height=173 } = { realname: '张三', age: 18};
console.log(Myname);//张三
console.log(Myage)//18
console.log(realname)//realname is not defined
console.log(height)//当属性没有的时候支持默认值
说明:对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
1.5.3 字符串解构
let [a,b,c] = "hello";
console.log(a);//h
console.log(b);//2
console.log(c);//l
1.5.4 解构应用
1:变量值交换
let a=1;
let b=2;
[a,b] = [b,a];
console.log(a);
2:函数返回多个值
function myfun(){
return [2,3,4];
}
let [a,b,c] = myfun();
3:函数参数的定义
function myfun([a,b,c]){
console.log(a);
}
myfun([4,5,6]);
第六节:箭头函数
ES6中新增的定义函数的方式。
1.6.1 基础语法
语法:() =>{} // ():函数 =>:必须的语法,指向代码块 {}:代码块
Const myFun = () => { } ;//把函数赋值给myFun
举例:
//原js写法
function myFun(k,v){
return k + v;
}
//es6 写法
const myFun1 = (k,v) => {
return k+v;
}
console.log(myFun(1,2));
console.log(myFun1(10,20));
1.6.2 省略写法
如果形参或者代码块只有一句可以简写:
Const myFun = (k) => {return k+1;} 简写:
Const myFun = k => k +1;
1.6.3 this全局函数
var name = "global this";
function globalTest() {
console.log(this);//window
console.log(this.name);//global this
This.name = “global this change”;
}
globalTest();
说明:globalTest()是全局性的方法,属于全局性调用,因此this就代表全局对象window。
1.6.4 对象方法里的this
如果函数作为对象的方法调用,this指向的是这个上级对象,即调用方法的对象。
const person = {
name:"张三",
age:18,
say:function(){
console.log(this.name);// 张三 这时候的this是person的对象
}
}
person.say();
1.6.5 构造函数对象的this
var name = "golbal";
function person(name,age){
this.name = name,
this.age = age,
this.say = function (){
console.log(this.name,this.age);
}
}
const person1 = new person("张三",18);
const person2 = new person("小帅",19);
person1.say();
person2.say();
说明:构造函数中的this指向新创建的对象本身。
1.6.6 apply/call调用时的this
定义:call(thisObj,Object) 调用一个对象的一个方法,以另一个对象替换当前对象。
说明:call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。
const person1 = {name:"张三",age:18};
var name = "G_张三",age = "G_18";
function myfun1(){
console.log(this.name,this.age);
}
myfun1();//对象是Windows
myfun1.call(person1);//对象改变为person1
说明:两者的区别,myfun.call(person,18,29); myfun.apply(person,[18,29]);
1.6.7 箭头函数中this
箭头函数不绑定this关键字,箭头函数中的this,指向的是函数定义位置的上下文this。
箭头函数中的this指向是它所定义(声明)的位置,可以简单理解成,定义箭头函数中的作用域的this指向谁,它就指向谁。
const obj = { name: '张三'}
function fn () {
console.log(this);//this 指向 是obj对象
return () => {
console.log(this);//this 指向 的是箭头函数定义的位置,那么这个箭头函数定义在fn里面,而这个fn指向是的obj对象,所以这个this也指向是obj对象
}
}
const resFn = fn.call(obj); //{ name: '张三'}
resFn();//{ name: '张三'}
1.6.8 箭头函数应用
练习1:单击按钮2s后改变按钮文字:按钮被点击,在单击按钮改变文字:点击被取消。
var flag = false;
let clickbtn = document.querySelector("#clickbtn");
clickbtn.addEventListener("click",function(){
flag = !flag;
setTimeout(() => {
if(flag){
this.value = '按钮被点击'
this.className='hover' //更换样式
}else{
this.value = '点击被取消'
this.className=’’//更换样式
}
},2000);
})
练习2:输出数组,让数组里面每个值扩大3-5倍。
练习3:判断数组,每个元素是奇数还是偶数。
第七节:剩余参数
剩余参数语法允许我们将一个不定数量的参数表示为一个数组,不定参数定义方式,这种方式很方便的去声明不知道参数情况下的一个函数。
1.7.1 传不定参数
function myfun(k1,...k2){
console.log(k1);//10
console.log(k2);//(2) [20, 30]
}
myfun(10,20,30);
1.7.2 剩余参数与解构使用
案例1:
let numarr = [1,2,3];
let [num1,...numx] = numarr;
console.log(num1);//1
console.log(numx);// [2,3]
案例2:
function connect({host,port,username,password}){
console.log(host);
}
connect({
host:"127.0.0.1",
port:"3306",
username:"root",
password:"root"
})
第二章:ES6内置对象
第一节:array的扩展方法
2.1.1 展开语法
...扩展运算符可以将数组或者对象转为用逗号分隔的参数序列。
举例1:
let ary = [1, 2, 3];
console.log(...ary); // 1 2 3,相当于下面的代码
console.log(1,2,3);
举例2:
合并数组
let arr1 = [1, 2, 3];
let arr2 = [4,5,6];
// let arr3 = [...arr1,...arr2];
arr1.push(...arr2);
console.log(arr1);
举例3:
将类数组转为数组
let eledivs = document.getElementsByTagName('div');
eledivs = [...eledivs];//Array.prototype.slice.call(eledivs);
2.1.2 Array.from()方法
将伪数组或可遍历对象转换为真正的数组。
举例1:
Array.from('12345') // [1,2,3,4,5]
举例2:
let arr1 = {
1:'a',
2:'b',
'length':3
}
console.log(Array.from(arr1));//undefined ,a,b.
举例3:还可转类数组,map,set对象等。
2.1.3 array.find() 方法
find() 方法返回通过测试(函数内判断)的数组的第一个元素的值。
举例1:
let arr1 = [1,2,3,2];
let target = arr1.find( item => item==2);
console.log(target);//2,如果未找到,返回undefined
举例2:
let person = [
{name:"张三",age:16},
{name:"李四",age:17},
{name:"王五",age:18},
]
let target = person.find((item,index)=>{return item.name=='张三'});
console.log(target.name);
2.1.4 array.findindex()方法
定义:用于找出第一个符合条件的数组成员的位置,如果没有找到返回-1。
let ary = [1, 5, 10, 15];
let index = ary.findIndex((item, index) => item > 9);
console.log(index); // 2
2.1.5 array.includes()方法
定义:判断某个数组是否包含给定的值,返回布尔值。
let ary = [1, 5, 10, 15];
console.log(ary.includes(5));//ture
第二节:String的扩展方法
2.2.1 模板字符串定义
ES6新增的创建字符串的方式,使用反引号定义 let name = `张三`;
2.2.2 模板字符串解析变量
-- 反引号定义模板
let name = '张三';
let sayHello = `hello,my name is ${name}`; // hello, my name is Lee
-- 模板字符串换行
let result = {
name: '张三',
age: 28,
sex: '男'
}
let html = ` <div>
<span>${result.name}</span>
<span>${result.age}</span>
<span>${result.sex}</span>
</div> `;
console.log(html);
-- 模板字符串中调用函数
const sayName = function () {
return '张三';
};
let greet = `${sayName('张三')} ,你好!`;
console.log(greet);
2.2.3 startsWith()、endsWith()
- startsWith():表示参数字符串是否在原字符串的头部,返回布尔值
- endsWith():表示参数字符串是否在原字符串的尾部,返回布尔值
举例:
let str = 'Hello world!';
str.startsWith('Hello'); // true
str.endsWith('!'); // true
str.endsWith('xx'); // false
2.2.4 repeat()
repeat方法表示将原字符串重复n次,返回一个新字符串。
console.log('hello'.repeat(2));//hellohello
第三节 Set 数据结构
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
定义:const s = new Set();
初始化:const set = new Set([1, 2, 3, 4, 4]);//{1, 2, 3, 4}
2.3.1 实例方法
const s = new Set();
s.add(1).add(2);//添加值
s.delete(2);//删除值,不是索引
console.log(s.has(2));//set有无2,有返回true
console.log(s.clear());//清除所有的值
2.3.2数据遍历
forEach方法,用于对每个成员执行某种操作,没有返回值。
s.forEach( v => console.log(v));
第四节 Map 数据结构
概念:JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制,map的键不限于字符串,对象也可以称为键。
let info = {age:18,height:173};
let person = new Map();
person.set(info,'人的详细信息');
person.set('name','张三'); //添加值
console.log(person.get("name")); //得到值
console.log(person.size);//获得map的个数
person.delete('name');//删除元素
console.log(person.size);
console.log(person.get(info));//对象作为键
//person.clear();//清空所有的值
console.log(person);
Person.keys()//获得所有的键
Person.values()//获得所有的值
Person.size//获得键的数量
//遍历
for(let v of person){
console.log(v);
}
第四节 DOM classList 属性
2.4.1 add(class1,class2)
添加一个类,如果类不存在则不添加。
document.getElementById("mydiv").classList.add("demodiv","demodiv1");
2.4.2 contains(class)
判断元素中是否存在某个类。存在返回true,反之返回false。
let x = document.getElementById("mydiv").classList.contains("demodiv");
console.log(x);
2.4.3 item(index)
返回元素中索引值对应的类名。索引值从 0 开始。 如果索引值在区间范围外则返回 *null*
document.getElementById("mydiv").classList.item(0);
.2.4.4 remove(class1,class2)
移除元素中一个或多个类名,移除不存在的类名,不会报错。
let mydom = document.getElementById("mydiv");
mydom.classList.add("demodiv");
console.log(mydom.classList.contains("demodiv")); // true
mydom.classList.remove("demodiv");
console.log(mydom.classList.contains("demodiv"));//false
2.4.5 toggle(*class,* true\|false)
在元素中切换类名。 第一个参数为要在元素中移除的类名,并返回 false。 如果该类名不存在则会在元素中添加类名,并返回 true。 第二个是可选参数,是个布尔值用于设置元素是否强制添加或移除类,不管该类名是否存在。
let mydom = document.getElementById("mydiv");
mydom.classList.toggle("demodiv");
console.log(mydom.classList.contains("demodiv"));
mydom.classList.toggle("demodiv");
console.log(mydom.classList.contains("demodiv"));
第五节 Array对象常用方法
2.5.1 Array map()
map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。

举例1:
let arr = [2,3,4,5,6];
let newarr = arr.map(v=>v+2)
console.log(arr );//2,3,4,5,6
console.log(newarr);//4,5,6,7,8
举例2:
let arr = [2,3,4,5,6];
function ckarr(v){
return v+2;
}
console.log(arr.map(ckarr));
总结:
-- map() 不会对空数组进行检测。
-- map() 不会改变原始数组。
2.5.2 Array filter()
filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。

let arr = [2,3,4,5,6];
function ckarr(v){
return v>3; //返回符合条件的值
}
console.log(arr.filter(ckarr));
总结:
-- filter() 不会对空数组进行检测。
-- filter() 不会改变原始数组。
2.5.3 reduce() 方法
reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
-- 对于空数组是不会执行回调函数的。

var arr = [1, 2, 3, 4];
var sum = arr.reduce(function(total, currentValue, index, arr) {
return total + currentValue;
},10);
console.log(sum);
2.5.4 Array.of()
负责把一堆文本或者变量转换成数组。
// let arr = Array.of(3,4,5,6);
// console.log(arr);
let arr =Array.of('张三','小帅','小红');
console.log(arr);
let a=1,b=2,c=3;
let arr =Array.of(a,b,c);
console.log(arr);
2.5.4 fill()
语法:array.fill(value, start, end)
Value:必需。填充的值。
Start:可选。开始填充位置。
End:可选。停止填充位置 (默认为 array.length)。
举例:
let arr=[0,1,2,3,4,5,6,7,8,9];
arr.fill('x',2,5);
console.log(arr); //[0, 1, "x", "x", "x", 5, 6, 7, 8, 9]
2.5.5 数组遍历
For..of遍历
for(let item of person){
console.log(item);
}
说明:item是当前遍历的值
For..in遍历
for(let index in person){
console.log(index);
}
说明:index 是当前遍历的索引
forEach()
方法用于调用数组的每个元素,并将元素传递给回调函数。

person.forEach(function(value,index){
console.log(value,index);
})
2.5.6 in用法
判断对象 是否 数组的属性。
判断对象 是否 是 对象 的属性。
数组判断:
let person = ['张三','小帅',"王五",4];
console.log(4 in person);//false
console.log(3 in person);// true
对象判断:
let person = {
"name":"张三",
"age":19
}
console.log("age" in person);
2.5.6 some用法
some() 方法用于检测数组中的元素是否满足指定条件(函数提供);
var ages = [3, 10, 1, 1];
var flag = ages.some(v=> v>2);
console.log(flag);
总结:
-- 如果有一个元素满足条件,则表达式返回*true* , 剩余的元素不会再执行检测。
-- some() 不会对空数组进行检测。
-- some() 不会改变原始数组。
-- 如果找不到返回flase。
2.5.7 join方法
join() 方法用于把数组中的所有元素放入一个字符串。
语法:array.join(separator);
var arr = new Array(3);
arr[0] = "George";
arr[1] = "John";
arr[2] = "Thomas";
let arrq = arr.join(',');
console.log(arrq);console.log(typeof arrq);
- 对象
2.6.1 ES6 创建对象
ES6允许把声明的变量直接赋值给对象。
举例:
let name='张三';
let age=19;
let person = {name,age};
console.log(person);
2.6.2 Key值构建
当键值非前台定义好,需要从后台拉取,可以用Key构建。
举例:
let key="name";
let obj = {
[key]:'web'
}
console.log(obj);
2.6.3 自定义对象方法
对象方法就是把对象中的属性,用匿名函数的形式编程方法(之前就有)。
var person={
say:function(a,b){
return a+b;
}
}
console.log(person.say(4,5));
2.6.4 Object.assign( )合并对象
举例:
let a = {name:"张三"},b = {age:19};
let c = Object.assign(a,b);
console.log(c);
//展开运算符方式
let d = {...a,...b};
console.log(d);
2.6.5 Symbol
ES6引入了一种新的原始数据类型 Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,是一种类似于字符串的数据类型。
Symbol 创建
特性1:Symbol 数据类型的特点是唯一性,即使是用同一个变量生成的值也不相等。
let a = Symbol("a");//a为symbol的描述
let b = Symbol("a");
console.log(a===b);//false
第二种创建方式(可以创建唯一的值)
let s3 = Symbol.for('bb');
let s4 = Symbol.for('bb');
console.log(s3===s4) //true`
特性2:Symbol 数据类型不能与其他数据类型运算。
Let c = a+100;//Cannot convert a Symbol value to a number
特性3:Symbol定义的对象属性不能使用for…in循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名。
Symbol内置值
ES6除了定义自己使用的Symbol值以外,还提供了11个内置的Symbol值,指向语言内部使用的方法。
1:Symbol.hasInstance
当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法。
class Person{
static [Symbol.hasInstance](param){
console.log('param----', param)
console.log('检测类型')
}
}
let o = {}
console.log(o instanceof Person)
2:Symbol.isConcatSpreadable
对象的Symbol.isConcatSpreadable属性等于一个bool值,表示该对象用于Array.prototype()时,是否可以展开。
const arr1 = [1,2,3]
const arr2 = [4,5,6]
arr2[Symbol.isConcatSpreadable] = false // arr2不可展开
const arr = arr1.concat(arr2)
console.log(arr) // [1,2,3,[4,5,6]]
3:Symbol.unscopables
该对象指定了使用with关键字时,哪些属性会被with环境排除。
const object1 = {
property1: 42
};
object1[Symbol.unscopables] = {
property1: true
};
with (object1) {
console.log(property1);
// expected output: Error: property1 is not defined
}
4:Symbol.match
当执行str.match(myObject)时,如果该属性存在,会调用它,返回该方法的返回值
5:Symbol.replace
当该对象被str.replace(myObject)方法调用时,会返回该方法的返回值
6:Symbol.search
当该对象被str.search(myObject)方法调用时,会返回该方法的返回值
7:Symbol.split
当该对象被str.split(myObject)方法调用时,会返回该方法的返回值
8:Symbol.iterator
对象进行for ... of循环时,会调用Symbol.iterator方法,返回该对象的默认遍历器
9:Symbol.toPrimitive
该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值
10:Symbol.toStringTag
在该对象上调用toString方法时,返回该方法的返回值
11:Symbol.species
创建衍生对象时,会使用该属性
Symbol使用场景
给对象添加方法,不予对象属性冲突。
let person = {
name:'张三',
age:18
}
let methods = {
say:Symbol(),
paly:Symbol()
}
person[methods.say] = function(){
console.log("say hi");
}
person[methods.paly] = function(){
console.log("paly game");
}
console.log(Object.getOwnPropertySymbols(person)); // 获得所有的[Symbol()]
console.log(Reflect.ownKeys(person));//返回所有属性key
// 调用
person[methods.say]();
let demo = Object.getOwnPropertySymbols(person);
person[demo[0]]();
迭代器
定义:迭代器(lterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署lterator接口,就可以完成遍历操作,ES6新增遍历方式for...of。
原生具备lterator接口的数据有:Array,Arguments,Set,Map,String,NodeList。
原理:创建一个指针对象,指向数据结构的起始位置,第一次调用==next()==方法,指针自动指向数据结构第一个成员,接下来不断调用next(),指针一直往后移动,直到指向最后一个成员,没调用next()返回一个包含value和done属性的对象.
举例:
const person = ['张三','李四','王五'];
console.log(person);
let myiterator = person[Symbol.iterator]();
console.log(myiterator.next());//{value: "张三", done: false}
console.log(myiterator.next());//{value: "李四", done: false}
console.log(myiterator.next());//{value: "王五", done: false}
console.log(myiterator.next());//{value: undefined, done: true}
迭代器使用场景
定义:遵循面向对象思想,自定义遍历数据。
let Person = {
kings : "四大天王",
realname:['刘德华','张学友','黎明','郭富城'],
[Symbol.iterator](){
let i=0;
let _this=this;
return {
next:function(){
if(i<_this.realname.length){
let res = {value: _this.realname[i], done: false}
i++
return res;
}else{
return {value: undefined, done: true}
}
}
}
}
}
for(let v of Person){
console.log(v);
}
2.6.6 生成器
生成器定义
生成器本身是一个特殊的函数,生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数不同。
代码:
function * cook(){
console.log('我被执行了');
yield '盛米';
yield '淘米';
yield '煮米';
}
let cook_step = cook();
cook_step;//这样不会被执行。
生成器调用
执行生成器函数,返回的是一个迭代器对象,通过iterator.next()调用执行函数内语句,用yield 的分隔符让语句分段执行。
代码1:next();
function * cook(){
let i=1;
console.log('我被执行了'+i+'次');
yield '盛米';
i++;
console.log('我被执行了'+i+'次');
yield '淘米';
i++;
console.log('我被执行了'+i+'次');
yield '煮米';
i++;
console.log('我被执行了'+i+'次');
}
let cook_step = cook();
console.log(cook_step.next());{value: "盛米", done: false}
console.log(cook_step.next());{value: "淘米", done: false}
console.log(cook_step.next());{value: "煮米", done: false}
console.log(cook_step.next());{value: undefined, done: true}
代码2:for...of
可以打印出yield返回的结果。
for(let v of cook_step){
console.log(v);
}
生成器传参
概念:next('BBB')传入的参数作为上一个next方法的返回值。
代码:
function * cook(person){
console.log(person);
let a1 = yield '盛米';
console.log(a1);
let a2 = yield '淘米';
console.log(a2);
let a3 = yield '煮米';
console.log(a3);
}
let cook_step = cook('张三');
cook_step.next();//张三
cook_step.next('a1');//a1
cook_step.next('a2');//a2
cook_step.next('a3');//a3
生成器的应用
题目:盛米用了2s,淘米用了2s,煮米用了2s。最后输出如果是张三就输出
盛了:2碗,淘米次数:3次,煮米工具:电饭锅。其他人就是1碗,1次,未知工具
代码:
function step_1(){
setTimeout(function(){
console.log('盛米end');
cook_zs.next();
},1000);
}
function step_2(){
setTimeout(function(){
console.log('淘米end');
cook_zs.next();
},1000);
}
function step_3(){
setTimeout(function(){
console.log('煮米end');
cook_zs.next();
},1000);
}
function * cook(){
yield step_1();
yield step_2();
yield step_3();
}
let cook_zs = cook();
cook_zs.next();
代码2:
function step_1(person){
setTimeout(function(){
let temp = '盛米:' + ((person=='张三'?3:1) + '碗');
cook_zs.next(temp);
},1000);
}
function step_2(person){
setTimeout(function(){
let temp = '淘米:' + ((person=='张三'?2:1) + '次');
cook_zs.next(temp);
},1000);
}
function step_3(person){
setTimeout(function(){
let temp = '工具:' + (person=='张三'?'电饭锅':'其他');
cook_zs.next(temp);
},1000);
}
function * cook(person){
console.log("做饭厨师:" + person);
let a1 = yield step_1(person);
console.log(a1);
let a2 = yield step_2(person);
console.log(a2);
let a3 = yield step_3(person);
console.log(a3);
}
let cook_zs = cook('张三');
cook_zs.next();
- export和import
ES6 模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。
7.1 export基本使用
export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。
// 写法一
export let a = 1;
// 写法二
var a = 1;
export {a};
// 写法三
var n = 1;
export {n as a};
<script type="module">
import * as m from '../module.js';
console.log(m.a);
Let {a,b} = m;//接收多个变量
</script>
7.2 export统一导出
let a = 1;
function change(){
console.log('我改变了');
}
export {a,change}
7.3 export 默认导出
export default命令的本质是将后面的值,赋给default变量。
const person = {name:'张三'}
export default person;
import a from '../module.js'; //简写方式
console.log(a);
7.4 export和export default的区别
两者的相同点与区别点如下:
1、两者均可用于导出常量、函数、文件、模块;
2、在一个文件中可以多次使用export,但是export default只能用一次;
3、通过export输出的,在import导入时需要使用{},export default不需要;
- export与export default不可同时使用;
7.4 import基础用法
基础
使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块。
import {a as aa,b} from '../module.js';//as重命名变量
console.log(aa);
只读
import命令输入的变量都是只读的,因为它的本质是输入接口。也就是说,不允许在加载模块的脚本里面,改写接口。
aa = {}; // Syntax Error : 'a' is read-only;
7.5 模块引入的第二个方式
<script src='../app.js' type="module"></script>
第八节 Promise
1:定义
Promise是异步编程的一种解决方案,可以替代传统的解决方案--回调函数和事件。ES6统一了用法,并原生提供了Promise对象。作为对象,Promise有一下两个特点:
- 对象的状态不受外界影响。
Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
- 一旦状态改变了就不会在变,也就是说任何时候Promise都只有一种状态。
Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。
2:三种状态
Pending状态(进行中)Fulfilled状态(已成功) Rejected状态(已失败)
一旦发生改变就只有一种状态:Pending -> Fulfilled Pending -> Rejected。
3:基本用法
Resolve,用来接收完成状态,reject用来接收失败的状态。
var promise = new Promise(function(resolve,reject){
let flag = true;
if(flag){
resolve('状态:执行成功!');
}else{
reject("状态:执行失败!");
}
})
promise.then(function(resolve){
console.log(resolve);
},function(reject){
console.log(reject);
})
说明:then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。这两个函数都是可选的,不一定要提供。它们都接受Promise对象传出的值作为参数。
4:模拟异步
模拟未来即将发生的代码。
function timeout(ms){
return new Promise(function(relove,reject){
setTimeout(()=>{
console.log('程序'+ms +'毫秒后打印!');
},ms);
})
}
timeout(3000);
5:执行步骤
function timeout(ms){
console.log(2);
return new Promise(function(relove,reject){
setTimeout(()=>{
console.log(3);
relove(4);
},ms);
})
}
console.log(1);
let res = timeout(3000);
res.then(relove=>{
console.log(relove);
})
说明:Promise 新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以4最后输出。
6:封装ajax
const sendajax = function(url){
return new Promise(function(reslove,reject){
//创建对象
const o = new XMLHttpRequest();
o.open('GET',url);//初始化
o.send();//发送
//接收状态 绑定事件
o.onreadystatechange = function(){
if(o.readyState === 4){ //标识请求发送结束
if(o.status>=200 && o.status<300){//
reslove(o.response);
}else{
reject(o.status);//失败的状态码
}
}
}
})
}
let test = sendajax('https://api.apiopen.top/getJoke');
test.then(function(value){
console.log(value);
},function(reason){
console.log(reason);
})
7:Proimse.prototype.then
Promise 实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。它的作用是为 Promise 实例添加状态改变时的回调函数。then方法的第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数,参数可选。
then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。根据这一特性我们可以采用链式方法:
function sayhi(){
let mypromise = new Promise(function(resolve,reject){
let str = "hello world";
resolve(str);
})
return mypromise;
}
sayhi().then(function(value){
console.log(value);
return value;
}).then(function(value){
console.log(value+2);
return value;
})
8:Promise.prototype.catch()
Promise.prototype.catch()方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。
let myfun = function(){
let mypromise = new Promise(function(resolve,reject){
reject('错误');
})
return mypromise;
}
//发生错误的时捕获
myfun().catch(function(e){
console.error(e);
});
第九节 Class的用法
JavaScript 语言中,生成实例对象的传统方法是通过构造函数,ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
9.1 类的定义
class Person{
constructor(username,password) {
this.username = username;
this.password = password;
}
getstr(){
console.log("用户名:"+this.username + "密码:" + this.password);
}
}
const p1 = new Person('123456','789012');
p1.getstr();
说明:使用class关键词 声明类,constructor为构造方法,一个类必须有constructor()方法,如果没有显式定义,一个空的constructor()方法会被默认添加,this关键字则代表实例对象,getstr()为普通方法,不要用“function”,getstr()存在 prototype上。
p1.constructor === p1.prototype.constructor // true
9.2 static静态成员
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
class Person{
static realname = '手机';
static play(){
console.log("会玩游戏!");
}
}
const p1 = new Person();
console.log(p1.realname);//undefined
Person.play();//会玩游戏
9.3 继承extends
Class 可以通过extends关键字实现继承,让子类继承父类的属性和方法。
ES6 规定,子类必须在constructor()方法中调用super(),否则就会报错。
除了私有属性,父类的所有属性和方法,都会被子类继承,其中包括静态方法。私有属性前面加#;
class Student{
constructor(realname,age) {
this.realname = realname;
this.age = age;
}
play(str){
console.log("我会玩" + str) ;
}
jump(){
console.log("我可以跳高");
}
}
class ItStudent extends Student{
constructor(realname,age,major) {
super(realname,age);
this.major = major;
}
program(type){
console.log("我会编程的语言是:"+type);
}
}
const It1 = new ItStudent("张三",13,'大数据');
console.log(It1.realname);
9.4 调用私有属性
#p=1;
getp(){
return this.#p;
}
9.5 重写方法
直接重写父类同样名称的方法。
9.6 getter和setter
Getter对动态属性就行一个封装,setter做判断满足条件赋值。
class demo{
get flag(){
return 'getter';
}
set flag(value){
console.log("setter方法执行了");
}
}
const demo1 = new demo();
demo1.flag=1;
练习:实现求平均数的类,set用来设置值,get用来取值。
第三章:ES7
第一节 Array.prototype.includes
定义:用来检测数组中是否包含某个元素,返回布尔类型值。
const person = ['张三','李四','王五'];
console.log(person.includes("张三") );//true
第二节 幂运算**
在ES7中引入指数操作符**,用来实现幂运算,功能与Math.pow结果相同。
console.log(2**10) // 1024
第四章:ES8
第一节:async 和 await
async和await两种语法结合可以让异步代码像同步代码一样。
4.1.1 async 函数
async 是一个修饰符,async 定义的函数会默认的返回一个Promise对象resolve的值,因此对async函数可以直接进行then操作,返回的值即为then方法的传入函数。
举例:
async function fn(){
//1.如果返回的是一个非Promise的对象,则fn()返回的结果就是成功状态的Promise对象,值为返回值
//2.如果返回的是一个Promise对象,则fn()返回的结果与内部Promise对象的结果一致
//3.如果返回的是抛出错误,则fn()返回的就是失败状态的Promise对象
return new Promise((resolve,reject)=>{
resolve('成功的数据');
});
}
const result = fn();
result.then(
value=>{
console.log(value) //成功的数据
},reason=>{
console.log(reason) //失败的数据
})
4.1.2 await表达式
它也是一个修饰符,await 关键字 只能放在 async 函数内部, await关键字的作用 就是获取 Promise中返回的内容, 获取的是Promise函数中resolve或者reject的值。
1:await必须放在async函数中
2:await右侧的表达式一般为promise对象
3:await可以返回的是右侧promise成功的值
4:await右侧的promise如果失败了,就会抛出异常,需要通过try…catch捕获处理
举例:
const bbb = function(){ return 'string'}
async function funAsy() {
const a = await 1
const b = await new Promise((resolve, reject)=>{
setTimeout(function(){
console.log(‘b执行了’)
resolve('time')
}, 3000)
})
const c = await bbb()
console.log(a, b, c)
}
funAsy() // 运行结果是 3秒钟之后 ,输出 1, time , string
如果Promise 不加await 会立刻输出 1 string,3秒后输入:”b执行了”。
4.1.3 ajax综合应用
function sendAjax(url) {
return new Promise((resolve, reject) => {
//创建对象
const x = new XMLHttpRequest();
//初始化
x.open('GET', url);
//发送
x.send();
//时间绑定
x.onreadystatechange = () => { //onreadystatechange 回调后的状态
if (x.readyState === 4) {
if (x.status >= 200 && x.status < 300) {
//成功
resolve(x.response)
} else {
//失败
reject(x.status)
}
}
}
// readyState 状态说明:
// 0:代理创建,未调用open()方法;
// 1:open方法已调用
// 2:send()方法一调用
// 3:LOADING 数据下载中 responseText已经有值
// 4:下载操作完成
// status:返回网页状态,200~299都是正常状态,404 not found。
})
}
//async 与 await 测试
async function main() {
let result = await sendAjax("https://api.apiopen.top/getJoke")
mytext = JSON.parse(result);
console.log(mytext.result[0].sid,mytext.result[0].text);
}
main()
- 对象扩展方法
const school = { name:'课工场', cities:['北京','上海','深圳'], xueke:['前端','Java','大数据','运维'] };
4.2.1 Object.keys
获得所有的键:console.log(Object.keys(school));
4.2.2 Object.values
获取所有的值:console.log(Object.values(school));
4.2.3 entries,用来创建map
console.log(Object.entries(school));
console.log(new Map(Object.entries(school)))
4.2.4 Object.getOwnPropertyDescriptors
//对象属性的描述对象
console.log(Object.getOwnPropertyDescriptor(school))
4.2.5 Object.create()
第一个参数是放在新对象的原型上的,第二个参数是放在新对象的实例上。
const obj = Object.create(null,{
name:{
value:'课工场',
//属性特性
writable:true,
configurable:true,
enumerable:true,
}
})
第五章:ES9
第一节:rest参数
rest参数用于获取函数的实参,用来代替arguments。
举例1:
function person(...p){//数组
p.forEach(v => console.log(v));
}
person("张三",18);
举例2:
function connect({host,port,...user}){
console.log(host);
console.log(port);
console.log(user);
}
connect({
host:'127.0.0.1',
port:3306,
username:'root',
password:'root',
type:'master'
})
注意:
1:rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。
function f(a, ...b, c) { ... } // 报错
2:函数的length属性,不包括 rest 参数。
(function(a) {}).length // 1
(function(...a) {}).length // 0
(function(a, ...b) {}).length // 1
第二节:扩展运算符
扩展运算符可以看做是 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列。
举例1:数组合并
console.log(...[1, 2, 3]) // 1 2 3
console.log(1, ...[2, 3, 4], 5) //1 2 3 4 5
举例2:rest结合使用
function person(...p){
console.log(...p);
}
person("张三",18);
举例3:
function sum(a,b){
console.log(a+b);
}
let nums = [4,3];
sum(...nums);
第五章:ES10
第一节:对象扩展方法
JavaScript中的Object.fromEntries()方法是标准的内置对象,用于将键值对列表转换为对象。此方法返回一个新对象,其属性由iterable的条目确定。
语法:Object.fromEntries( iterable )
参数:此方法接受单个参数iterable,该参数包含可迭代对象,例如Array或Map或其他实现可迭代协议的对象(把二维数组转成对象);
举例1:数组转为对象
const arr = [['name','张三'],['age',18]];
const obj_arr = Object.fromEntries(arr);
console.log(obj_arr);//{name: "张三", age: 18}
举例2:把map转为对象
const mymap = new Map([['name','张三']]);
mymap.set("age",18);
const map_obj = Object.fromEntries(mymap);
console.log(map_obj);
第二节:字符串扩展方法
let str = ' asd '
console.log(str) //asd
console.log(str.trimStart()) //asd 清空头空格
console.log(str.trimEnd()) // asd 清空尾空格
第三节:数组扩展方法 flat与flatMap
flat
作用:会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回
返回值:一个包含将数组与子数组中所有元素的新数组,flat会移除数组的空项。
是否改变原有数组:否
//二维数组变为一维
const arr1 = [1, 2, 3, 4, 5, 6, [7, 8, 9]]
console.log(arr1.flat())
const arr2 = [1, 2, 3, [4, 5, 6, [7, 8, 9]]] //参数为深度,是一个数字
console.log(arr2.flat())//三维变二维
console.log(arr2.flat(2)) //[1,2,3,4,5,6,7,8,9]三维变一维 深度为2
flatMap
作用:首先使用映射函数映射每个元素,然后将结果压缩成一个新数组
返回值:一个新的数组,其中每个元素都是回调函数的结果,并且结构深度 depth值为1
是否改变原有数组:否
const arr2 = [1, 2, 3, 4]
const result2 = arr2.map(item => item * 10);
console.log(result2);
//给item加上[]变为二维 可以用flatmap变为一维
const arr3 = [1, 2, 3, 4]
const result3 = arr3.flatmap(item => [item * 10]);
console.log(result3);
//如果map的结果是一个多维数组可以进行flat 是两个操作的结合
const arr4 = [1, 2, 3, 4]
const result4 = arr4.flatMap(item => [item * 10]);
第三节:Symbol的description
定义:用来获取Symbol的字符串描述
方法:let s = Symbol('课工场'); console.log(s.description) //课工场
第六章:ES11
第一节:私有属性
#privateFieldName 定义私有属性。
使用intro()方法 放在里面可以访问到
class Person {
name;
#age;
#weight;
constructor(name,age,weight){
this.name = name;
this.#age = age;
this.#weight = weight;
}
intro() {
console.log(this.name);
console.log(this.#age);
console.log(this.#weight);
}
}
var girl = new Person('程',18,45)
console.log(girl.name);
console.log(girl.#age);//报错
console.log(girl);
girl.intro()//调用私有属性
第二节:Promise使用
见第二章。
第三节:可选链运算符
定义:可选链运算符的语法很简单,只需在下一个访问 . 之前添加一个 ? 即可。
function main(config){
const dbHost = config?.db?.host
console.log(dbHost) //192.168.1.100
}
main({
db:{
host:'192.168.1.100',
username:'root'
},
cache:{
host:'192.168.1.200',
username:'admin'
}
})
第四节:动态import
模块加载分为静态加载和动态加载。这里讲解如何动态加载模块,也就是在程序运行过程中,遇到某个操作或者某个事件时加载需要的模块。
Import(‘路径’),返回的是一个promise的对象
本文详细介绍了JavaScript中的ES6到ES11的主要新特性,包括let和const变量的使用,解构赋值,箭头函数,剩余参数,数组和字符串的扩展方法,以及Promise和async/await等内容,帮助读者理解和掌握这些新特性。
1044

被折叠的 条评论
为什么被折叠?



