淘先锋技术网

首页 1 2 3 4 5 6 7

ES6

1.1 ES6环境搭建

在Node.js环境中运行ES6

  • 安装node.js

webpack

现代JavaScript应用程序的静态模块打包器。

  • 核心概念

    • 入口(entry)

      指出那个模块作为构建内部依赖图的开始

      • 单个入口语法

        const config ={
        	entry: "./src/main.js"
        }
        
      • 对象语法

        const config ={
        	app: "./src/main.js",
        	vendors: "./src/vendors.js"
        }
        
    • 输出(output)

      output确定在哪输出创建的bundles,默认值./dist

      const config={
      	entry: "./src/main.js",
      	output: {
      		filename: "bundle.js",
      		path: path.resolve(_dirname,'dist')
      	}
      }
      
    • loader

      处理非JavaScript文件,例:通过loader将ES6语法转为ES5

      const config ={
      	entry: "./src/main.js",
      	output: {
      		filename: "bundle.js",
      		path: path.resolve(_dirname,'dist')
      	},
      	module:{
      		rules: [
      			{
      				test: /\.js$/,
      				exclude: /node_modules/,
      				loader: "babel-loader",
      				options: [
      					presets: ["env"]
      				]
      			}
      		]
      	}
      }
      
    • 插件(plugins)

      打包,优化,压缩,定义环境变量等等

      //通过npm安装
      const HtmlWebpackplugin = require('html-webpack-plugin') 
      //用于访问内置插件
      const webpack = require('webpack')
      const config = {
      	module: {
      		rules: [
      			{
      				test: /\.js$/,
      				exclude: /node_mkodules/,
      				loader: "babel-loader"
      			}
      		]
      	},
      	plugins: [
      		new HtmlWebpackplugin({template: './src/index.html'})
      	]
      }
      
  • 利用webpack搭建应用

    const path = require('path')
    module.exports = {
    	mode: "development", //development:开发模式,production:生产模式
    	entry: "./src/main.js",
    	output:{
    		filename: "bundle.js",
    		path: path.resolve(_dirname, 'dist')
    	},
    	modele: {
    		rules: [
    			{
    				test:/\.js$/,
    				exclude:/node_modeles/,
    				loader: "babel-loader",
    				options: [
    					presets: ["env"]
    				]
    			}
    		]
    	},
    	plugins: [
    		...
    	]
    }
    

gulp

基于流的自动化构建工具

  • 使用gulp

    • 全局安装

      npm install --global gulp
      
    • 在项目中引用依赖

      npm install --save-dev gulp
      
    • 在项目根下创建gulpfile.js的文件

      const gulp = require('gulp')
      //default表示一个任务名,为默认执行任务
      gulp.task('default',function(){
      	//放置默认的任务代码
      })
      
    • 运行gulp

      gulp
      
  • 利用gulp搭建应用

    const gulp = require('gulp')
    const uglify = require("gulp-uglify")
    gulp.task('default',function(){
    	gulp.src('./src/main.js')
    		.pipe(uglify())
    		.pipe(gullp.dest('./dist'))
    })
    

2.1 let与const

let声明的变量只在let命令所在的代码块内有效

const声明一个只读的常量,一旦声明,常量的值就不能改变

  • let在代码块内有效,var在全局范围内有效

  • let只能声明一次,var可声明多次

  • let不存在变量提升,var会变量提升

    console.log(a) //ReferenceError: a is not defined 引用错误或参考错误
    let a = "apple"
    console.log(b)//undefined
    var b = "xiong"
    
  • const声明之后不允许改变,一旦声明必须初始化(否则出现语法错误)

  • 代码块内如果存在let或者const,再声明之前使用会报错,参考变量提升

2.2 结构赋值

  • 剩余运算符

    let [a,...b] = [1,2,3]
    // a=1 b=[2,3]
    

2.3 Symbol

原始数据类型,表示独一无二的值,用来定义对象唯一属性名

let sy = Symbol("kk")
let sy2 = Symbol("kk")
sy === sy1 //false
typeof(sy)  //sysbol
console.log(sy) //Symbol(kk)
  • 属性名的用法

    let sy = Symbol("key1")
    //用法1
    let syObject = {}
    syObject[sy] = "kk"
    console.log(syObject) //{Symbol(key1): "kk"}
    //用法2
    let syObject = {
    	[sy]: "kk"
    }
    //用法3
    let syObject = {}
    Object.defineProperty(syObject, sy,{value: "kk"})
    
  • Symbol作为属性名时不能用.运算符,要用方括号

  • Symbol作为属性名时,该属性是公有属性,不是私有属性。循环无法读取,只能通过Object.getOwnPropertySymbols()和Reflect.ownKeys()取到

Symbol.for()

类似单例模式

let yellow = Symbol.for("Yellow")
let yellow1 = Symbol.for("Yellow")
yellow === yellow1 //true

Symbol.keyFor()

返回一个已登记的Symbol类型的值的key,用来检测字符串参数作为名称的Symbol值是否被登记

3.1.1 Map与Set

Map对象

Map对象保存键值对,任何值都可以作为一个键或一个值

Map中的key

  • key是字符串

    var myMap = new Map()
    var keyString = "a string"
    myMap.set(keyString, "xiong")
    myMap.get(keyString) //xiong
    myMap.get("a string") //xiong
    
  • key是对象

    var myMap = new Map()
    var keyObj = {}
    myMap.set(keyObj,"xiong")
    myMap.get(keyObj) //xiong
    myMap.get({}) //undefined 因为keyObj !== {}
    
  • key是函数

    var myMap = new Map()
    var keyFunc = function(){}
    myMap.set(keyFunc,"xiong")
    myMap.get(keyFunc) //xiong
    myMap.get(functin(){})//undefined
    
  • key是NaN

    var myMap = new Map()
    myMap.set(NaN,"not a number")
    myMap.get(NaN) //not a number
    
    var otherNaN = Number("foo")
    myMap.get("otherNaN")//not a number
    //虽然NaN和任何值甚至自己都不相等(NaN!==NaN返回true),NaN作为Map的键来说是没什么区别的
    

Map的迭代

  • for…of

    var mayMap = new Map()
    myMap.set(0,"zero")
    myMap.set(1,"one")
    //"0=zero","1=one"
    for(var [key, value] of myMap){
    	console.log(key + "=" + value)
    }
    for(var [key, value] of myMap.entries()){
    	console.log(key + "+" + value)
    }
    //"0","1"
    for(var key of myMap.keys()){
    	console.log(key)
    }
    //"zero","one"
    for(var value of myMap.values()){
    	console.log(value)
    }
    
  • forEach()

    var myMap = new Map()
    myMap.set(0,"zero")
    myMap.set(1,"one")
    //"0=zero", "1=one"
    myMap.forEach(function(value,key)){
    	console.log(key + "=" + value)
    }
    

Map对象的操作

  • Map与Array的转换

    var kvArray=[["key1", "value1"],["key2"],"value2"]
    //Map构造函数可以将二维键值对数组转换成一个Map对象
    var myMap = new Map(kvArray)
    //使用Array.form函数可以将一个Map对象转换成一个二维键值对数组
    var outArray = Array.from(myMap)
    
  • Map的克隆

    var myMap1 = new Map([["key1", "value1"],["key2", "value2"]])
    var myMap2 = new Map(myMap1)
    
  • Map的合并

    var first = new Map([[1,'one'],[2,'two'],[3,'three']])
    var second = new Map([[1,"umo"],[2,'dos']])
    //合并两个Map对象是,如果有重复的键值就不会覆盖前面的
    var merged = new Map([...first, ...second])
    

Set对象

允许修改任何类型的唯一值,无论是原始值或者是对象索引,set对象存储的值总是唯一的

  • +0和-0,undefined和undefined不重复,NaN和NaN不恒等,Set中只能存一个

    let mySet = new Set()
    mySet.add(1)
    mySet.add(2)
    mySet.add("some text")
    var o = {a: 1, b: 2}
    mySet.add(o)
    mySet.add({a:1, b: 2})
    //{1,2,"some text",{...},{....}}
    
  • 类型转换Array

    //Array转set
    var mySet = new Set(["value1", "value", "value3"])
    //用...操作符,将Set转Array
    var myArray = [...mySet]
    //String转Set
    var mySet = new Set("hello")
    
  • Set对象的作用

    • 数组去重

      var mySet = new Set([1,2,3,4,4])
      [...mySet]
      
    • 并集

      var a = new Set([1,2,3])
      var b = new Set([4,3,5])
      var union = new Set([...a,...b])//{1,2,3,4,5}
      
    • 交集

      var a = new Set([1,2,3])
      var b = new Set([2,3,4])
      var intersect = new Set([...a].filter(x=>b.has(x)))
      
    • 差集

      var a = new Set([1,2,3])
      var b = new Set([2,3,4])
      var difference = new Set([...a].filter(x=>!b.has(x)))//{1}
      

3.1.2 Reflect与Proxy

Proxy基本用法

一个Proxy对象有两个部分组成:target、handler。target即目标对象,handler是一个对象声明了代理target的指定行为

let target = {
	name: "tom",
	age: 24
}
let handler = {
	get: functin(target,key){
		return target[key]
	},
	set: function(target, key, value){
		target[key] = value
	}
}
let proxy = new Proxy(target,handler)
proxy.name //实际执行 handler.get
proxy.age  //实际执行 handler.set

//target为空对象
let targetEpt = {}
let proxyEpt = new Proxy(targetEpt, handler)
proxyEpt.name //向目标对象添加了name属性
proxyEpt.name = "Tom" //setting name "Tom"

//handler 对象为空,相当于不设置拦截操作,直接访问目标对象
let targetEmpty = {}
let proxyEmpty = new Proxy(targetEmpty, {})
proxyEmpty.name="Tom"
targetEmpty //{name: "Tom"}

3.2.1 字符串

扩展的方法

  • include():判断是否包含参数字符串
  • startsWith():判断参数字符串是否在原字符串头部
  • endsWith():判断参数字符串是否在原字符串尾部

字符串的重复

repeat():返回新的字符串,表示将字符串重复指定次数返回

  • 如果参数是小数,向下取整

    console.log("xiong".repeat(3.2)) //"xiong,xiong,xong,"
    
  • 如果参数是NaN,等同于repeat零次

  • 如果参数是负数或者Infinity,会报错

  • 如果参数是字符串,会将字符串转化为数字

字符串的补全

  • padStart:参数字符串从头部补全原字符串

  • padEnd:参数字符串从尾部补全原字符串

    console.log("h".paddStart(5,"o"))  //"ooooh"
    console.log("h".padEnd(5,"x"))  //"hoooo"
    console.log("h".padEnd(5))		// "h    "
    
    • 如果指定长度小于或者等于原字符串的长度,则返回原字符串
    • 如果原字符串加上补全的字符串长度大于指定长度,则截去超出的位数的字符串

模板字符串

反引号``,普通字符串,多行字符串,可加入变量和表达式

  • 字符串中插入变量和表达式和调用函数,变量名写在 中 , {}中, {}中可以放入JavaScript表达式

    let name = "xiong"
    let age = 20
    let info = "my name is ${name},my age is ${age+1}"
    //调用函数
    function f(){
    	return "have fun!"
    }
    let String = `game is ${f()}`
    
  • 模板字符串中的换行和空格都是会被保留的

标签模板

alert`hello xiong`
alert('hello xiong')

3.2.2 数值

数值的显示

  • 二进制新写法:前缀0b或0B
  • 八进制新写法:前缀0o或0O

常量Number.EPSILON

测试数值是否在误差的范围内

0.1 + 0.2 === 0.3 //false
equal = (Math.abcs(0.1 + 0.2 - 0.3 < Number.EPSILON))

最大/最小安全整数

安全整数的范围在2的-53次方到2的53次方之间(不包含两个端点),否则无法精确表示

Number方法

  • 检查数值是否为有限的(finite),NaN不是有限的,所有非数值都返回false,不存咋转换
Number.isfinite() 
//检查一个值是否为NaN
Number.isNaN(NaN) //true
//全局的isNaN()中,判断前会将非数值向数值转换,Number.isNan()中不会
Number.isNaN("NaN") //false
  • Number.parseInt:将字符串转化为指定进制的整数

    Number.parseInt('12.34')  //12
    //指定进制
    Number.parseInt('0011', 2) //3
    //与全局的parseInt()函数是同一个函数
    Number.parseInt === parseInt //true
    
  • Number.parseFloat

    将字符串解析成浮点数

    Number.parseFloat('123.45') //123.45
    Number.parseFloat('123.45abc') //123.45
    //无法解析成浮点数返回NaN
    Number.parseFloat('ajf') //NaN
    //与全局的parseFloat()方法是同一个方法
    Number.parseFloat === parseFloat //true
    
  • Number.isInteger()

    判断给定的参数是否为整数,NaN和正负InFnity不是整数,不存在转换

    Number.isInteger(1)   //true
    Number.isInteger(1.0) //true
    Number.isInteger(1.2) //false
    
  • Number.isSafeInteger()

    用于判断数值是否在安全范围内,由于上一个判断数值小于JavaScript能够分辨的最小值,会被自动转换为0,会误判

    Number.isSafeInteger(Number.MIN_SAFE_INTEGER - 1) //false
    Number.isSafeInteger(Number.MAX_SAGE_INTEGER + 1) //false
    

Math对象的扩展

新增了17个数学相关的静态方法,只能在Math中调用

  • 普通计算

    • Math.cbrt

      计算一个数的立方根,会对非数值进行转换,无法转换数值是返回NaN

      Math.cbrt('1') //1
      
    • Math.imul

      两个数以32位带符号整数形式相乘的结果,返回的也是32位

      Math.imul(1,2) //2
      
    • Math.hypot

      计算所有参数的平方和的平方根,非数值会转换为数值,空值和空数组会转换为0,无法转换是返回NaN,参数为正负Infinity返回Infinity

      Math.hypot(3,4) //5
      
    • Math.clz32

      返回数字的32位无符号整数形式的前导0的个数,参数为小数是,只考虑整数部分,空值,空数组,空对象,正负Infinity,NaN,undefined,‘fff’(非数值字符串)都会转换为0,非数值会转换为数值

      Math.clz32(0) //32
      Math.clz32(1) //31
      Math.clz32(0.5) //32
      

    数字处理

    • Math.trunc

      返回数字整数部分,会判断符号,非数值会转换为数值,空值或者无法转换为数值时返回NaN

      Math(12.3) //12
      Math.trunc(-0.5) //-0
      
    • Math.fround

      获取数字的32位单精度浮点数形式,参数位非数值时会进行参数的转换,true 1,false 2,null和空数组为1,空对象为NaN

      //对于2的24次方取负至2 的 24 次方之间的整数(不含两个端点),返回结果与参数本省一致
      Math.fround(-(2**24)+1) //-16777215
      Math.fround(2**24-1) //16777215
      //将64位双精度浮点数转为32位单精度浮点数
      Math.fround(1.234) //1.235
      //当小数精确度超过24个二进制位会丢失精度
      Math.fround(0.3) //0.300000001192092896
      
    • Math.sign

      判断数字的符号,判断前会对非数值进行转换,无法转换时返回NaN

      Math.sign(0) //0
      Math.sign(-0) //-0
      

    对数方法

    • Math.expm1()

      计算e的x次方减1的结果,即Math.exp(x)-1,会对非数值进行转换,无法转换返回NaN

      Math.expm1(1) //1.718281828459045
      Math.expm1(0) //0
      Math.expm1(-1) // -0.6321205588285577
      
    • Math.log1p(x)

      用于计算1+x的自然对数,即Math.log(1+x),当参数小于-1时返回NaN,会转换

      Math.log1p(1) //0.6931471805599453
      Math.log1p(0) //0
      Math.log1p(-1) //-Infinity
      
    • Math.log10(x)

      计算以10为底的对数,会转换,参数为0时返回-Infinity,小于0时返回NaN

      Math.log10(1) //0
      
    • Math.log2(x)

      与以10为底的相同

    双曲函数方法

    • Math.sinh(x) 计算双曲正弦
    • Math.cosh(x) 计算双曲余弦
    • Math.tanh(x) 计算双曲正切
    • Math.asinh(x) 计算反双曲正弦

3.2.3 对象

对象字面量

  • 属性的简写

    ES6允许属性直接写变量,属性名就是变量名,属性值时变量值

    const age = 12
    const name = "amy"
    const person = {age,name}
    person {age:12, name: "amy"}
    
  • 方法名的简写

    const person = {
    	sayHi(){
    		console.log("hi")
    	}
    }
    //等同
    const person = {
    	sayhi:function(){
    		console.log("hi")
    	}
    }
    
    • Generator函数

      const obj = {
      	*myGenerator(){
      		yield 'Hello xiong'
      	}
      }
      //等同
      const obj = {
      	myGenerator: function*(){
      		yield 'Hello xiong'
      	}
      }
      
  • 属性名表达式

    • 表达式需要放在方括号内

      const obj = {
      	['he' + 'llo'](){
      		return "xiong"
      	}
      }
      obj.hello()
      
    • 属性名的简洁表示法和属性名表达式不饿能同时使用

      const xiong = "xiong"
      const obj = {
      	[xiong + "2"] : "world"
      }
      obj //{xiong2: "world"}
      

对象扩展运算符

(…)

  • 拷贝

    let person = {name: "xiong", age: 22}
    let someone = {..person}
    
  • 合并

    let age = {age: 22}
    let name = {name: "xiong"}
    let person = {...age, ...name}
    person {age: 22, name: "xiong"}
    
  • 覆盖

    后面会覆盖前面的同名属性,如果前面是空对象,…null,…undefined没有效果

    let person = {name: "xiong", age: 22}
    let someone = {...person, name: "Mike", age: 18}
    

对象新方法

  • Object.assign(target, source_1,…)

    将源对象的所有可枚举的属性赋值到目标对象中,同名属性后面会覆盖前面

    let a = {a: 1}
    let b = {b: 2}
    let c = {c: 3}
    Object.assign(a,b,c)
    a {a: 1, b: 2, c: 3}
    
  • 参数不是对象是,会将参数转换为对象然后返回。参数为null和undefined时报TypeError,不放在第一个作为目标对象,则不会报错

    Object.assign(3) //Number{3}
    typeof Object.assign(3) //Object
    
  • 注意点

    • assign的属性拷贝时浅拷贝

    • 同名属性的替换,覆盖掉属性里的所有值

      let xiong = {a: {b: 1, c: 2}}
      let hua = {a: {b: "cai"}}
      Object.assign(xiong,hua)
      xiong //{a: {b: "cai"}}
      
    • 数组的处理

      Object.assign([2,3],[5])
      //数组会先变成对象{0:2,1:3}
      
  • Object.is(value1,value2)

    用于比较两个值是否严格相等,与(===)基本类似

    Object.is(+0,-0) //false
    +0 === -0 //true
    Object.is(NaN,NaN) //true
    NaN ===NaN //false
    

3.2.4 数组

数组创建

  • Array.of()

    将所有参数值作为元素形成数组,没有参数时返回空数组

    Array.of(1,'2',true) //[1,'2',true]
    
  • Array.from()

    将类数组对象或可迭代对象转化为数组

    Array.form([1,2,,3]) //[1,2,undefined,3]
    
  • 参数

    Array.form(arrayLike[,mapFn[,thisArg]]) : 想要转换的类数组对象或可迭代对象,mapFn用于对每个元素进行处理,用于指定map函数执行时的this对象

    let map = {
    	do: function(n){
    		return n*2
    	}
    }
    let arrayLike = [1,2,3]
    Array.form(arrayLike,function(n){return this.do(n)},map) //[2,4,6]
    
  • 类数组对象

    含有length属性,属性名必须可以转换为数值或数值。没有length属性返回空数组,如果属性名无法转换为数值,返回长度为length元素值为undefined的数组

    let arr = Array.from({
    	0: '1',
    	1: '2',
    	2: 3,
    	length: 3
    })
    
  • 转换可迭代的对象

    • 转换map

      let map = new Map()
      map.set('key0': 'value0')
      map.set('key1': 'value1')
      Array.form(map) //[['key0','value0'],['key1','value']]
      
    • 转换set

      let arr = [1,2,3]
      let set = new Set(arr)
      Array.from(set) //[1,2,3]
      
    • 转换字符串

      let str = 'abc'
      Array.form(str) //["a","b","c"]
      

扩展的方法

  • 查找

    • find()

      符合条件的第一个元素

      let arr = Array.of(1,2,3,4)
      arr.find(item => item >2) //3
       [,1].find(n=>true) //undefined
      
    • findIndex()

      符合条件的第一个元素的索引

      let arr = Array.of(1,2,4,5)
      arr.findIndex(item => item == 2) //1
      [,1].findIndex(n=>true) //0
      
  • 填充

    • fill(a,b,c):a用来填充 的值,b被填充的开始索引,c可选被填充的结束索引

      let a = Array.of(1,2,3,4)
      a.fill(0,1,2) //[1,0,3,4]
      
    • copyWithin() :将一定范围索引的元素修改为另一指定范围索引的元素

      [1,2,3,4].copyWithin(0,2,4)//被修改的起始索引,被用来覆盖的数据的起始索引,可选被用来覆盖的数据的结束索引,默认为数组末尾
      
  • 遍历

    • entries()

      遍历键值对

      for(let [key, value] of ['a', 'b'].entries()){
      	console.log(key,value) //0 "a"   1 "b"
      }
      
      let entries = ['a', 'b'].entries()
      entries.next().value //[0, "a"]
      entries.next().value //[1, "b"]
      
      [...[, 'a'].entries()] //[[0,undefined], [1, "a"]]
      
    • keys()

      遍历键名

      for(let key of ['a', 'b'].keys()){
      	console.log(key) //0  1
      }
      
    • values()

      遍历键值,如果含空位则输出undefined

      for(let value of ['a', 'b'].values()){
      	console.log(value) //"a"   "b"
      }
      
  • 包含

    • includes()

      数组是否包含指定值 ,可以判断NaN

      [1,2,3].includes(1) //true
      [1,2,3].includes(1,2) //false 在指定索引处开始检索
      
  • 嵌套数组转一维数组

    • flat():自动跳过空位

      [1,2,[3,4]].flat() //[1,2,3,4]
      //可以指定要转换的嵌套的层数,Infinity是不管嵌套多少层都解析
      flat(2) flat(Infinity)
      
    • flatMap(): 对数组中每个元素进行处理后再执行flat()方法

      [1,2,3].flatMap(n => [n*2]) //[2,4,5]
      

数组缓冲区

内存中的一段地址,定型数组的基础,创建后只可修改其中的数据,不可修改大小

  • 通过构造创建数组缓冲区

    let buffer = new ArrayBuffer(10)
    buffer.byteLength //10
    //分割已有的数组缓冲区
    let buffer = new ArrayBuffer(10)
    let buffer = buffer.slice(1,3)
    buffer1.byteLength //2
    
  • 视图

    用来操作内存的接口

    • 创建

      let buffer = new ArrayBuffer(10)
      dataView = new DataView(buffer)
      dataView.setInt8(0,1)
      data.getInt(0) //1
      //通过设定的偏移量与长度指定DataView可操作的字节范围
      let buffer1 = new ArrayBuffer(10)
      dataView1 = new Dataview(buffer1,0,3)
      dataView1.setInt(5,1) //RangeError
      
  • 定型数组

    数组缓冲区的特定类型的视图

    • 创建 不传参时默认长度为0,可接收参数有定型数组,可迭代对象,数组,类数组对象

      //通过数组缓冲区生成
      let buffer = new ArrayBuffer(10)
      view = new Int8Array(buffer)
      view.byteLength //10
      //通过构造函数
      let view = new Int32Array(10)
      view.byteLength //40
      view.length //10
      
    • 注意要点

      • length不可修改,严格模式下抛出错误

      • 定型数组可食用entries(),keys(),values()进行迭代

        let view = new Int16Array([1,2])
        for (let [k, v] of view.entries()){
        	console.log(k,v)
        }
        //0 1
        //1 2
        
      • find() 等方法也可用于定型数组

      • 所有定型数组都含有of()方法和from()方法,运行方法和Array.from()方法相似

      • 定型数组新增了set()和subarray()方法,前者将其他数组赋值到已有的定型数组,后者提取已有的定型数组的一部分形成新的定型数组

        let view = new Int16Array(4)
        view.set([1,2])
        view.set([3,4],2)
        view //[1,2,3,4]
        //subarray
        let view = new Int16Array([1,2,3,4])
        view.subarray() //[1,2,3,4]
        view.subarray(1) //[2,3,4]
        view.subarray(1,3) //[2,3]
        

扩展运算符

  • 复制数组:空位会转换为undefined

    let arr = [1,2]
    arr1 = [...arr]
    

4.1 函数

函数参数的扩展

  • 默认参数:不能有同名参数

    function fn(name,age=22){
    	console.log(name + "," + age)
    }
    
    • 不能有同名参数
    • 只有未传递参数或者参数为undefined时,才使用默认参数
  • 不定参数

    function f(...value){
    	console.log(value.length)
    }
    f(1,2) //2
    

箭头函数

参数=>函数体

  • 多行语句时用{}包裹起来

  • 返回对象时,为了区分代码块,要使用({id: id, name: name})包裹起来

  • 没有this,super,arguments,new.target绑定

  • 箭头函数的对象时定义函数时的对象

  • 不适合使用的场景

    var Person = {
        'age': 18,
        'sayHello': ()=>{
            console.log(this.age);
          }
    };
    var age = 20;
    Person.sayHello();  // 20
    // 此时 this 指向的是全局对象
     
    var Person1 = {
        'age': 18,
        'sayHello': function () {
            console.log(this.age);
        }
    };
    var age = 20;
    Person1.sayHello();   // 18
    

4.2 迭代器

Iterator

  • 统一的接口
  • 遍历数据结构元素的指针

迭代过程

  • 通过Symbol.iterator创建迭代器

    const items = ["zero", "one"]
    const it = items[Sysmbol.iterator]
    
  • 通过next防范进行向下迭代

    it.next()
    >{value: "zero", done: false}
    it.next()
    >{value: "one", done: true}
    it.next()
    >{value: undefined, done: true} //done为true时访问结束
    

可迭代数据结构

Array, String, Map, Set ,Dom元素

for (let item of ["zero", "one", "two"]) {
  console.log(item);
}
// output:
// zero
// one
// two

普通对象不可迭代

//TypeError
for(let item of {}){
	console.log(item)
}

for…of 循环

用于迭代常规的数据类型,Array,String,Map,Set

  • keys, values, entries

    // 只遍历 key 值
    for (let key of mySet.keys()) {
      console.log(key);
    }
     
    // 只遍历 value
    for (let value of mySet.values()) {
      console.log(value);
    }
     
    // 遍历 key 和 value ,两者会相等
    for (let [key, value] of mySet.entries()) {
      console.log(key + " = " + value);
    }
    

可迭代数据结构

  • of操作数必须是可迭代的,普通对象无法进行迭代,可借助Array.from方法进行转换迭代

    const arrayLink = {length: 2, 0: "zero", 1: "one"}
    //报TypeError异常
    for(let item of arryLink){
    	console.log(item)
    }
    
    //正常运行
    //output:
    //zero
    //one
    for(let item of Array.form(arrayLink)){
    	console.log(item)
    }
    
  • let, const, var用于for…of

    • 使用let和const,每次迭代会创建一个新的存储空间

      const nums = ["zero", "one", "two"];
       
      forv (var num of nums) {
        console.log(num);
      }
      // output: two  如果使用let和const会报ReferenceError
      console.log(num); 
      

4.3 Class类

class作为模板引用,本质是function

基本用法

  • 类定义:类表达式可以为匿名或命名

    //匿名
    let Example = class {
    	constructor(a){
    		this.a = a
    	}
    }
    //命名
    let Example = class Example{
    	constructor(a){
    		this.a = a
    	}
    }
    
  • 类声明

    • 不可重复声明
    • 类定义不会提升,不可在类没有定义前访问
    • 类中方法不需要function关键字
  • 类的主体

    • 属性:prototype

      //覆盖方法/初始化时添加方法
      Example.prototype={//methods}
      //添加方法
      Object.assign(Example.prototype,{//methods})
      
      • 静态属性

        直接定义在类内部的属性(Class.propname),不需要实例化。ES6中Class内部只有静态方法,没有静态属性。(疑问)

        class Example {
        //新提案
        	static a=2
        }
        //目前可行写法
        Example.b = 2
        
      • 公共属性

        class Example{}
        Example.prototype.a = 2
        
      • 实例属性(实例对象(this)上的属性)

        class Example {
        	a = 2
        	constructor(){
        		console.log(this.a)
        	}
        }
        
      • name属性,跟在class后的类名

        let a = class Exa{
        	contructor(a){
        		this.a = a
        	}
        }
        a.name //Exam
        
    • 方法

      • 类的默认方法constructor,实例化对象时被调用

      • 返回对象:默认返回实例对象,也可指定返回对象

      • 静态方法:方法前带static

      • 原型方法:不带任何东东

      • 实例方法

        class Example{
        	constructor(){
        		this.sum = (a,b) => {
        			console.log(a + b)
        		}
        	}
        }
        

类的实例化

  • new:class的实例化必须通过new关键字

  • 实例化对象

    • 共享原型对象

      class Example{
      	constructor(a,b){
      		this.a = a
      		this.b = b
      	}
      	sum(){
      		return this.a + this.b
      	}
      }
      let exam1 = new Example(2,1)
      let exam2 = new Example(3,1)
      exam1._proto_ == exam2._proto_ //true
      exam1._proto_.sub = function(){
      	return this.a - this.b
      }
      exam1.sub() //1
      exam2.sub() //2
      

decorator

  • 函数,修改类的行为,在代码翻译时产生作用

类修饰

  • 一个参数:第一个参数target,指向类本身

     function testable(target){
     	target.isTestable = true
     }
     @testable
     class Example{}
     Example.isTestable //true
    
  • 多个参数-嵌套实现

    function testable(isTestable){
    	return function(target){
    		target.isTestable=isTestable
    	}
    }
    @testable(true)
    class Example{}
    Example.isTestable //true
    

方法修饰

  • target(类的原型对象),name(修饰的属性名),descriptor(该属性的描述对象)

    class Example{
    	@writable
    	sum(a,b){
    		return a + b
    	}
    }
    function writable(target, name, descriptor){
    	descriptor.writable = false
    	retrun descriptor //必须返回
    }
    
  • 修饰器执行顺序:由外向内进入,由内向外执行

    class Example{
    	@logMethod(1)
    	@logMethod(2)
    	sum(a, b){
    		return a + b
    	}
    }
    function logMethod(id){
    	console.log('evl' + id)
    	return (target, name,descriptor) => console.log('exl' + id)
    }
    //evl 1
    //evl 2
    //exl 2
    //exl 1
    

封装与继承

  • getter/setter

    class Example{
    	constructor(a,b){
    		this.a = a;
    		this.b = b;
    	}
    	get a(){
    		return this.a
    	}
    	set a(){
    		this.a = a
    	}
    } 
    
    • getter与setter必须同时出现
  • extends:类的继承

  • super:子类constructor方法中必须有super,必须扎this之前

    • 调用父类的构造函数只能出现在子类的构造函数

    • 调用父类方法,super作为对象,在普通方法中,指向父类的原型对象,在静态方法中指向父类

      class Child2 extends Father {
          constructor(){
              super();
              // 调用父类普通方法
              console.log(super.test()); // 0
          }
          static test3(){
              // 调用父类静态方法
              return super.test1+2;
          }
      }
      Child2.test3(); // 3
      
  • 注意要点

    //不可继承常规对象
    var Father = {
    }
    class Child extends Father {
    }
    // Uncaught TypeError: Class extends value #<Object> is not a constructor or null
    //解决方案
    Object.setPrototypeOf(child.prototype, Father)
    

4.4 模块

export与import

  • 导出的函数和类声明必须有名称(export default命令另外考虑)
  • export命令可以出现在模块任何位置,但必须处于模块顶层
  • import命令会提升到整个模块的头部,必须先执行

as的用法

  • export命令导出的接口名称,必须和内部的变量有一一对应的关系
  • 不同的模块导出接口名称重复,使用as重新定义变量名

import命令的特点

  • 只读:可以该写import变量类型为对象的属性值,不能给些import变量类型为基本类型的值

    import {a} from "./xxx.js"
    a = {}; // error
     
    import {a} from "./xxx.js"
    a.foo = "hello"; // a = { foo : 'hello' }
    
  • 多次执行同一句import语句,只会执行一次

  • import是静态的,不能使用表达式和变量

export default命令

  • exportport default仅有一个
  • 通过export方式导出,导入时需要加{},export default则不需要
  • export default 向外暴露成员,可以使用任意变量接收

5.1 Promise对象

异步变成的有一种解决方案

Promise状态

状态的特点

  • pending(进行中)、fulfilled(已成功)、rejected(已失败)

  • 只有处于fulfilled和rejected,状态就不会在变了,即resolved(已定型)

    const p1 = new Promise(function(resolve,reject){
    	resolve('success1')
    	resolve('success2')
    })
    const p2 = new Promise(function(resolve,reject){
    	resolve('success3')
    	reject('reject')
    })
    p1.then(function(value){
    	console.log(value) //success1
    })
    p2.then(function(value){
    	console.log(value) //success3
    })
    

状态的缺点

  • 一旦创建,无法取消
  • 没有回调函数,Promise内部抛出的错误,不会反应到外部
  • 处于pending转态时,无法得知目前进展到哪一个阶段

then方法

两个参数(函数),Promise执行成功时的回调,Promise执行失败时的回调,只有一个被调用

then方法的特点

  • JavaScript事件队列的当前运行完成之前,回调函数永远不会被调用

    const p = new Promise(function(resolve, reject)){
    	resolve('success')
    }
    p.then(function(value){
    	console.log(value)
    })
    console.log('first')
    //first
    //success
    
  • 通过.then形式添加的回调函数,都会被调用

  • 添加多个回调函数,会按照顺序并且独立运行

    const p = new Promise(function(resolve,reject){
      resolve(1);
    }).then(function(value){ // 第一个then // 1
      console.log(value);
      return value * 2;
    }).then(function(value){ // 第二个then // 2
      console.log(value);
    }).then(function(value){ // 第三个then // undefined
      console.log(value);
      return Promise.resolve('resolve'); 
    }).then(function(value){ // 第四个then // resolve
      console.log(value);
      return Promise.reject('reject'); 
    }).then(function(value){ // 第五个then //reject:reject
      console.log('resolve:' + value);
    }, function(err) {
      console.log('reject:' + err);
    });
    

then方法注意点

  • 不要嵌套Promise
  • 大多数浏览器不会终止Promise链里的rejection,后面跟上.catch(error => console.log(error))

5.2 Generator函数

可以通过yield关键字,把函数的执行流挂起

Generator函数组成

  • 在function后面函数名之前有个*

  • 函数累不有yeild表达式

    function* function(){
    	console.log("one")
    	yield '1'
    	console.log("two")
    	return '2'
    }
    

执行机制

  • 不会立即执行,返回一个指向内部状态对象的指针,所以要调用遍历对象Iterator的next方法

    f.next()
    //one
    //{value: "1", done": false}
    f.next()
    //two
    //{value: "3", done: true}
    

函数返回的遍历器对象的方法

  • next方法:传参和不传参的区别、

    function* sendParameter(){
    	console.log("start")
    	var x = yeild '2'
    	console.log("one:" + x)
    	var y = yield '3'
    	console.log("two:" + y)
    	console.log("total:" + (x + y))
    }
    
    var sendp1 = sendParameter();
    sendp1.next();
    //start
    //{value: "2", done: false}
    sendp1.next()
    //one:undefined
    //{value: "3", done: false}
    dendp1.next()
    //two:undefined
    //total: NaN
    //{value: undefined, done: true}
    
    next传参
    var sendp2 = sendParameter()
    sendp2.next(10)
    //start
    //{value: "2", done: false}
    sendp2.next(20)
    //one:20
    //{value: "3", done: false}
    sendp2.next(30)
    //two: 30
    //total: 50
    //{value: undefined, done: true}
    
  • return

    • return方法返回给定值,并结束遍历Generator函数
    • return方法提供参数是,返回该参数,不提供参数是返回undefined
  • yeild* 表达式

    • yield*表达式表示yield返回一个遍历器对象,用于Generator函数累不,调用另一个Generator

      function* callee(){
      	console.log('callee:' + (yield))
      }
      functino* caller(){
      	while(true){
      		yield* callee()
      	}
      }
      const callerObj = caller()
      callerObj.next()
      //{value: undefined, done: fasle}
      callerObj.next("a")
      //callee: a
      //{value: undefined, done: false}
      callerObj.next("b")
      //callee: b
      {value: undefined, done: false}
      
      //等同于
      function* caller(){
      	while(true){
      		for(var value of callee){
      			yield value
      		}
      	}
      }
      

使用场景

  • 实现Iterator

    为不具备Iterator接口的对象提供遍历方法

    function* objectEntries(obj){
    	const propKeys = Reflect.ownKeys(obj)
    	for (const propKey of propKeys){
    		yield [propKe, obj[propKey]]
    	}
    }
    const jane = {first: 'Jane', last: 'Doe'}
    for (const[key, value] of objectEntries(jane)){
    	console.log(`${key}: ${value}`)
    }
    //first: Jane
    //last: Doe
    

5.3 async 函数

async

ES7才有的与异步操作有关的关键字

语法

  • name:函数名称
  • param: 要传递给函数的参数的名称
  • statements:函数体语句

返回值

async返回一个Promise对象,可以使用then方法添加回调函数

async function helloAsync(){
	return "helloAsync"
}
helloAsync() //Promise{<resolved>: "helloAsync"}
helloAsync().then(v=>{
	console.log(v) //helloAsync
})
  • await表达式:遇到await暂停执行,触发异步操作完成后,回复async函数的执行并返回解析值

  • await关键字仅在async function中有效,之外的话报语法错误

await

  • 操作符用于等待一个Promise对象,只能在异步函数async function内部使用

  • 语法

    [return_value] = await expression  //expression: 一个Promise对象或者任何要等待的值
    
  • 返回值

    • 返回Promise对象的处理结果,不是的话返回该值本身

    • 如果一个Promise被传递给一个await操作符,await将等待Promise正常处理完成并返回处理结果

      function testAwait(x){
      	return new Promise(resolbe => {
      		setTimeout(() => {
      			resolve(x)
      		},2000)
      	})
      }
      async function helloAsync(){
      	var x = await testAwait("hello world")
      	console.log(x)
      }
      helloAsync()
      // hello world
      
    • await命令后面是一个Promise对象,也可以跟其他值,字符串,布尔值,数值,以及普通函数

      functin testAwait(){
      	console.log("testAwait")
      }
      async function helloAsync(){
      	await testAwait();
      	console.log("helloxiong")
      }
      helloAsync()
      //testAwait
      //helloAsync