let
1 支持块级作用域(在if、for循环体中定义的变量,在外部也不能访问到)
2 不能声明前置
3 不能重复定义
4 不能被window挂载
5 可以在for循环体中保存变量
var 在if、for循环中定义的变量,在外部可以访问到
存在块级作用域{}
let a=10;
if(a>5){
var b=10;
}
console.log(b);//10
if(a>5){
let c=10
}
console.log(c);//c is not defined
不存在变量的提升
console.log(a);//undefined
var a=10;
console.log(b);// Cannot access 'b' before initialization 初始化前无法访问“b”
let b=20;
不允许重复声明(包括普通变量和函数参数)
let a=20;
let a=10; //dentifier 'a' has already been declared
不能够被window挂载
let b = 20;
console.log(window.b);//undefined
在for循环体中保存变量
//定义数组
let arr=[];
/*1 利用闭包 在for循环体中保存变量
for(var i=0;i<5;i++){
arr[i]=(function(i){
return function(){
console.log(i)
}
})(i)
}*/
//2使用let 在for循环体中保存变量
for(let i=0;i<5;i++){
//利用闭包 保存变量
arr[i]=function(){
console.log(i)
}
}
//执行
arr[0]()//0
arr[1]()//1
arr[2]()//2
const
const定义变量的特点:
1 支持块作用域
2 无法修改
3 不能重复定义
4 不能声明前置
5 不能被window挂载
6 不能作为for循环的变量来使用
7 值只能是值类型,如果是引用类型则可以被修改
const a=10;
a=20;//Assignment to constant variable. 报错常数变量赋值。
在ES5中 模拟静态变量
let obj={
num:100,
color:"red",
size:{width:100,height:200}
}
//冻结对象
Object.freeze(obj);
//尝试拓展属性
obj.title="nihao";
//尝试修改属性值
obj.num=200;
//尝试删除属性
delete obj.color;
console.log(obj);//{num: 100, color: "red", size: {…}}
在ES3.1 中模拟静态变量
let Conf=(function(){
//定义对象
let obj={
num:100,
color:"red",
size:{width:100,height:200}
}
//返回接口函数
return function(key){
return obj[key]
}
})()
console.log(Conf("num"));//100
console.log(Conf("color"));//red
Conf("size").width=1000;
解构赋值 :按照一定模式,从数组和对象中提取值,对变量进行赋值.
数组:
let [a,b,c]=[1,2,3]
console.log(a,b,c);//1 2 3
let [d=3,e]=[2];
console.log(d,e);//2 undefined
let f;
let [m=2,n]=[f];
console.log(m);//2 如果原来的有值 在赋值一个undefined 则原来的值不改变
对象
let {a,b}={a:111,b:2222}
console.log(a,b);//111 2222
let {c,d=5}={c:1};
console.log(c,d);//1 5
``键之间提供了插值语法${},在插值语法之前是真正的js环境,因此可以使用表达式**
单行字符串拼接
//ES5
// var obj={"name":"john","age":"18"};
// var name=obj.name;
// var age=obj.age;
// console.log(name+"的年龄是"+age);//john的年龄是18
// ES6
let obj={"name":"john","age":"18"};
let {name,age}=obj;
console.log(`${name}的年龄是${age}`);//john的年龄是18
多行字符串拼接
<ul id="test"></ul>
<script>
var arr=[0,1,2];
let oUL=document.getElementById("test");
var html=""
// ES5
// for(var i in arr){
// html+="<li>"+arr[i]+"</li>"
// }
// oUL.innerHTML=html;
// console.log(html);//<li>0</li><li>1</li><li>2</li>
//ES6 写法
for(var i in arr){
html+=`
<li>
<a href="#">${arr[i]}</a>
</li>`
}
console.log(html);
/*
<li>
<a href="#">0</a>
</li>
<li>
<a href="#">1</a>
</li>
<li>
<a href="#">2</a>
</li>
*/
oUL.innerHTML=html;
</script>
数字拓展
ES6为Number拓展了几个方法:isNaN、 isFinite、isInteger
全局中isNaN方法(判断时会做类型转换) | 用于判断是否是NaN(Not a Number)如果是,返回true,否则false) |
---|---|
Number拓展中的isNaN(判断时不会做类型转换) | 首先必须是数字—其次才是判断是否NaN; (如果是NaN,返回true,否则false) |
全局中的isFinite(判断时会做类型转换) | 判断是否是有限的 |
Number拓展中的isFinite(判断时不会做类型转换) | 首先必须是数字—其次才是判断是否是有限的; (如果是有限的,返回true,否则false) |
Number拓展中的isInteger(判断时会做类型检验) | 首先必须是数字—其次判断是否是整型;(如果是整型则返回true否则返回false) |
字符串拓展
String.raw 原始字符串(不需要转义特殊字符)
let str="He\nllo i\nckt";
console.log(str);//He(换行)llo i(换行)ckt
console.log(String.raw`He\nllo i\nckt`);//He\nllo i\nckt
//实现String.raw`字符串`
String.IRaw=function(str){
return str.replace(/\n/g,"\\n");
}
console.log(String.IRaw("He\nllo i\nckt"));//He\nllo i\nckt
str.repeat(num) 重复字符串 num 要重复的次数
//原始字符串
let str='_hello'
console.log(str.repeat(3));//_hello_hello_hello
//通常拓展一个方法的是否先判断是否内置
//if(!String.prototype.repeat){}
//实现str.repeat(num);
String.prototype.icktRepet=function(num){
let result="";
for(let i=0;i<num;i++){
result+=str;
}
return result;
}
console.log(str.icktRepet(5))
str(父).startsWith(str(子),pos) 判断子字符串是否在开头
str(父).endsWith(str(子),pos) 判断子字符串是否在结尾
let str="jwlrjworuosfsaf"
console.log(str.startsWith("jw",0));//true
console.log(str.startsWith("af",13));//true
//自己实现
String.prototype.icktStartsWith=function(substr,pos=0){
var newStr=this.slice(pos);
//定义正则表达式
var reg=new RegExp('^'+substr);
//验证
return reg.test(newStr);
}
//测试
console.log(str.startsWith("jw"));//true
console.log(str.startsWith("af",13));//true
str(父).includes(str(子),pos) 判断是否包含子字符串
let str="温馨提示:会员显示时间更新有延迟,请稍后再查看";
console.log(str.includes("提示",2));//true
console.log(str.includes("提示",7));//false
//自定义实现
String.prototype.IcktIncludes=function(substr,pos){
//定义切割的字符串
var newStr=this.slice(pos);
//判断
return newStr.indexOf(substr)>=0;
}
console.log(str.IcktIncludes("查看",22));//false
拓展数组
**类数组:**可以通过索引值获取属性值,并且具备length属性的这一类对象
不能数组方法,ES6中拓展的from方法可以将其转为数组,就能使用数组方法了)
for of可以遍历数组,但是在遍历的过程中,不能使用索引值(用法参考下面的set结构)
Array.from(arr,function(item,index){ return ;})
不传function(){},只是将类数组转为数组对象,
如果传function(){},先将类数组转为数组,在对数组进行遍历,此时from方法的返回值就是函数执行的结果
let divs=document.getElementsByTagName("div");
//判断数组的方法
console.log(Array.isArray(divs));//Array.isArray(obj)
console.log(divs instanceof Array);//arr instanceof Array
console.log(divs.__proto__.constructor===Array);//obj.__proto__.constructor===Array
console.log(Object.prototype.toString.call(divs)==="[object Array]");//Object.prototype.toString.call(obj)==="[object Array]"
//使用ES6中from 方法转为数组 Array.from(arr)
let result=Array.from(divs);
console.log(Array.isArray(result));//true
//如果传递了函数,先讲类数组转为数组,在对数组进行遍历,此时from方法的返回值就是函数执行的结果
let result1=Array.from(divs,function(item,index){
// console.log(arguments)
return item.innerHTML=index+"----"+index;
})
console.log(result1)
自定义实现
Array.from(arr,function(item,index){ return ;})
let divs=document.getElementsByTagName("div");
//自定义实现 Array.from(arrlike,fn)
Array.icktFrom=function(arrlike,fn){
//定义结果容器
let result=[];
//遍历数组
for(let i=0;i<arrlike.length;i++){
//判断是否传递fn
if(fn){
//执行fn 传递两个参数 成员值 :arrlike[i] 索引 i
result.push(fn(arrlike[i],i))
}else{
return result.push(arrlike[i])
}
}
//返回结果
return result;
}
let result=Array.icktFrom(divs,function(item,index){
// console.log(arguments)
return item.innerHTML=index+"----"+index;
})
console.log(result instanceof Array)
之前创建数组的方式存在的问题
- 如果没有传递参数,得到的是空数组
- 如果传递一个数字参数,得到是带有长度的空数组
- 如果传递一个非数字参数,得到的带有一个成员的数组
- 如果传递多个参数,得到的是一个多个参数的数组
//之前创建数组的方式
console.log(Array());//[]
console.log(Array(10));// [empty × 10]
console.log(Array("a"));//["a"]
console.log(Array(1,2));//[1, 2]
ES6 中拓展了*Array.of()创建数组(实现将传递的每一个参数,都作为数组的成员)
//ES6中拓展的of方法
console.log(Array.of());//[]
console.log(Array.of(10));//[10]
console.log(Array.of('a'));//["a"]
console.log(Array.of(1,2));//[1, 2]
ES6中拓展了find() findIndex()
允许参数是可以执行的函数,在***查找的过程中,一旦找到立刻停止遍历***
find((item,index,arr)=>{return})查找成员,找到返回成员,没找到返回undefined
findeIndex(((item,index,arr)=>{return})查找成员,找到返回索引值,没找到返回undefined
let arr = ['尼古拉斯赵四', '宋小宝', '刘能', '小沈阳'];
//arr.find(function(item,index,arr){})
let result=arr.find((item,index,arr)=>{
return item==="宋小宝"
})
console.log(result);//宋小宝
let result1=arr.findIndex((item,index,arr)=>{
return item==="宋小宝";
})
console.log(result1);//1
拓展对象
let obj = {}
几点省略:
- 如果对象中定义的属性名和属性值的变量是相同的,则可以省略属性名以及冒号
- 我们可以通过[]动态的设置属性,可以书写表达式
之前我们可以通过[]获取属性,而现在我们可以通过[]设置属性名称 - 在对象中定义的方法,可以省略冒号以及function关键字
//定义变量
let color="red",
num=100;
let obj={
//在ES5中
// 定义属性
// color:"red",
// num:100,
// 定义方法
// getNumber:function(){}
// 在ES6中
color,
num,
//通过[]动态的设置属性,并且可以书写表达式
["hello"+color.toUpperCase()]:100, //helloRED: 100
//定义方法
getNumber(){
return this.num;
}
}
== 在判断两个参数的时候 会做类型转换
=== 在判断两个参数的时候 不会做类型转换
全等判断有几个问题:
1、0 和-0在全等判断的时候,得到的是true
2、NaN和NaN在全等判断的时候,得到的是false
所有的NaN表示“不是一个数字”,NaN就是一种数据类型,在存储的时候的地址是一样的
is 用于判断两个参数是否全等
is方法在判断的时候:
0 和-0 得到的是false
NaN和NaN 得到的是true
let num=0*1;
let num1=0*-1;
console.log(num===num1);//true
console.log(Object.is(num,num1));//false
//NaN
let num2=0/0;
let num3=+"100abc";
console.log(num2===num3);//false
console.log(Object.is(num2,num3));//true
//判断其他的
let num4=+"100";
let num5=100.00;
console.log(num4===num5);//true
console.log(Object.is(num4,num5));//true
**浅复制:**值类型是直接复制,引用类型只是改变指针,并不是真正的复制
**深复制:**值类型是直接复制,引用类型也是直接复制,并不是改变指针
**Object.assign(target, obj1, obj2)**浅复制
target: 要复制的对象 obj1,obj2:传递的对象给target,后面对象中的同名属性会覆盖前面对象的中的属性
let obj={
name:"老张"
}
let obj1={
num:100
}
let obj2={
title:"你好",
num:500,
colorsL:["red","green"]
}
//开始复制
let result=Object.assign(obj,obj1,obj2);
console.log(result);
console.log(obj);
console.log(obj1);
console.log(obj2);
简单实现深复制
//定义对象
let demo={width:100};
//简单实现深复制
let demo1=JSON.parse(JSON.stringify(demo));
console.log(demo,demo1);//{width: 100} {width: 100}
console.log(demo===demo1);//false
Jquery中实现深复制 extend方法
$.extend(true,target,obj1,obj2);
true :深复制
target: 要复制的对象 obj1,obj2:传递的对象给target,后面对象中的同名属性会覆盖前面对象的中的属性
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
<script>
let obj={
name:"老张"
}
let obj1={
num:100
}
let obj2={
title:"你好",
num:500,
colors:["red","green"]
}
let result=$.extend(true,obj,obj1,obj2);
console.log(result);//{name: "老张", num: 500, title: "你好", colors: Array(2)}
console.log(obj2.colors);//["red","green"]
console.log(result.colors===obj2.colors);//false
</script>
实现深复制
Object.icktAssign=function(target){
for(let i=0;i<arguments.length;i++){
//缓存arguments
let obj=arguments[i];
//遍历对象
for(let key in obj){
//判断是否是数组
if(Array.isArray(obj[key])){
//递归处理
target[key]=Object.icktAssign([],obj[key])
}else if(Object.prototype.toString.call(obj[key] === '[object Object]')){
//判断对象 Object.prototype.toString.call instanceOf constructor
//递归处理
target[key]=Object.icktAssign({},obj[key])
}else{
target[key]=obj[key]
}
}
}
//返回数据
return target;
}
let result=Object.icktAssign(obj,obj1,obj2)
ES6拓展了Symbol数据类型 (通过Symbol创建的数据即可避免对象中同名属性被覆盖的问题)(第七种数据类型)
使用typeof 来判断Symbol里面的数据类型
let obj={
num:100,
color:"red"
}
//定义Symbol数据
let s=Symbol();
let s1=Symbol("hello");//S1和S2是同名函数不会被覆盖
let s2=Symbol("hello");
obj[s]=200;
obj[s1]="ickt";
obj[s2]="hello_ickt";
console.log(obj);
for(let i in obj){
console.log(i);//for in 不能查看Symbol数据类型 只能看其他数据
}
let keys=Object.getOwnPropertySymbols(obj);
//查看数据
console.log(obj[keys[0]]);//200
console.log(obj[keys[1]]);//ickt
console.log(obj[keys[1]]);//ickt
console.log(typeof obj[s1]);//number
console.log(typeof obj[s1]);//String
箭头函数
- 只含有一个表达式可以省略{}
// ES5
// var foo=function(){
// return 1;
// }
// console.log(foo());//1
//ES6
let foo=()=> 1;
console.log(foo());//1
- 含有多条语句则需要加{}
let foo=(a)=>{
let b=10;
return a+b;
}
console.log(foo(10));//20
- this的指向问题
- ES5 this的指向问题 在谁的作用域里 它就指向谁
var obj={
"name":"john",
"sayHello":function(){
console.log(this);//obj
setTimeout(function(){
console.log(this);//window
},1000)
}
}
obj.sayHello()
- ES6 箭头函数this的指向定义时所在的作用域,在谁的作用域 ,this指向谁
// ES6
//this指向定义时所在的作用域,而不是执行时所在的作用域
var obj={
"name":"john",
"sayHello":()=>{
console.log(this);//window
setTimeout(()=>{
console.log(this);//window 定时器固定指向window
},1000)
}
}
obj.sayHello()
聚合数组
set结构和map结构
set结构 (实现了迭代器接口对象的去重数组,在去重的的时候不会做类型转换)
原型对象中具有**Symbol(Symbol.iterator)**属性 就可以使用for of迭代器进行遍历
let set=new Set()构造函数
功能:Set对象会自动过滤掉传入参数中的重复项,并将传入的参数转化为对象。
//过滤掉数组中重复的值,并转为对象
var set = new Set([1,2,3,4,4,5,5]);
console.log(set);//{1, 2, 3, 4, 5}
//过滤掉字符串中重复的值,并转为对象
var set1= new Set("hello world!");
console.log(set1);//{"h", "e", "l", "o", " ","w","r","d"};
利用set对象实现数组去重
var arr = [12,23,45,34,56,56,87,23,45,12,89];
var arr1 = new Set(arr);
var arr2 = [];
for(var arr3 of arr1){
arr2.push(arr3)
}
console.log(arr2);
拓展运算符 三个点语法总结:
//解构对象中:
let { key, key1, ...keys } = obj;
//逆运用:
let obj = { ...keys };
//解构数组中:
let [arg, arg1, ...args] = arr;
//逆运用:
let arr = [...args];
//获取剩余参数:
function demo(...arr) {}
//逆运用:
demo(...arr);
[…set]…扩展运算 符,将类数组对象转换以逗号分割的序列
var set = new Set([1,2,3,4,4,5,5]);
console.log(set);//{1, 2, 3, 4, 5}
var arr=[...set];//把对象内的值赋给数组
console.log(arr);//[1, 2, 3, 4, 5]
var arr1=[...arr];//把arr 赋值给数组arr1
console.log(arr1);//[1, 2, 3, 4, 5]
console.log(arr===!arr1);//false
for of //遍历
var set = new Set([1,2,3,4,4,5,5]);
//for of遍历对象 遍历的item 是成员
for(let item of set){
console.log(item)
}
// for of 遍历数组 遍历的item 是成员
for(let item of arr){
console.log(item)
}
//for in 遍历数组 (遍历的i 是索引)
for( var i in arr){
console.log(i);//遍历的i 是索引
}
//for in 遍历对象 (遍历的i 是key 值)
for( var i in obj){
console.log(i);//遍历的i 是key 值
}
set.size set对象长度
var set = new Set([1,2,3,4,4,5,5]);
console.log(set);//{1, 2, 3, 4, 5}
console.log(set.size);//5 数组长度用length 对象长度用size
set.add(0) //在set中添加0这个元素
set.delete(0)//在set中删除0这个元素
set.has(0) //判断set中是否含有0这个元素
set.clear();//清除set
var set = new Set([1,2,3,4,4,5,5]);//把数组过滤掉重复的值,并转为对象
console.log(set);//Set(5) {1, 2, 3, 4, 5}
//set增加元素
set.add(6);
console.log(set);//{1, 2, 3, 4, 5, 6}
//set删除元素
set.delete(5);
console.log(set);//{1, 2, 3, 4, 6}
//set判断是否存在元素
console.log(set.has(3));//true
//清空set
set.clear();
console.log(set);// {}
**keys()😗*返回键名的遍历器 for(let item of set.keys()){console.log(item)}
values():返回键值的遍历器for(let item of set.values()){console.log(item)}
entries():返回键值对的遍历器 for(let [key,item] of set.entries()){ console.log(key,item); }
forEach():使用回调函数遍历每个成员set.forEach((item,key)=>{console.log(key,item)})
var set = new Set([1,2,3,4,4,5,5]);
// console.log(set);//{1, 2, 3, 4, 5}
// console.log(obj.size);//5 数组长度用length set对象长度用size
//keys()返回键名的遍历器
for(let item of set.keys()){
console.log(item);
}
// 1, 2 , 3, 4, 5
//values():返回键值的遍历器
for(let item of set.values()){
console.log(item);
}
//1,2,3,4,5
//entries() 返回键值对的遍历器
for(let [key,item] of set.entries()){
console.log(key,item);
}
//forEach() 使用回调函数遍历每个成员
set.forEach((item,key)=>{console.log(key,item)})
Map是一个超级对象
- 在js中定义的属性名称必须都是字符串
- 但是Map对象中添加的属性数据可以是任意类型(7种类型都可以)
- 内部也提供了大量的方法用于操作该对象
- let map=new Map([[“name”,“john”],[“age”,“20”]]);
var map=new Map([["name","john"],["age","20"]])
console.log(map);// {"name" => "john", "age" => "20"}
用法和set 类似
map.size;长度
map.set(key,value) 添加键值对
map.get(key) 读取
map.delete(key) 删除
map.has(key) 参看是否含有
map.clear() 清除
keys() :返回键名的遍历器
values():返回键值的遍历器
entries():返回键值对的遍历器for(let [key,value] of map.entries()){
console.log(key,value)}
forEach():使用回调函数遍历每个成员 map.forEach((value,key)=>{
console.log(value*2)})
var map=new Map([["name","john"],["age","20"],["sexy","male"]])
console.log(map);//{"name" => "john", "age" => "20", "sexy" => "male"}
//返回键名的遍历器
for(let item of map.keys()){
console.log(item)
}
//返回键名的遍历器
for(let item of map.values()){
console.log(item)
}
//返回键值对的遍历器
for(let [item,value]of map.entries()){
console.log(item,value)
}
//使用回调函数遍历每个成员
map.forEach((value,key)=>{
console.log(key,value)
})
ES6提供了代理,(用于对重要的数据起到了拦截保护作用)
语法:return new Proxy(data, { get(obj,key), set (obj,key,value)})
//代理
let star=(function(){
//定义数据类型
let data={
name:"赵丽颖",
boyFriend:"冯绍峰"
};
//代理
return new Proxy(data,{
//get 读取
get(obj,key){
//什么都可以获取
// console.log(111,this,arguments);//查看所有数据
//进行判断
if(key==="boyFriend"){
return "不告诉你";
}
return obj[key];
},
//设置
set(obj,key,value){
//console.log(222,this,arguments);//什么都可以设置
//乳沟想要修改重要数据,则不可以
if(key==="boyFriend"){
console.log("不能修改")
}
//其他数据可以修改
obj[key]=value;
}})
})();
console.log(star.name);// 赵丽颖
console.log(star.boyFriend)// 不告诉你
star.name='大美女';//大美女
star.boyFriend='刘能'; //不能修改
console.log(star.name); //大美女
console.log(star.boyFriend)// 不告诉你
promise()
语法:
new Promise((resolve, reject) => {
// 执行异步操作
如果执行成功 则执行resolve方法
如果执行失败 则执行reject方法
})
在外部我们可以通过then方法监听异步操作的结果
then方法:可以监听成功或者是失败的方法
catch: 用于监听失败时候的方法
finally: 无论成功还是失败都会执行的方法
// 定义函数
let IcktPromise = function (callback) {
// 定义状态
this.state = 'pending';
// 执行成功时候的回调函数队列
this.resolvedArr = [];
// 执行失败时候的回调函数队列
this.rejectedArr = [];
// 定义resolve方法
let resolve = (value) => {
// console.log(111, this);
// 缓存value
this.doneValue = value;
// 改变状态
this.state = 'resolved';
// 将执行成功时候的回调函数队列中的每一项函数逐一执行
this.resolvedArr.forEach(fn => value = fn(value));
// 执行完毕将队列清空
this.resolvedArr = [];
}
// 定义reject方法
let reject = (value) => {
// 缓存value
this.doneValue = value;
// 改变状态
this.state = 'rejected';
// 将执行成功时候的回调函数队列中的每一项函数逐一执行
this.rejectedArr.forEach(fn => value = fn(value));
// 执行完毕将队列清空
this.rejectedArr = [];
}
try {
callback(resolve, reject);
} catch (e) {
reject(e);
}
}
// 添加then方法
IcktPromise.prototype.then = function (success, fail) {
if (this.state === 'pending') {
// 通过&&优化
typeof success === 'function' && this.resolvedArr.push(success);
typeof fail === 'function' && this.rejectedArr.push(fail);
} else if (this.state === 'resolved') {
typeof success === 'function' && success(this.doneValue);
} else {
typeof fail === 'function' && fail(this.doneValue);
}
// 返回this 可以进行链式调用
return this;
}
let p=new IcktPromise((resolve,reject)=>{
//异步执行操作
setTimeout(()=>{
//执行成功
resolve("执行成功");
//执行失败
// reject("执行失败");
},2000)
})
p
.then(res=>{
console.log("success",res);
return res;
})
生成器函数(generator)
generator函数适用于处理异步编程(异步函数)的处理方法,内部封装了大量的状态,允许我们逐一遍历
语法:
.then方法的返回值是Promise对象,因此可以链式调用该方法(上一次的then方法的输出作为下一次then方法的参数来使用)
//定义式
function*foo(x){
yield x+1;
return yield x+2;
}
//表达式
let demo=function *(){
yield x+1;
return yield x+2;
}
//执行状态函数
let d=demo();
//逐条遍历内部状态
d.next()
yield 表示暂停的意思(注意:yield关键字只能出现在generator函数中)
通过return 返回最后一个状态(后面的状态不会再执行)
generator函数的返回值实现了next方法,因此可以通过next()逐条遍历内部的状态,
next() 表示上一次yield的返回值 ,返回值是一个对象*,*
对象中 done表示表示是否遍历完成, value表示状态值
<input type="button" id="btn" value="按钮">
<script>
var btn=document.getElementById("btn");
function *demo(){
console.log("第一件事");
yield "起床";
console.log("第二件事");
yield "刷牙";
console.log("第三件事");
yield "洗脸";
console.log("第四件事");
return yield "吃饭";
}
//执行状态函数
let d=demo();
btn.onclick=function(){
//逐条遍历内部状态
console.log(d.next());
}
</script>
传递数据
在generator函数种数据的传递有两个方向
1 数据由generator函数流入函数的外部
通过yield表达式定义i状态值
通过next方法上的value属性接受
//定义状态函数 数据由内向外
function *foo(){
//1 通过yield关键字定义状态值
yield "你好";
yield "我好";
yield "大家好";
}
//执行状态函数
let d=foo();
//2 通过next()方法中的value属性接受
console.log(d.next().value);//你好
console.log(d.next().value);//我好
console.log(d.next().value);//大家好
2 数据由外部流入generator函数内部
在外部通过next方法传递参数
在函数内部通过yield表达式,接受状态值
//定义状态函数 数据由外向内
function *demo(){
//2 通过yield关键字接受数据
let a=yield;
console.log(a);
let b=yield;
console.log(b);
let c=yield;
console.log(c);
}
//执行状态函数
d=demo();
//1 通过next()传递数据
//第一次执行的next()只用于启动状态函数,传递的数据是接受不到的
//遍历状态
console.log(d.next());
console.log(d.next("a"));
console.log(d.next("b"));
//在外部中止遍历状态
console.log(d.return("c"));
ES7 async与await
async 表示函数中有异步操作
*代表了 语法
await 表示等一等 当前程序执行完毕 后面的代码才会执行
代表了 yield关键字
特点:
1 提高代码的语义化
2 await允许任何数据 co方法中yield后面的数据不能是值类型
3 函数的返回值是Promise对象
4在函数中内置状态函数的启动,直接执行函数即可,不需要通过next方法逐条遍历,当程序执行到await的时候,会交出程序的控制权,后面的逻辑代码会继续执行,只有异步操作之后,await后面的代码才会执行,当await后面出现了其它数据的时候,返回一个监听resolved状态的Promise对象,当函数中出现了错误,函数会继续执行,会将错误的信息追踪到错误队列中
当程序执行到await的时候,会交出程序的控制权,后面的逻辑代码会继续执行,只有异步操作之后,await后面的代码才会执行,
//定义异步函数
async function gen(){
console.log(1);
await 100;//当程序执行到await的时候,会交出程序的控制权,后面的逻辑代码会继续执行,只有异步操作之后,await后面的代码才会执行
// await 100 ; 等价于 await Promise resolve(100)
console.log(2)
}
gen();
console.log(3);
//所以执行顺序 1 3 2
当await后面出现了其它数据的时候,返回一个监听resolved状态的Promise对象,当函数中出现了错误,函数会继续执行,会将错误的信息追踪到错误队列中
//定义错误队列
function demo(){
console.log("demo start");
//抛出错误
throw new Error("出错了");
}
//定义异步函数
async function foo(){
//执行异步
return new Promise((resolve,reject)=>{
//执行异步操作
setTimeout(()=>{
resolve("执行成功了")
},2000)
})
.then(res=>{
demo()
})
}
foo();
async返回的是一个Promise对象, 因此
我们可以通过then方法监听执行成功时候的状态改变
我们可以通过catch方法监听执行失败时候的状态改变
await与yield一样:
await只能出现在async中
yield只能出现在generator函数中
异步执行顺序
function task1(){
console.log("task1 start"); //2
return "task1 end";
}
function task2(){
console.log("task2 start"); //7
return "task2 end";
}
//定义异步函数
async function demo(){
console.log("demo start"); //1
let data1=await task1();
console.log(task1()); //6
let data2=await task2();
console.log(data1,data2); //9
}
demo();
console.log("demo done"); //3
//定义异步函数
new Promise((resolve,reject)=>{
console.log("promise start"); //4
//执行成功
resolve("成功了"); //8
})
.then(res=>{
console.log(res); //10
})
.then(res=>console.log(res));
console.log("all done"); //5
类class(了解)
class Person{
//构造函数
constructor(name){
this.name=name;
}
//类的方法
sayHello(){
console.log(this.name);
}
}
var person=new Person("john");
console.log(person.name);//john
person.sayHello();//john