前段时间在学习es6,整理下笔记。
1.变量和常量的声明
变量的声明
1.let声明变量
let 声明的变量只在其所在的代码块内有效 for循环的设置条件的是父作用域 里面的是子作用域 是独立的
2.let不存在变量提升 需先声明再调用 否则会报错
3.暂时性死区:在块级作用域里面存在let命令 那么就绑在在此作用域 不受外界的影响
eg:typeof x;//报错
let x;
eg:typeof x //undefined 即一个变量未被声明 那么就不会报错
注意:函数传参的时候 要注意先后顺序 注意暂时性死区导致的报错
声明的注意点:需先声明再使用 在同一个作用域中不能重复声明一个变量否则会报错
需要块级作用域的优点 解决的问题有::1.es5函数内层变量可能会覆盖外层变量 2.用来循环计数的变量泄露为全局变量
4.es6块级作用域
1.允许作用域的多层嵌套 但是外部作用域不能访问内部作用域的变量
2.不同作用域或者嵌套作用域声明的变量名可相同
3.允许在块级作用域里面定义函数 但是必须有{}包着 否则会报错
5.块级作用域没有返回值 解决方法是使用do表达式 那么x是等于执行的最后一句的结果即x=t*t+1
let x = do{
let t = f();
t*t+1;
}
注意:es6有6种声明变量方式 es5只有var/function2种
常量的声明
1.const PI = 3.1415 在声明的时候必须初始化 一旦声明就不能再改变 重复声明同一个常量第二次会报错
2.作用域和暂时性死区 也不会提示声明的常量 这些与变量的声明规则一样
重点:const实质不是不能改动值,而是变量指向的那个内存地址不能改变
简单数据类型=>值保存在变量指向的那个内存地址 因此等同于常量
复杂数据类型=>变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,不能保证它指向的数据结构的变化 所以 将一个对象声明为常量时必须非常小心
3.将对象冻结的方法使用Object.freeze方法 const foo = Object.freeze({});
冻后 不能给该对象添加属性和方法 常规模式下添加属性不起作用 严格模式下添加会报错
对象的属性也可以彻底冻结 百度即可
2.顶层对象
es5中js中顶层对象的属性与全局变量是等价的
导致的问题1.所以需要运行才能报出变量未声明的错误
2.且程序猿容易不知不觉就创建全局变量
3.顶层对象的属性是可以到处读写 这样不利于模块化开发
4.顶层对象是一个有实体含义的对象即窗口对象
Node里面顶层对象是global
为了解决顶层对象和全局属性等级为问题 es6规定var function声明的全局变量是属于顶层对象的属性 但是let const class声明的变全局变量不属于顶层对象的属性
1.全局环境中 this返回的是顶层对象
Node模块和ES6模块中 this返回的是当前模块
2.通过垫片库在所有环境拿到global 即import shim from 'stystem.global/shim';shim();
3.将顶层对象放入变量global即执行 import getGlobal from 'system.global';const global = getGlobal();
3.解构赋值
1.数组的解构赋值 即模式匹配赋值 注意:左右两边必须都是数组形式否则报错 左右的数量可以不相等 不相等的情况下会解析部分
let [a,b,c]=[1,2,3] //a=1 b=2 c=3
let [head,...tail]=[1,2,3,4]//head=1 tail=4
let [x,y,...z]=['a']//x='a' y=undefined z=[] 解构不成功值就是undefined
2.Set结构的解构赋值
let [x,y,z]=new Set(['a','b','c']);//x=a y=b z=c
注意:只有数据具有Iterator接口 那么都可以用数组形式的解构赋值
3.默认值
let[x,y='b']=['a'];//x=a y=b 注意:ws6内部使用严格相等运算符=== 只有当成员严格===undefined的时候 默认值才会有效;
let[x,y='b']=['a',2];//x=a y=2此时默认值是无效的 null===undefined是false;
如果默认值是一个表达式 那么这个表达式是惰性求值的,即若右边能取到值时那么表达式将不会执行,只有右边是undefined的时候表达式才会执行
默认赋值的时候需确认该变量必须已经声明
4.对象的解构赋值 对象的属性没有次序但是变量必须与属性同名才能取到正确的值
let {x,y}={y:"yy",x:"xx"};//x=xx y=yy
5.如果要将一个已经声明的变量 用于解构赋值的话
let x;
{x}={x:1};//syntax error因为js会将{x}理解成一个代码块,从而发生语法错误
解决方法是let x; ({x}={x:1})
解构赋值允许等号左边不放置任何变量名 如下是可以执行的egg:({}=[ture,false]);({}='abc');({}=[])
6.字符串的解构赋值 字符串会被转换成一个类似数组的对象
7.数值和布尔值的解构赋值 如果等号右边是数值和布尔值 则会先转为对象
4.Iterator迭代器和for...of循环
Iterator迭代器
1.js元素的表示集合的数据机构是数组和对象 ES6添加了Map和Set一起4种我们组合使用来定义自己的数据解构,需要一种统一的接口机制来处理所有不同的数据解构 Iterator(遍历器)就是这样的一种机制,是一
种接口
2.Iterator的作用:1.为各种数据解构提供一个统一的简便的访问接口 2.使数据结构的成员按某种次序排列 3.以供遍历for...of循环消费
3.Iterator的遍历过程:1.创建一个指针对象 指向当前数据结构的起始位置 2.第一次调用指针对象的next方法,将指针指向数据结构的第一个成员 3.第二次调用next,指针指向第二个成员 4.不断调用next,指向数据结构的结束位置
4.默认Iterator接口 默认的Iterator接口部署在数据结构的Symbol.iterator属性需放[]里面[Symbol.iterator]
一种数据只要部署Iterator接口,那么就是可以遍历的
原生具有Iterator接口的数据有Array/Map/Set/String/TypedArray/函数的arguments对象/NodeList对象
let arr = [1,2,3];
let iter= arr[Symbol.iterator]();
iter.next();//{value:1,done:false}
iter.next();//{value:2,done:false}
iter.next();//{value:3,done:false}
iter.next();//{value:undefined,done:true}
5.调用Iterator接口的场合
1.解构赋值 let [x,y]=set
2.扩展运算符 [...str]
3.yield* eg:yield*[2,3,4]
4.其他场合 比如任何接受数组作为参数的场合
6.字符串的Iterator接口
字符串也有Iterator接口
7.Symbol.iterator接口与Generator函数 Symbol.iterator方法的最简单实现是使用Generator函数
8.遍历器对象的return() throw
自己定义遍历器对象生成函数时,next方法必须部署 return()和throw()方法可选部署
return方法的使用场合:for...of循环提前退出
触发return的3种情况:1.break 2.continue 3.throw new Error(
循环for...of
1.for...of循环是遍历所有数据结构的统一的方法 循环内部调用的是数据结构的Symbol.iterator方法
for...of使用的范围有Array/Set结构/Map结构/类似数组的对象/Generator对象/字符串
2. 允许直接拿到值
var arr = ['a','b'];
for(let a in arr){
console.log(a);//a b
}
3.只能拿到有数字索引的值
let arr = [3,5,7];
arr.foo='hello';
for(let i of arr){
console.log(i)//3 5 7 不能拿到索引是foo的hello
}
4.变量Set/Map结构数据的区别
遍历Set(是一个[1,2,3])返回的是值value 遍历Map(形式是[{"a":1},{"b":2}])返回的是一个数组[key,value]
5.计算生成的数据结构:有的数据结构是在现有数据结构的基础上计算生成的 比如数组/Set/Map都部署了以下3种方法,调用后都返回遍历器对象
entries()用来遍历[key,value]组成的数组
keys()用来遍历所有的健名
values()用来遍历所有的健值
6.对于字符串来说for...of会正确识别32位UTF-16字符
for(let x of 'a\uD83D\uDC0A'){
console.log(x);//a 和一个utf格式的啥东西
}
7.不是所有类似数组的对象都具有Iterator接口 解决方法是使用Array.from方法将其转为数组
let arrayLike= {length:2,0:"a",1:'b'};
for(let x of Array.from(arrayLike)){
console.log(x);//a b 不会打印2因为只识别是数字索引的值
}
8.对于普通的对象必须部署Iterator接口才能用for...of否则会报错
但是普通对象使用for...in可以用来遍历key
让其能使用for...of的解决方案有
方法1:使用Object.keys方法将对象的健名生成一个数组
let es= {
edition:6,
committee:"Tc",
standard:'Ecma'
};
for(let e of Object.keys(es)){
console.log(Object.keys(es));//["edition", "committee", "standard"]
console.log(e+":"+es[e])// edition:6等
方法2:使用Generator函数将对象重新包装一下
}
9.for...of与其他循环的比较
1.与原生的(var i = 0;i 2.与forEach比较 forEach使用break/continue都无法跳出循环
3.与for in比较
for in获取的是key 但是typeof key==string 会遍历
手动添加的其他键甚至原型链上的 有时候会以任意顺序遍历键名
注意:使用数组的时候 自定义添加的值会自动添加到数组的最后面 使用数组的方法会优先添加
4.for...in主要是用来遍历对象
5.正则的扩展
1.es6 语法var regexp=new RegExp(/abc/ig, 'i') 即允许第一个参数是正则 第二个参数是修饰符且会覆盖第一个参数的修饰符 变为/abc/i
2.字符串的正则方法
match()/replace()/search()/split()四种方法
3.u修饰符 含义是Unicode模式 用于正确处理大于\uFFFF的Unicode字符
1.点字符 对于码点大于0xFFFF的Unicode字符,点字符不能识别,必须加上u修饰符/^.$/u.test(s)
2.Unicode字符表示法 /\u{61}/u.test('a')必须加u否则会被解释为量词
3.量词 使用u修饰符后,所有量词都会正确识别码点大于0xFFFF的Unicode字符
4.预定义模式 /^\S$/u.test('')
5.i修饰符 /[a-z]/iu.test('\u212A')
4.y修饰符叫做“粘连”(sticky)修饰符。
5.sticky属性 表示是否设置了y修饰符
6.flags属性 返回正则表达式的修饰符 /abc/ig.flags=>gi
7.s修饰符:dotAll模式
8.后行断言 即x只有在y前面才匹配 必须写成/x(?=y)/
9.Unicode属性类 \p{...}和\P{...}
10.具名组匹配
6.数值的扩展
1.二进制和八进制的表示法
二进制:0b或者0B
八进制:0o或者0O
将0b 0o前缀的字符串数值转为十进制 使用Number方法 Number('0b111');
2.Number.isFinite()用来检查一个数值是否为有限的,即表示infinity 若蚕食表示数值则都返回false
Number.isNaN()用来检查一个值是否为NaN
3.ES6将parseInt()和parseFloat()移植到Number对象上面
Number.parseInt('12,34')//12
Number.parseFloat('123.45#')//123.45
4.Number.isInteger()用来判断一个数值是否为整数
在js内部整数和浮点数采用的是同样的储存方法 所以25/25.0被视为同一个值
Number.isInteger(25)//true
Number.isInteger(25.0)//true
使用此方法时若数值精度超过52个有效位 会误判
5.Number.EPSILON 表示1与大于1的最小浮点数之间的差
6.完全整数和Number.isSafeInteger()=>判断一个整数是否落在这个范围之内
7.Math对象的扩展
1.Math.trunc()用于去除一个数的小数部分,返回整数部分 对于null和无法截取整数的值,返回NaN
2.Math.sign()用来判断一个数到底是正数负数还是0
参数为正数返回+1
参数为负数返回-1
参数为0返回0
参数为-0返回-0
其他值返回NaN
3.Math.cbrt()用于计算一个数的立方根
4.Math.hypot()返回所有参数的平方和的平方根
对象方法
1.Math.expm1(x)
2.Math.log1p(x)
3.Math.log10(x)
4.Math.log2(x)
8.Math.signbit()用来判断一个数的正负符号位是否设置了
9.指数运算符**
2**2//4
let a=1.5;a **=2;//a=a*a
10.Integer数据类型
js的整数精确程度只能到53个二进制位,引进Integer(没有位数的限制)
Integer类型的数据必须使用后缀n表示 1n+2n//3n
typeof 123n//integer
Integer(123)//123n
运算:除法运算/会舍去小数部分,返回一个整数 9n/5n //1n
注意:Integer类型不能与Number类型进行混合运算 1n+1//报错
==会改变数据类型也不允许Integer类型不能与Number类型进行混合运算
===不会改变数据类型允许Integer类型不能与Number类型进行混合运算
7.函数的扩展
1.函数参数的默认值 function log(x,y='World'){}
注意:参数变量是默认声明的,所以不能用let const再次声明 且参数不能同名
// 写法一
function m1({x = 0, y = 0} = {}) {//设置了解构赋值的默认值 但是函数参数的默认值是空对象
return [x, y];
}
2.函数的length属性 返回没有制定默认值的参数个数,若指定了默认值,那么length属性将失真
(function(a,b,c=5){}).length//2
注意:若有一个参数是有默认的 那么后面的参数将不会计入length
(function (a, b = 1, c) {}).length // 1
// 写法二
function m2({x, y} = { x: 0, y: 0 }) {//设置了函数参数的默认值,但是没有设置对象解构赋值的默认值
return [x, y];
}
3.作用域 一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域
应用:利用参数默认值,可以指定某一个参数不得省略,若省略就抛出一个错误
思路:参数默认是一个函数 该函数抛错
另外,可以将参数默认值设置为undefined表明这个参数是可以省略的
4.name属性 返回该函数的函数名
function foo(){} console.log(foo.name)//foo
var f=function(){} console.log(f.name)//f
Function构造函数返回的函数实例,name属性的值为anonymous 即(new Function).name//anonymous
bind返回的函数,name属性值将会加上bound前缀 function foo(){} foo.bind({}).name//bound foo
5.箭头函数注意事项
若只有一句代码返回 则可以省略return单词
若return返回的是一句对象 那么则用()包起来let get=id=>({id:id,name:'Temp'})
变量解构与箭头函数结合使用
const full = ({ first, last }) => first + ' ' + last;
6.双冒号运算符即函数绑定运算符,左边是对象右边是函数 该运算符会自动将左边的对象,作为上下文环境(this对象),绑定到右边的函数上面
foo::bar//bar.bind(foo)
foo::bar(...arguments)//bar.apply(foo,arguments)
7.尾调用 就是函数的最后一步是return的是另一个函数 function f(x){return g(x);}
尾调用优化(只在严格模式下开启) 如果不再用到外层函数的内部变量 即只保留内层函数的调用帧 即调用帧只有一项 节省内层
8.尾递归 尾调用自身就称为尾递归 需要将所有用到的内部变量改成函数的参数
function factorial(n, total = 1) {
if (n === 1) return total;
return factorial(n - 1, n * total);
}
9.函数参数后允许尾逗号 以方便添加参数function clownsEverywhere(
param1,
param2,
) { /* ... */ }
10.允许catch语句没有参数即try{}catch{}以前的写法是try{}catch(error){}
8.数组的扩展
1.扩展运算符...用来将数组转为用逗号分割的参数序列 该运算符用于函数调用
console.log(...[1,2,3])//123
可用来将数组参数变成参数序列再进行处理
eg1.替代函数的apply方法
es5写法:Math.max.apply(null,[14,3,77])
es6写法:Math.max(...[14,3,77])即是Math.max(14,3,77);
eg2:通过push将一个数组添加到另一个数组的尾部
es6:let arr1 = [0,1,2];let arr2=[3,4,5];arr1.push(...arr2);
扩展运算符的应用:
1.复制数组
es5: const a1 = [1,2];const a2 = a1.concat();
es6:const a1 = [1,2];const a2 = [...a1];
2.合并数组
es5:arr1.concat(arr2);
es6:[...arr1,...arrr2]
3.与解构赋值结合 用于生成新的数组
const [first,...rest]=[1,2,3,4,5]//first=1 rest = [2,3,4,5]
注意:...用于数组赋值时,需要放在参数的最后一位
4.将字符串转换为真正的数组 能识别四个字节的Unicode字符
[...'hello']//['h','e','l','l','o']
5.任何Iterator接口的对象都可以用...运算符转为真正的数组
2.Array.from(arrayLike,x=>x*x)的用法 是将类似数组的对象和可遍历对象转为真正的数组
第一个参数是要转变的数组 第二个参数一个回调函数 用来处理每个元素并将值返回到数组中
可用来处理数组的值或者获取每一个元素的内容或者返回每一个元素的类型等 相当于forEach
es5:var arr1 = [].slice.call(arrayLike);
es6:let arr2 = Array.from(arrayLike);
注意:任何有length属性的对象都可以通过Array.from转为数组但是扩展运算符...不行
3.Array.of()用于将一组值转换为数组 用于弥补构造函数Array()的不足
构造函数Array的参数个数不一样时,返回结果不一样
Array.of(3,11,8);//[3,11,8]
4.数组实例的copyWithin() 在当前数组内部,将指定位置的成员复制到其他位置(会覆盖),会修改数组
[1,2,3,4,5].copyWithin(0,3,4);//[4,2,3,4,5]
//参数1必选,是从该位置开始替换数据 参数2、3可以选,2是开始读取的位置,可为负数,即倒数 3是到该位置前停止读取数据,默认等于数组长度,可为负数,即倒数
5.数组实例的find()和findIndex()
function f(v){
return v>this.age;
}
let person = {name:"json",age:20};
[10,12,26,15].find(f,person);
find(f,person)参数1必选是个回调函数,若有符合条件的,就返回第一个返回值为true的成员,若没有就返回undefined,参数2可选用来绑定回调函数的this对象
findIndex()参数1是个回调函数,返回第一个符合条件的数组成员的位置,若没有就返回-1
Object.is()与===的作用类似但是能判断NaN===NaN是true
6.数组实例的fill() 将定值填充到一个数组中
let arr = ['a','b','c'].fill(7,1,2)//参数1是定值 2.3可选 2是开始填充位置 3是结束位置之前
注意:若填充的是对象,那么被赋值的是同一个内存地址的对象,意思是赋值后若改变arr[0].name='Ben';那么arr = ['Ben','Ben','Ben'];
7.数组实例的entries(),keys(),values()用来遍历并获取index value
8.数组实例的includes()用来判断一个数组中是否包含特点的值
[1,2,3].includes(2)//true
[NaN].includes(NaN);//true
注意:Map和Set数据结构的Map.prototype.has(key)是用来查找键名的
Set,prototype.has(value)是用来查找值的
9.数组的空位 指的是数组的某一个位置没有任何值 Array(3);//[,,,]就是有3个空位的数组
空位不是undefined,一个位置的值等于undefined
es6将空位转为undefined
9.对象的扩展
1.简写 即键值一样的时候 值可省略
2.name属性 函数也有name属性
3.Object.is判断两个值是否相等
4.Object.assign(target,obj1,obj2)合并对象的
注意:typeof Object.assign(2)//object 即不是对象时会先将值转变为对象 undefined null无法转变成对象所以会报错的 但是若非对象参数出现在非首位 则会跳过的不会报错
Object.assign只拷贝源对象的自身属性不拷贝继承属性也不拷贝不可枚举的属性
属性名为Symbol值的属性会被拷贝
注意点:1.Object.assign是浅拷贝 即若拷贝对象 则拷贝的是这个对象的引用
2.同名属性的会被替换而不是添加
3.可以处理数组 但是把数组当做对象来处理的
Object.assign([1,2,3],[4,5])//[4,5,3]
4.取值函数的处理 先求值再复制
Object.assign的常见用途 1.为对象添加属性
2.为对象添加方法
3.克隆对象 若需要克隆继承链则需要先获取继承的
4.合并多个对象
5.为属性设置默认值
5.属性的可枚举性和遍历
Object.getOwnPropertyDescriptor用来获取对象的描述对象用来控制该属性的行为
enumerable:false的时候会被以下4种忽视 1.for...in 2.Object.keys() 3.JSON.stringify() 4.Object.assign()
注意:所有的Class的原型的属性都是不可枚举的
尽量用Object.keys()而不是for...in
5.属性遍历的五种方法
1.for...in
2.Object.keys(obj)
3.Object.getOwnPropertyNames(obj)
4.Object.getOwnPropertySymbols(obj)
5.Reflect.ownKeys(obj)
以上五种遵循的遍历规则是 先遍历数值键,按照数值升序排列 再遍历字符串键,按照加入时间升序排列 再遍历Symbol键,按照加入时间升序排列
6.Object.getOwnPropertyDescriptors()
主要是为了解决Object.assign()无法正确拷贝get和set属性的问题
还可以实现一个对象继承另外一个对象
还可以实现Mixin(混入)模式
7.原型
Object.setPrototypeOf()写操作
Object.getPrototypeof()读操作
Object.create()生产操作
8.super关键字 指向的是当前对象的原型对象
注意:super只能用在对象的方法中 即用到对象的方法简写中 用到属性或者属性赋值都会报错
9.Object.keys() Object.values() Object.entries
entries()方法用来遍历数组和将对象转为结构Map解构
10.对象的扩展运算符... 另外一个用处是扩展某个好安神的参数,引入其他的操作
注意:1.不能复制继承的
2.若...参数是null或者undefined 那么会忽略不会报错
3.扩展...的参数对象中若有get取值函数会执行的
10.Symbol
1.是es6引入的一种新的原始数据类型Symbol,通过Symbol函数生成,是独一无为,保证不会与其他属性名发送冲突
let s = Symbol();
console.log(typeof s)//symbol
2.作为属性名的Symbol
注意:1.Symbol函数前不能使用new命令,可以接受一个字符串作为参数,用来区分
let s1 = Symbol('foo')
console.log(s1)//Symbol(foo)
2.相同参数的Symbol函数的返回值是不相等的
let s1 = Symbol()
let s2 = Symbol()
console.log(s1==s2)//false
3.Symbol值不能与其他类型的值进行运算,但是可以显式转为字符串和布尔值,但是不能转为数值
4.Symbol值作为对象属性名时,不能用点运算符
const s1 = Symbol()
const a = {}
a.s1="Hello"
console.log(a.s1)//Hello
console.log(a[s1])//undefined
console.log(a['s1'])//Hello
5.在对象的内部,使用Symbol值定义属性时,值必须放在方括号中
let s1 = Symbol()
let obj={
[s1]:function(arg){console.log(arg)}
}
obj['s1'](123)//123
6.Symbol值作为属性名时,是公开属性,不是私有属性
3.实例:消除魔术字符串 即将多次出现的字符串修改为一个变量
4.Symbol属性名的遍历,使用Object.getOwnPropertySymbols()获取
5.Symbol.for('foo')先全局查找,若找到就返回这个Symbol值 ,否则就新建以该字符串为名称的Symbol值
6.模块的Singleton模式
7.内置的Symbol值 指向语言内部使用的方法
Symbol.hasInstance使用instanceof运算时自动调用,判断是不是实例
Symbol.isConcatSpreadable表示该对象用于Array.prototype.concat()时是否可以展开,需要定义是false还是true,数组默认是展开的,类似数组的对象默认是不展开的
Symbol.species指向一个构造函数,创建衍生对象时,会使用该属性,即所有的衍生对象都是Array的实例不是MyArray的实例
class MyArray extends Array{
static get [Symbol.species](){
return Array
}
}
Symbol.math即执行str.match(myObject)时,若该属性存在就调用它,返回该方法的返回值
Symbol.replace当该对象被String.prototype.replace方法调用时,会返回该方法的返回值
...
11.Set和Map数据结构
1.Set 是一个构造函数,用来生成Set数据结构。类似数组,但是没有重复的值,5和'5'是不同的两个值。
可以接受一个数组作为参数用来初始化 const set = new Set([1,2,3,4,4])
数组的去重[...new Set(array)]
在Set内部,NaN===NaN//true {}==={}//false
Set实例的属性和方法add() delete() has() clear()
遍历操作keys() values() entries() forEach()
2.WeakSet
与Set有两个区别:1.成员只能是对象 2.WeakSet中的对象都是弱引用(若其他对象都不引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存)3.没有size和forEach属性
3.Map 各种类型的值都可以当做键 属性和方法与Set一样
forEach方法可接受第二个参数,用来绑定this
与其他数据结构的互相转换
4.WeakMap用于生成键值对的集合
与Map的区别有两点:1.WeakMap只接受对象作为键名(null除外) 2.是弱引用,解决内存泄漏
API区别:没有遍历操作(包括key() values() entries()方法)和size属性 没有clear()方法
WeakMap的另一个用处是部署私有属性
12.Proxy
用于修改某些操作的默认行为,即对编程语言进行编程
var target = {};
var handler = {};
var proxy = new Proxy(target, handler);
proxy.a = 'b';//注意是对proxy进行操作
console.log(target.a) // "b"
13.Reflect
Reflect对象设计的目的有:
1.将Object对象的一些明显属于语言内部的方法放到Reflect对象上
2.修改某些object方法的返回结果,让其变得更合理
3.让Object操作都变成函数行为
4.Reflect对象的方法与proxy对象的方法一一对应
14.Promise
是异步编程的一种解决方案,是一个容器。里面保存着某个未来才会结束的事件的结果
Promise对象的两个特点:1.对象的状态不受外界影响。有3种状态:pending fulfilled rejected
2.一旦状态改变,就不会再变
基本用法:
const promise = new Promise(function(resolve,reject){
if(){
resolve(value);
}else{
reject(err);
}
})
推荐用法:
promise.then(function(){}).catch(function(err){})
15.Generator函数
语法,Generator函数是一个状态机,封装了多个内部状态 返回值是Iteraator对象
特征:1.function关键字与函数名之间有一个*号
2.函数体内部使用yield表达式,定义不同的内部状态
注意:1.返回的是一个指向内部状态的指针对象,即遍历器对象。需调用next()方法,使指针移向 下一个状态
2.yield表达式只能用在Generator函数里面
3.next方法可以带一个参数,该参数会被当做上一个yield表达式的返回值
16.async函数
是Generator函数的语法糖 返回的是Promise对象
17.Class
是用Point类来构造方法
1.定义类的语法 class Point{}
2.严格模式 类和模块的内部,默认是严格模式
3.constructor方法 会默认添加一个空的constructor方法
4.类的实例对象 var point = new Point(2,3)
5.Class表达式
const MyClass = class Me{
getClassName(){
return Me.name;
}
}
注意:这个类的名字是MyClass不是Me Me只在Cla ss的内部代码可用,指代当前类
6.类不存在变量提升
7.私有方法和私有属性
8.this的指向 默认是指向类的实例,但是单独提取出来用,this会指向该方法运行时所在的环境
解决方法:1.在构造方法中绑定this
2.使用箭头函数
9.name属性 就是跟在class后面的关键词
10.Class的取值函数(getter)和存值函数(setter):直接定义get set
11.Class的Generator方法:若某个方法之前加上*,就表示该方法是一个Genarator函数
12.Class的静态方法:在方法前加上static关键词即可,静态方法不会被实例继承
13.Class的静态属性和实例属性
14.new.target属性 该属性一般用在构造函数之中,返回new命令作用于的那个构造函数,若不是通过new调用的,会返回undefined,因此该属性可以用来确定构造函数是怎么调用的
注意:子类继承父类时,new.target会返回子类。切在函数外部使用new.target会报错
18.Class的继承
1.通过extends关键字来实现继承
2.Object.getPrototypeOf()方法用来从子类上获取父类
3.super关键字
一种情况是super()作为函数调用时,代表父类的构造函数
第二种情况是super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类
4.类的prototype属性和_proto_属性
5.原生构造函数的继承
es5不能继承原生构造函数
es6可以继承原生构造函数
class MyArray extends Array{
constructor(...args){
super(...args);
}
}
let arr = new MyArray();
6.Mixin模式的实现
19.Decorator
1.类的修饰 例如@testable是给实例添加静态属性
2.方法的修饰
20.Module的语法
1.es6以前是CommonJS和AMD(运行时加载) es6是用import(编译时加载或者静态加载,效率高)
2.严格模式 es的模块自动采用严格模式
3.export命令 用于规定模块的对外接口,注意:必须是接口不能是值
两种写法 1.export let year = 1968
2.let year = 1968;
export {year};
或者export {y as year}
可以用as修改默认的名字
4.import命令
import {firstname,lastname,year} from ''
import {f as firstname} from ''
引入后若是对象,则能改写其属性,否则报错。且import是静态执行,所以不能用表达式和变量
5.模块的整体加载
import * as circle from ''
6.export default命令
export default function foo(){}
或者function foo(){};export default foo;
注意:使用export default的相应的import语句不需要使用{}
export default后面不能跟变量声明语句,可以直接跟值 如export default 44
export default可以用来输出类
7.export与import的复合写法
export {foo,bar} from ''此种写法,foo和bar并没有被导入当前模块,只是相当于对外转发了这两个接口,导致当前模块不能直接使用foo bar
8.模块的继承
export *命令会忽略模块的default方法
9.跨模块常量:将输出的常量,合并在index.js里面
10.import()是编译时加载
21.Module的加载实现
1.浏览器加载:传统是浏览器通过script标签加载JavaScript脚本是同步加载。若需要异步加载,则需要加一个defer/async
es6浏览器加载es6模块