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
-