ES6~ES11

本文详细介绍了JavaScript中的ES6到ES11的主要新特性,包括let和const变量的使用,解构赋值,箭头函数,剩余参数,数组和字符串的扩展方法,以及Promise和async/await等内容,帮助读者理解和掌握这些新特性。

第一章: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不需要;

  1. 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有一下两个特点:

  1. 对象的状态不受外界影响。

Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。

  1. 一旦状态改变了就不会在变,也就是说任何时候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的对象

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值