es6学习

http://es6.ruanyifeng.com
https://blog.csdn.net/huhao0829/article/details/79315457
es6怎么兼容?babel

let和const

  • let
    1.let只在let声明的代码块内有效,({ }内一般都可以是代码块)
    2.注意区别全局作用域var 和块级作用域,而只有let 后定义的才是块级,被赋值的和let后的不要弄混。经典的for循环,a[i]=function(){consolo.log(i)},注意此时的赋值不仅仅是值的复制,还有引用的指向,指向的是全局变量i,var 在循环中使用的变量是同一个变量,而let根据块级作用域,使用的不是同一个变量。
    (对于for循环的理解,因为只有全局变量一个i,所以i始终都是一个地址空间?虽然名字变了,但是对于数组a[i]来说,都是指向的同一数组空间,这就是引用,结果就是最后一个值)
    3.for循环变量和循环体不是一个作用域对于let来说,所以let声明的变量互不干扰
    4.var的变量提升,虽然可以使用但是是undefind(未赋值之前),而let是报错
    5.暂时性死区:在同一个作用域下(块级作用域),只要有let或const,在let或const之前的赋值都是错误的,都是不可用的。解决死区:不使用未声明的变量,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。(typeof如果在let之前会出错)
    6.在同一作用域内不可重复声明一变量(无论有没有var),因此,不能在函数内部重新声明参数,函数的参数和第一个{}为同一个作用域,前提是参数没有默认值。如果参数有默认值就会单独形成一个作用域。要么是函数调用时传的参数,要么函数外的全局变量。
    function func(arg){ let arg;//错误,同一作用域} (arg){ { let arg;//正确} } 和循环变量区别

  • 块级作用域
    1.在es5中只有全局作用域和函数作用域,es6添加了块级作用域
    2.块级作用域的出现使得立即执行函数(function(){}())不再需要?
    3.ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。(这个了解一下,虽然是非法的但是可以运行)es6虽然可以在块级作用域内声明函数,但是环境有差别,(至于具体差别还是要具体查看文档),**考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。let f=function(){}**但如果在块级作用域内声明里函数,则函数相当于var,但是也要视情况而定。最好要写成函数表达式。
    4.es6块级必须要有大括号

  • const
    1.const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化.
    2.虽然const 声明引用类型时是可以改变值的,但也是仅仅改变的这个对象的值,而不可以改变const指向的地址空间, const a=[]; a.push(‘s’);//可以,仅仅改变了值。 a=[‘s’]//不可以,此时改变了内存地址,
    3.如果连引用类型的值都不可以改变时,则必须使用Object.freeze()方法

  • 声明变量
    1.es5只有两种var全局变量和function函数变量,es6又有let,const,class,import
    2.顶层对象:window对象。在es6里,var和function是顶层对象,但是let、const、class声明的全局对象不是顶层对象,let a=2;window.a//是错误的。
    3.globalthis对象:函数里面的this,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this会指向顶层对象。但是,严格模式下,这时this会返回undefined。node里没有self和window,只有global

变量的解构赋值(为字符串、数组、对象等的解构赋值)

  • 基本用法:从数组和对象中提取值,对变量进行赋值,数组,对象,数字什么的解构赋值是对于右侧数据类型来说。通常来说左侧都是数组或对象,而右侧可以为数组,对象、数字或字符串等,所以要使用解构赋值,右侧通常不能为空,但是{},[]这样的空可以,函数参数解构赋值也是同理。
    -数组的解构赋值
    1.解构一定要对应的位置,如果对应的位置无值则为undefined,…符号收(rest参数)取剩下的所有值,没有的为[];
    2.解构有两种情况:结构不成功(左边的声明比右边的值多)和不完全解构(左边的声明比右边的值少)
    3.如果左侧为数组,则右侧也要为数组,不可为{},null,nan等,但如果有iterator接口或者set结构则另说
    4默认值(一定要多看看这里的题).可以使用默认值,如果默认值后为undefined或[],则优先使用默认值,否则则不适用默认值
    特殊:let [x = 1(默认值)] = [null]; x // null 因为null和undefined不完全相等,所以null赋值成功。

  • 对象的解构赋值
    1.对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。但是同样因为声明了但是未取到值,所以值为undefined。
    2.对象的赋值:对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。let { foo: baz } = { foo: ‘aaa’, bar: ‘bbb’ }; 所以foo为同名属性,baz为对应的变量,真正被赋值的是baz。
    3.(容易忘记,可以多瞧瞧)与数组一样,结构也可以嵌套结构的对象。(就是对象里面有对象)。let {p:[‘heelo’,{y:'world}]}; 此时p只是模式,不能输出,输出p需要let {p,p:[x,{y}]},而且没有赋具体值的都是模式,
    4.对象的解构赋值可以取到继承的属性。setpropertyof
    5.默认值生效的条件:对象的属性值严格等于undefined(注意默认值是哪个,属性值是哪个)
    6.对象的默认值容易混淆点:var {x:y=3}={x:5}//此时x只是个模式,不能输出,如果输出会显示未定义,能输出的只有属性值y,默认值是给y赋值,不要瞎想,此时x的属性值y的值为5.
    7.也可以将数组的值赋给对象,但注意输出时一定是属性值输出,不要输出模式,而且模式对应的数组内的index。

  • 字符串的解构赋值:length

  • 数值和布尔值的解构赋值:解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。由于null和undefined都无法转换为对象,所以无法对其结构赋值。会报错。

  • 函数**参数!!!**的解构赋值
    1.这里有个易混的内容。函数参数的默认传值和函数参数变量的默认值
    function move({x=0,y=0}={}){//}. function move({x,y}={x:0,y:0}){//}
    第一种为是直接为x,y指定了默认值,而第二种是传参的时候指定了默认了,就是默认传递了什么参数,当然这个传递的值可以改变
    ~move({x:3}) 1.[3,0]. 2.[3,undefined] 两种情况结果如图所示,是因为本来就给y指定来默认值0,传参数没有传y就使用默认值,而第二种是因为x,y刚开始都没有默认值,传的参数只有x,没有y,覆盖掉了默认传参{x:0,y:0},所以y没有参数,为undefined
    ~move() 1.[0,0] 2.[0,0] 因为根本就没有传参数,所以1使用了默认值,2使用了默认参数,xy都有值
    ~move({}),1.[0,0] 2.[undefined,undefined],第一种xy还是使用了默认值,而第二种xy虽然传参数了,但都为空,都为undefined. !!!这里要注意另一个undefined情况,但是是在变量上设置默认值的。
    ~注意区别function move({x,y=0}){} 和 function move({x,y=0}={}). 第二种已经解构赋值了。所以为undefined。就算move()也是[undefined,0] ,虽然函数参数也属于声明的一种,但是对于解构赋值来说,必须要有默认参数{}否则就不是undefined而是报错,如果是函数参数时没有设定,那么在调用函数的时候需要move({})设定。

  • 使用圆括号的情况:赋值语句(声明语句不可以,函数参数也是声明语句),非模式部分,如果有模式,就将括号放在最最最外层,可以避免块作用域。!!!!多多看看文档熟悉一下

  • 用途:看文档多敲一敲

  • 注意区别:函数参数的默认值和设置对象解构赋值的默认值注意是对象结构,如果不是对象的情况要考虑。

函数的扩展

  • 参数默认值的位置(undefined),如果想缺少参数值使用默认值的话,除了尾位(1,2, ),其他位置必须得用undefined,否则就会报错。
  • 函数的length属性,返回的参数的个数,如果参数有默认值,则其个数不会被包含;…rest参数也不会被包含在length里,…rest之后也不能有值,否则会报错,含有默认值的参数后面的也不会被包含在length里。
  • 函数作用域??没看懂那里
  • rest参数(…):用于获取函数的多余参数,这样就不用arguments,而且arguments是类数组,用数组的方法的时候需要call,rest本身就是数组,可以直接用数组的方法。
  • 函数参数的默认值(要区别默认值和解构赋值)
    1.函数参数和解构赋值结合起来使用的时候注意一定要赋值(直接在参数赋值或者在调用的时候赋值,否则不会像普通参数一样undefined,还会报错),可以看文档!
    2.作用域:一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域,这是个新的作用域,通常来说不会影响别的作用域,除非有下面的作用域有需要外层的变量。变量没有值的话,找值先找参数,再找外层变量。
  • rest参数
    1.rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。(表现出来是参数,但实际存入的是数组?)
  • name属性:返回函数的名字
  • 箭头函数:箭头函数的this是重点
  • 尾调用优化
    1.尾调用:就是指某个函数的最后一步是调用另一个函数
  • 函数参数的尾逗号
    1.允许最后一个参数后有逗号

数组的扩展

  • 数组的属性和方法
    https://blog.csdn.net/qq_41807645/article/details/82781693
    https://juejin.im/entry/59ad2cacf265da248a7aa6cc#Array构造器
    1.Array.copyWithin(target, start,end):实际上选取的start-end是start和end-1中间的值放到target之后而不改变其长度。
    2.filter()通常来说,filter里的参数是一个函数,用来检测数组的元素.
    3***.foreach()对数组中的每一个执行foreach中的函数(没有返回值?)
    4.对于数组pop、push添加方法,通常都是添加返回最后长度,删除返回删除的值
    5.sort()、slice、splice

  • 扩展运算符
    1.关于扩展运算符和rest参数: rest参数搭配的变量是一个数组(…rest)可以使用数组的一切操作,直接使用;关于扩展运算符,可以将数组转化为参数列表,注意,首先…后面的必须是数组 …[2,3,4],本身就是一个数组, [1,2,…[3,5,6]] ===[1,2,3,5,6]因为3,5,6本身是一个数组,通过转化为参数列表,这样就可以放在一个数组里了。
    2.可以用于代替apply应用数组的方法,可以代替cancat实现数组拼接,如果将扩展运算符用于数组复制,只能放在参数最后一位,否则会报错。(关于是否要放在最后一位,在仔细看看)

对象的扩展

  • 属性名表达式
    1.[‘a’+'bc] 用表达式来表示属性名
  • 属性的遍历
    1.for…in
    2.object.keys()

set和map数据结构

  • set数据结构
    1.是一个类似数组的数据结构,值唯一没有重复。set本身是一个构造函数,用来生成set数据结构。
    2.Set函数可以接受一个数组(或者具有 iterable 接口的其他数据结构)作为参数,用来初始化。
    3.向 Set 加入值的时候,不会发生类型转换,是因为内部发生的是===
    4.向set加入两个空对象时,可以认为两个空对象不等

  • 实例属性和方法
    1.size属性和constructor属性
    2.操作方法
    (1)add(value):返回set结构本身
    (2)delete(value):删除,返回布尔值
    (3)has(value):表示是否为set成员
    (4)clear():清空,无返回值
    (5)注意区别object结构和set结构,Array.from方法可以将 Set 结构转为数组,同时可以去重。
    3.遍历方法
    (1).keys():返回键名的遍历器,由于 Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。
    (2).values():返回键值。。。,但要注意,返回的所有的,不是一个一个的。可以用for…of遍历。
    (3).entries()返回键值对
    (4)forEach()使用回调遍历没个成员
    (5)扩展运算符的,map,filter和set的结合应用,并集,交集。

  • map数据结构(map没仔细看,等到想仔细看的时候要看)
    1.hash结构:键值对的集合
    2.它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。作为构造函数,Map 也可以接受一个数组作为参数

generator生成器—异步编程

  • 因为现在比较支持async,所以对于iterator和generator需要稍微了解一下
  • https://www.jianshu.com/p/5fb1586b9164,了解看这篇
  • http://www.imooc.com/article/279435
  • 调用 Generator 函数并不会立即执行其内部的代码,而是会等待返回的遍历器调用 next() 方法时,移动状态指针,再执行代码,Generator 函数会返回一个遍历器对象,遍历器对象拥有 next() 方法。
    -调用next()方法,会输出一个包含value和done属性的对象,value:yeild和return,done:false属性,表示是否遍历完。
  • 不能使用箭头函数创建生成器函数
  • for…of…也可以遍历,但无法遍历return
  • next()方法的参数,但是 next() 方法可以传入一个参数,同时这个参数会作为上一个 yield 的返回值,可以将这个返回值赋给一个变量,然后供接下来使用。但要注意如果有yeild表达式同时又有next传参。注意区别next传参和return传参。
  • generator函数原型链上的两个方法:
    1.Generator.prototype.throw():该方法抛出的错误可以被函数内部和外部捕获,yield 表达式替换成一个 throw 语句,并返回给定的错误信息,(手动输入错误信息?执行后就结束,不再遍历?)更详细的可以看看第二个链接,再往下next()就没有输出了
    2.Generator.prototype.return():该方法能够将参数作为下一个状态的返回值,同时结束遍历;yield 表达式替换成一个return语句,并返回给定的值。如果调用 return() 方法时无参数,则 value 值将是 undefined 同时结束遍历.再往下next()结果就会是undefined,还是会有输出
    3.如果被调用的 Generator 函数有 return 语句,那么 return 后面的表达式将会作为这个 Generator 函数的返回值,返回值可以赋给一个变量,同时可以输出这个变量。
  • yeild*表达式:可以看看第二个链接
  • generator的异步应用
    1.Generator 函数可以暂停执行和恢复执行(到达yeild就停下?),这是它能封装异步任务的根本原因。除此之外,它还有两个特性,使它可以作为异步编程的完整解决方案:函数体内外的数据交换和错误处理机制。
    2.next返回值的 value 属性,是 Generator 函数向外输出数据;next方法还可以接受参数,向 Generator 函数体内输入数据。
    3.Generator 函数内部还可以部署错误处理代码,捕获函数体外抛出的错误
    4.thunk函数:自动执行generator函数
    (1).thunk函数的意义:临时函数(了解一下,涉及返回函数什么的)
    (2).co模块:也可以自动执行generator函数,co模块自动执行generator并返回一个promise对象。
    (3).关于co模块基于promise自动执行,是因为将readfile包装成了一个promise对象,yield定义的就是一个promise对象。参数必须要为thunk或promise对象。

async函数(多练习一下,还不熟)

https://juejin.im/post/5a9516885188257a6b061d72

  • 和generator区别
    1.内置执行器:generator不许依靠执行器,比如co模块,而async自带执行器,直接调用函数即可。
    2.更好的语义:async和await,比起星号和yield,语义更清楚了。async表示函数里有异步操作,await表示紧跟在后面的表达式需要等待结果
    3.更广的适用性:co模块约定,yield命令后面只能是 Thunk 函数或 Promise 对象,而async函数的await命令后面,可以是 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时会自动转成立即 resolved 的 Promise 对象)。
    4.返回值是 Promise:async函数的返回值是 Promise 对象,这比 Generator 函数的返回值是 Iterator 对象方便多了。你可以用then方法指定下一步的操作。进一步说,async函数完全可以看作多个异步操作,包装成的一个 Promise 对象,而await命令就是内部then命令的语法糖。

  • 基础用法:
    1.async返回一个promise对象,当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体内后面的语句。(注意在async一定要等到异步操作完成(await表示异步操作?)之后再执行函数体内后面的语句)
    2.由于async函数返回的是 Promise 对象,可以作为await命令的参数,这样就不用将对象通过resolve()转为promise对象了?这样就还是promise可执行。
    3.async使用模式:函数模式、对象的方法、函数表达式、class方法、箭头函数

  • 语法
    1.返回promise对象(return):
    (1)async函数内部return语句返回的值,(注意如果变成reject状态),会成为then方法回调函数的参数。(then方法再async函数的外部)
    (2)async函数内部抛出错误,会导致返回的 Promise 对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到。
    2.promise对象的状态变化:async函数返回的 Promise 对象,必须等到内部所有await命令后面的 Promise 对象执行完,才会发生状态改变,除非遇到return语句或者抛出错误。也就是说,只有async函数内部的异步操作(await)执行完,才会执行then方法指定的回调函数。
    3.await命令:正常情况下,await后面是一个promise对象,返回的是该对象的结果,如果不是对象,就直接返回对应的值;另一种情况:await后面是一个thenable对象,即定义then方法的对象(不是promise对象),但await会将其等同于promise对象;await可以实现休眠效果(因为async函数的原因)
    4.任何一个await语句后面的 Promise 对象变为reject状态,那么整个async函数都会中断执行,并被catch的回调捕获。【await promise.reject(‘出错了’); reject情况下可以不用return?return await promise.resolve(‘sdsad’)】
    5.我们希望即使前一个异步操作失败,也不要中断后面的异步操作。这时可以将第一个await放在try…catch结构里面,这样不管这个异步操作是否成功,第二个await都会执行。
    await后面的 Promise 对象再跟一个catch方法,处理前面可能出现的错误。await.promise.reject(‘出错了’).catch(e=>console.log(e))
    6.await后面的异步操作出错,那么等同于async函数返回的 Promise 对象被reject。[注意区别await后面的promise对象和异步操作new promise(function(resolve,reject){})和promise的实例],同理也可以trycatch
    7.注意:(1)多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发。(注意怎样同时触发?看文档)
    (2)await命令只能用在async函数之中,如果用在普通函数,就会报错
    (3)async 函数可以保留运行堆栈???没搞懂,很困
    (4)在async函数中使用await,那么await这里的代码就会变成同步的了
    (5)await可以直接获取到后面Promise成功状态传递的参数,然后还赋值给别的变量?
    (6)如果在是循环中使用await,就需要牢记一条:必须在async函数中使用
    8.顶层await

module

  • 和commonjs的一些比较

https://www.wengbi.com/forum.php?mod=viewthread&tid=74503&extra=page%3D&page=1
一、module语法之export

  • es6在编译时就可以确认依赖关系(静态加载),效率比commonjs高,但是es的模块不是对象,commonjs在运行时才能确认
  • es6自动采用严格模式,关于严格模式下的一些要求,具体看文档:禁止this指向全局变量
  • export:一个文件就是一个模块,外界无法读取,通过export和import,除了输出变量,还可以输出函数和类等
  • export写法:1,2。 。 使用as重命名,as对于同一个变量可以使用不只一次,as后输出名字不同的同一变量。
  • export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系(注意是模块内部的变量!!!变量)。
  • export语句输出的接口,与其对应的值是动态绑定关系,即通过该接口,可以取到模块内部实时的值。
  • export命令可以出现在模块的任何位置,只要处于模块顶层就可以(环境的最顶层)
    二、module语法之import(引入)
  • import {} from ’ xxxxxx’
  • import命令输入的变量都是只读的,因为它的本质是输入接口。也就是说,不允许在加载模块的脚本里面,改写接口。import { a} from ‘…’ a={} //错误,因为a是变量;如果a是对象,则可以改写a对象的属性 a.foo=‘dsss’ //正确,其他模块也可以读到,所以最好不要改写。
  • 注意,import命令具有提升效果,会提升到整个模块的头部,首先执行。所以如果在import之前用到了import里的内容,也不会undefined和报错。
  • 如果from后不是文件名,要进行配置
  • 由于import是静态执行,所以不能使用表达式({}这个里面不能是表达式)和变量(from后面的,不能使用定义的变量,一定要注意是变量啊)
  • 如果多次重复执行同一句import语句,那么只会执行一次,而不会执行多次。
  • 模块的整体加载 import * as circle from ‘./circle’. 模块整体加载时不允许模块的变量或者函数。?
    三、module语法之export default
  • 为模块指定默认输出。其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。不用as,不用{},因为default只能有一个.如果不指定名字就为_。 普通的export,import需要大括号,也可以用在非匿名函数上,不过加载的时候,视同匿名函数加载。
  • export {add as default};import { default as foo } from ‘modules’;
  • default是一个default变量,所以default后面不能跟变量声明语句。
    四、module语法之import和export复合使用
    五、模块继承
    六、跨模块常量 const
    七、import适用场合
  • 按需加载
  • 条件加载
  • 动态的模块路径
  • then方法是啥
  • 加载多个模块,用在async中
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值