扩展 运算符
用处 | 代码 | 解释 |
数组 | [...[],1]; // [1] arr=[1,2,3],arr1=[4,5,6] [...arr] //复制数组 [...arr,...arr2] //合并数组 | ...后跟一个空数组,无任何效果 |
函数 | const args = [0, 1]; const f = v => console.log(v); | 函数调用时...才能用在扩展()中 |
字符串(有Interator) | //转化为数组 [...'hello'] //['h','e','l','l','o'] //正确返回Unicode字符串长度 [...'x\uD83D\uDE80y'].length | 将字符串转化为数组 凡涉及四个字节的字符串操作,都要用...改写 |
有Interator的对象 | //Nodelist转化为数组 let nodeList = document.querySelectorAll('div'); //Map/Set转化为数组 const map = new Map([1,2],[3,4]); let arr = [...map.keys()]; //Generator函数转化为数组 const go = function*(){ yield 1;} [...go()] // [1] | 将有Inerator接口的对象转化为真正的数组 |
字符串的扩展
字:?
码点Unicode(16进制的):20BB7 ,js看作两个字节
length:2(大于FFFF)
十进制:134071
utf-16:0xD842 0xDF87
十进制:55362 57271
内容 | 代码 | 解释 |
String.fromCodePoint() Unicode转为字符串并返回 | String.fromCodePoint(0x20BB7) | 可以返回大于0xFFFF的字符(即优化String.fromCharCode()),接受三个参数,会被合并成一个字符串返回 |
String.raw() 斜杠前加斜杠 | String.raw`Hi\\n` // 返回 "Hi\\\\n" String.raw({raw:'abc'},1,2,3) //a1b2c3 | 将有斜杠的字符加转义斜杠:String.raw``; 处理字符串:String.raw({raw:' '}),第一个参数必须是带raw属性的方法
|
codePointAt() 返回Unicode的十进制值 | let s = '?'; s.codePointAt(0) //134071:Unicode的十进制值 s.codePointAt(0).toString(16) //20BB7:Unicode '\u20BB7' //? let s = '?a' s.codePointAt(0) //134071:?的Unicode十进制 s.codePointAt(1) //57271:?中后两字节的Unicode十进制 s.codePointAt(2) //97:a的Unicode十进制 let s = '?a' for(let ch of s){ console.log(ch.codePointAt(0)) } 判断字符的字节数 let function(x => { if(x.codePointAt(0)>0xFFFF){ console.log('四字节')}else{console.log('二字节')} }) | charAt():无法读取4字节字符 charCodeAt():四字节时,分别返回前后两个字节的Unicode的十进制 codePointAt():正确返回四字节字符的Unicode的十进制 |
normalize() 字符统一 | \u01D1===\u004f\u030c //false \u01D1.normalize()===\u004f\u030.normalize() //true | 将字符的不同表示方法同一为同一形式 ǒ可以表示为 \u01D1(ǒ) \u004f\u030c(o+ˇ) |
includes() 判断是否包含字符 | includes(value,n) let s = 'Hello world!'; s.includes('world', 6) // true | n:从该位置开始 |
startsWith() 判断字符是否在头部 | startsWith(value,n) let s = 'Hello world!'; s.startsWith('world', 6) // true | n:从该位置开始 |
endsWith() 判断字符是否在尾部 | endsWith(value,n) let s = 'Hello world!'; s.endsWith('world', 6) // true | n:在该位置前结束 |
repeat() 重复 | 'a'.repeat(3); //aaa | 将字符串重复输出并返回新的字符串 |
padStart() 头部补全 | 'x'padStart(4) 'x'.padStart(4,ab) //abax | 第二个参数不填,默认用空格补全 用ab在被补全字符x的前面补全,直到长度为4 |
padEnd() 尾部补全 | 'x'.padStart(4,ab) //xaba | 用ab在被补全字符x的后面补全,直到长度为4 |
trimStart() 消除头部空格 | const s = ' abc '; s.trim() // "abc" | trim()用作消除空格 |
trimEnd() 消除尾部空格 |
正则的扩展
数值的扩展
内容 | 代码 | 解释 |
0b(0B),0o(0O) 二进制数,八进制数 | Number(0b111); //7 Number(0o10); //8 | Number将数值转化为十进制数
|
Number.EPSILON 极小常量 | Number.EPSILON===0.00...01(小数点后51个零)===Math.pow(-2,-52) //应用 function re = (x,y) => { return Math.abs(x-y)<Number.EPSILON*Math.pow(2,2) //误差小于-2的-50次方 } re(0.2,0.3) //ture | 浮点数计算不精确,如0.2+0.1====0.3 //false 0.2+0.1=0.30000000000000004() 引入极小常量可以设置误差范围 Number.EPSILON等于-2的-52次方
|
Number.MIN_SAFE_INTEGER 最小安全整数 | Number.MIN_SAFE_INTEGER===Math.pow(-2,53) +1
| Number.MIN_SAFE_INTEGER为-2的53次方加1 |
Number.MAX_SAFE_INTEGER 最大安全整数 | Number.MIX_SAFE_INTEGER===Math.pow(2,53) -1 | Number.MIN_SAFE_INTEGER为2的53次方减1 |
Number.isFinite() 判断是否有限 | Number.isFinite(15); //true Number.isFinite('15'); //false Number.isFinite(ture); //false | 非数值false |
Number.isNaN() 判断数值是否是NaN | Number.isNaN(NaN); //true Number.isNaN(NaN/9) //true Number.isNaN('true'/0) //true Number.isNaN('true'/'true') //true Number.isNaN('NaN'); //false Number.isNaN('15'/0) //false | 只有NaN返回true |
Number.isInteger() 判断是否为整数 | Number.isInteger(15) //true Number.isInteger(15.0) //true Number.isInteger(15.0000000000000002) //ture Number.isInteger(5E-325) //true Number.isInteger(5E-324) //false Number.isInteger() //false | 非数值全返回false javascript能分辨的最小值(Number.MIN_VALUE)是5E-324 当数值小于5E-324,归零 |
Number.isSafeInteger() 判断是否是安全数 | Number.isSafeInterger(12) //true Number.isSafeInterger(Number.MIN_SAFE_INTEGER) //true | 整数在-2^53~2^53为安全数 非数值全返回false |
Number.parseInt() 转换为整数 | Number.parseInt('12.34') // 12 | 相当于parseInt('12.34') //2 |
Number.parseFloat() 转换为浮点数 | Number.parseFloat('123.45#') // 123.45 | 相当于parseFloat('123.45#') //123.45 |
Math对象的扩展
内容 | 代码 | 解释 | 代码模拟 |
** 指数运算(^) | 2**2 // 4 2**2**3 // 2**(2**3) a**=2 //a=a**2 | 2**2==2^2 和Math.pow差不多但有细微差别,在大数值运算中,结果不同 | |
Math.trunc() 去除小数部分 | Math.trunc(4.1); //4 Math.trunc('4.1'); //4 Math.trunc(true); //1 Math.trunc(false); //0 Math.trunc(null); //0 Math.trunc(); //NaN Math.trunc('foo'); //NaN Math.trunc(NaN); //NaN Math.trunc(undefined); //NaN | 非数值,可以转化为数值的,如true,false,null,‘123’,先转化为数值 非数值,不能转化为数值的,如NaN,undefine,‘foo’返回NaN | Math.trunc = Math.trunc || function(x) { |
Math.sign() 判断数值类型 | Math.sign(5) //1 Math.sign(0) //0 Math.sign('5') //1 Math.sign('foo') //NaN | 返回值 正数:1 负数:-1 +0:0 -0:-0 其他:NaN 非数值,可以转化为数值的,如true,false,null,‘123’,先转化为数值 非数值,不能转化为数值的,如NaN,undefine,‘foo’返回NaN | Math.sign = Math.sign || function(x) { |
Math.cbrt() 计算立方根 | Math.cbrt(8) //2 Math.cbrt('8') //2 Math.cbrt(‘foo’) //NaN | 非数值,可以转化为数值的,如true,false,null,‘123’,先转化为数值 非数值,不能转化为数值的,如NaN,undefine,‘foo’返回NaN | Math.cbrt = Math.cbrt || function(x) { |
Math.clz32() 转为32位无符号整数,返回前导0 | Math.clz32(1) //31 Math.clz32(true) //31 Math.clz32([]) //32 | 000..01:1前面有31个零 非数值,可以转化为数值的,如true,false,null,‘123’,先转化为数值 非数值,不能转化为数值的,如NaN,空,undefine,‘foo’返回32
| |
Math.imul() 转为32位带符号整数,返回相乘结果 | Math.imul(-1, 8) // -8 Math.imul(0x7fffffff, 0x7fffffff) // 1 | 超出-2^53~2^53的也可以正确结算 | |
Math.fround() 返回32位单精度浮点数形式 |
|
|
|
Math.hypot() 返回平方和相加的平方根 | Math.hypot(3,4) //5 Math.hypot(3,4,5) Math.hypot(3,4,NaN) //NaN | 3^3+4^4再开平方,结果为5 3^3+4^4+5^5再开平方 非数值,可以转化为数值的,如true,false,null,‘123’,先转化为数值 非数值,不能转化为数值的,如NaN,空,undefine,‘foo’返回NaN | Math.fround = Math.fround || function (x) { return new Float32Array([x])[0]; }; |
Math.expm1(x) e^x-1 | Math.expm1(-1) //e^(-1)-1 | Math.expm1(x)返回e^x-1,相当于Math.exp(x)-1 | Math.expm1 = Math.expm1 || function(x) { |
Math.log1p(x) 1+x的自然对数 | Math.log1p(1) | n<-1返回NaN n=-1返回-Infinity Math.log1p(x)返回1+x的自然对数,相当于Math.log(1+x)
| Math.log1p = Math.log1p || function(x) { return Math.log(1 + x); }; |
Math.log10(x) 以10为底的x的对数 | Math.log10(1) //0 | log10(1)==0 x小于0返回NaN | Math.log10 = Math.log10 || function(x) { |
Math.log2() 以2为底的x的对数 | Math.log2(2) //1 | log2(2)==1 x小于0返回NaN | Math.log2 = Math.log2 || function(x) { |
数组的扩展
内容 | 代码 | 解释 | 空位 |
... 扩展运算符 | let arr1 = [0, 1]; [...arr2] //[2,undefined ,3] | push参数不能为数组但和...结合使用可以实现在尾部添加 | 空位转为undefine |
Array.from() 转化为数组 | //转化为数组(有Interator) const map = new Map([[1,2],[3,4]]); const arr = Array.from(map); 兼容写法 const toArraya = ((obj) => {Array.from?Array:obj => [].slice.call(obj)})() | 所有类似数组的对象(有length属性)都能用此方法转化为数组, 转化为数组的方法还有 [...] //有Interator接口 Array.prototype.slice //无部署Array的浏览器 | 空位转为undefine |
//处理元素 Array.from([1, 2, 3], (x) => x * x); Array.from(map, (x) => x * x); | 相当于Map遍历,先将前一个参数转化为数组,再将元素进行处理 | ||
Array() 一组值转化为数组 | Array() // [] | 参数不同表现不同: 无参数:空数组 一个参数:空数组,长度为该参数 两个以上参数:参数全为数组元素 | |
Array.of() 一组值转化为数组 | Array.of() // [] | 弥补Array()的不足,参数不同表现相同 Array.of总是返回参数值组成的数组,参数为空总是 | |
copyWithin() 复制成员 | 格式: Array.prototype.copyWithin(target, start = 0, end = this.length) 无部署copyWithin写法 [].copyWithin.call(new IntArray(arr,target,start,end)); | target:从该位置开始替换元素,负数表示倒数(必须) star:从该位置开始读取数据(可选) end:从该位置前停止读取数据(可选) | 连空位一起拷贝 |
例子: [1,2,3,4,5].copyWithin(0,3) //[4,5,3,4,5] [1,2,3,4,5].copyWithin(0,3,4) //[4,2,3,4,5] [].copyWithin.call(new IntArray([1,2,3,4,5],0,3,4)); //IntArray [4,2,3,4,5] | |||
find() 查找 | 一参数: [1,2,3].find((n) => n>1); //2 [0,5,10,15].find((value,index,arr) => {return value>5}) //10 两参数: function f = (n) =>{ n>this.age} let v = {age:2,name:anny} [1,2,3,4]find(f,v) | 找到第一个符合的元素,返回元素 value:当前值 index:当前位置 arr:原数组
f中的this指向find的v | |
findIndex() 查找 | [1,NaN,3].findIndex(n =>Object.is(NaN,n)); // 1 | 查找第一个符合的元素的索引,返回元素的索引 indexOf不能查找数组中的NaN成员,findIndex可以 | |
includes() 查找 | 格式 include(value,start) 兼容性写法 const ins = (() => Array.prototype.includes?(arr,value) =>arr.includes(value):(arr,value) =>arr.some(el => el===value))() ins([1,2],2) //true 例子 [1, 2, NaN].includes(NaN) //true | value:给定值 start:从该位置开始查找,可选,如果不填则从头开始查找 判断是否包含给定值,包含则返回true | |
fill() 填充 | 格式: .fill(value,start,end) 例子: //一个参数:全覆盖 new Array(3).fill(7) // [7,7,7] [1,2,3].fill(7) // [7,7,7] //三个参数 ['a', 'b', 'c'].fill(7, 1, 2); // ['a',7,'c'] //一个参数,为对象 let arr = new Array(2).fill({name:tom}); //{name:tom,name:tom} arr[0].name=jack; //{ name:jack,name:jack} | value:替换的值 start:从该位置开始替换 end:在该位置前停止替换
fill填充的value为对象(包括数组)时,被赋值的是同一个内存地址对象,当改变任意一个元素是,所有元素都会被改变 | 将空位看作正常位置 |
遍历 keys() values() entries()
| for(k of [a,b].keys()); let arr = [a,b]; for(k of arr.keys()); [...[,a].keys()] //[0,1] | values:遍历值 keys:遍历键 entries:遍历键值 | for...of会遍历空位 values,keys,entries都会将空位处理成undefine |
for(v of [a,b].values()); [...[,a].values()] //[undefine,a] | |||
for([k,v] of [a,b].entries()); [...[,a].entries()] //[[0,undefine],[1,a]] | |||
flat() 多维数组拉平 | .flat(times) [1,2,[3,[4]],5].flat(); // [1,2,3,[4],5] [1,2,[3,[4]],5].flat(2); // [1,2,3,4,5] [1,2,[3,[4]],5].flat(Infinity); // [1,2,3,4,5] [1, ,2,[3,[4]],5].flat(2); // [1,2,3,4,5] | 用于将嵌套的数组拉平,返回新数组,不影响原数组 times:拉平的次数,默认为1,当参数为Infinity时,不管多少层都拉成一维数组 如果数组有空元素,会跳过空元素 | |
flatMap() 操作+拉平 | .flatMap(() => {}) [1,2,3].flatMap(x => [x,x*x]) //[1,1,2,4,3,9] [1,2,3].flatMap(x =>[[x]]) //[[1],[2],[3]] | 对数组成员执行函数后做falt拉平一次,返回新数组,不影响原数组 |
解构赋值
从对象和数组中提取值,并赋值给变量
数组 | let [a,b,c]=[1,2,3]; let [a, ,c]=[1,2,3]; //c为3 let [a,...b]=[1,2,3]; //b为[2,3] let [a,b,c]=[1,[2,3],4] //b为2,c为4 let [a,b,c]=new Set([1,2,3]) | ...只能放数组最后一位 |
对象 | ||
字符串 | ||
数值和布尔值 | ||
函数参数 | ||
对象
1.对象和属性的写法
ES5 | ES6 | ||
属性 | const obj = {val:'123'} | 简洁表达法 | function(x,y){ {x,y} } |
function(x,y){ {x:x,y:y} } | const val = '123'; const obj = {val} | ||
var obj = { abc:123 foo:true } | 属性名为表达式 | obj.['a'+'bc']=123; 或 let obj = { ['a'+'bc']=123 } | |
属性名为标识符 | obj.foo=true; 或 let pkey=foo; let obj = { [pkey]:true } | ||
方法 | const obj = { method:function(){ // } } | 方法简写 | const obj = { method(){ // } }
|
方法名为Symbol | const obj = { [mySymbol](){ // } } | ||
方法名为表达式 | const obj ={ ['method'+'1'](){ // } } | ||
方法为Generator函数 | const obj = { * method(){ // } } |
2.对象方法的name属性,返回函数的名称
对象方法的类型 | 方法举例 | name使用 | 解释 |
普通方法 | const obj= { | obj.foo.name // 'foo' | 对象.方法.name |
取值/存值函数 | const obj = { | const a=Object.getOwnPropertyDiscription(obj,foo); a.set.name(); // 'set foo' a.get.name(); // 'get foo' | name属性在描述对象的get和set方法上 |
构造函数 | (new Function()).name | //anonymous | 构造函数name属性返回anonymous |
bind()创建的函数 | var foo=function(){ // } | foo.bind().name | name属性在bind方法上 |
3.属性 的可枚举
属性>枚举性>操作
const obj={a:1}; //属性
Object.getOwnPropertyDescriptior(); //描述
//常见不可枚举属性
toString
length
Symbol
//四种操作忽略不可枚举属性
for...in //遍历
Object.keys() //获取键
Object.assign() //拷贝
JSON.stringify() //转化为字符串
4.属性遍历
遍历方法 | 遍历范围 | 图示 |
for...in | 遍历包含 自身可枚举+继承可枚举 | ![]() |
Reflect.ownkeys | 返回数组 自身可枚举+自身不可枚举+Symbol 属性的键 | |
Object.getOwnPropertyName() | 返回数组 自身可枚举+自身不可枚举(不包含Symbol) | |
Object.getOwnPropertySymbol() | 返回数组 所有Symbol类型属性 | |
Object.keys() | 返回数组 自身可枚举属性 |
5.方法中使用super
用于继承原形链上属性,注意:只能在对象的方法中使用,不能用于属性的赋值
const father = {foo:123};
const child = {
a(){return super.foo}
};
Object.setPrototypeOf(child,father);
child.a();
6.新增方法
包括比较两对象Object.is(),拷贝对象,合并对象,普通数据类型转换成对象(Object.assign()),有Interator接口的数据转化为对象(Object.formEntries()),原形链上属性读取和设置
方法 | 举例 | 解释 |
比较 Object.is() | Object.is({},{}) //false Object.is(+0,-0) //false Object.is(NaN,NaN) //true | == 会自动转换类型 === 中NaN不等于自身,+0不等于-0 |
合并,浅拷贝,转换成 Object.assign() | //对象 const obj1={x:1,a:{b:1}} const obj2={x:2,z:3} obj1.a.b=2 obj3=Object.assign({},obj1) //克隆对象 Object.assign(obj1); //浅拷贝,obj1.a.b为2 Object.assign(target,obj1,obj2); //合并 //为对象添加属性 class Point{ constructor(x,y){ Object.assign(this,{x,y}) }} //为对象添加方法 Object.assign(SomeClass.prototype,{ foo(){ // } }) | 用于对象的合并,对象拷贝,为对象添加属性和方法
注意:浅拷贝:如果源对象的属性值是对象,拷贝得到的是对象的引用
对象合并时,重复属性会被后面的覆盖,
为Point类的实例添加属性
在SomeClass的原形链上添加方法 |
//基本数据类型转换成对象 Object.assign(‘123’); Object.assign({},null); //object Object.assign({},undefine); //object | 转换成对象,null和undefine不能直接转,要用这种方式 | |
//数组合并 Object.assign([1,2,3],[5]); //[5,2,3] | 用做数组合并,会将数组也当成对象,相同下标会被覆盖 | |
//取值函数 const obj1={get foo(){return 1}}; Object.assign({},obj1) //{foo:1} | 取值函数拷贝时,不会直接拷贝函数,只会拿到值后拷贝 | |
键转化为数组 Object.keys() | 格式 Object.keys(obj) 配合for...of使用 for(k of Object.keys(obj)){ // } | 返回数组,包含参数对象自身可遍历的属性的键名 |
值转化为数组 Object.values() | 格式 Object.values(obj) 配合for...of使用 for(k of Object.values(obj)){ // } | 返回数组,包含参数对象自身可遍历的属性的键值 |
键值对转化为数组和Map Object.entries() | 格式 const obj = {x:1,y:2} Object.entries(obj) 配合for...of遍历(对象转化为数组) for(let [k,v] of Object.entries(obj)){ // } //遍历键值对 将对象转化为Map结构 const map=new Map(Object.entries(obj)) | 返回数组,包含参数对象自身可遍历的属性的键值对 可用于将对象转化为数组 |
转化为对象 Object.formEntries() | 数组>对象 Object.formEntries([ [x,1],[y,2] ]) Map>对象 const map =new Map().set('x',true) Object.formEntries(map) 查询字符串>对象 Object.fromEntries(new URLSearchParams('foo=bar&baz=qux')) | 将键值对数组转化为对象
将Map结构转化为对象
将查询字符转化为对象
|
对象属性的描述对象 Object.getOwnPropertyDescriptior() | const source = { const target2 = {};
| 返回自身属性的描述对象 可以配合defineProperties实现正确的存值和取值函数的拷贝 |
创建 Object.create() | 创建对象 | |
写操作 Object.setOwnPrototypeOf() | 格式 Object.setOwnPrototypeOf(object,prototype) 例子 Object.setOwnPrototypeOf(obj,proto); //将proto设置为obj的原形,obj可读取proto的属性 | 设置当前对象的prototype对象,返回参数对象本身 |
读操作 Object.getOwnPrototypeOf() | 格式 Object.getOwnPrototypeOf(obj) | 读取一个对象的原形对象 |
Symbol
Symbol | 代码 | 解释 |
创建 Symbol() | let s = Symbol(); let s1 = Symbol('foo'); //创建+添加描述 let s2 = Symbol.for('foo'); //创建+添加描述+登记 (可以在不同Iframe或service worker中取到同一个值) | 调用Symbol函数,注意:不用new 若参数是对象,则先调用对象中toString方法将对象转化为字符串 Symbol('foo')===Symbol('foo') //false Symbol.for('foo') ===Symbol.for('foo') //true |
返回描述 discription | s1.discription; | 返回Symbol的描述 |
返回key keyFor() | Symbol.keyFor(s2); | 只有Symbol.for创建的才能用这个方法 |
转化 | String(s1); Boolean(s); //转化为布尔值,返回ture | 转化为字符串,返回'Symbol(foo)' |
作为对象的属性名(三种写法) [Symbol] obj[Symbol] defineProperty() | let s = Symbol(); | 创建对象时直接添加属性 |
let s2 = Symbol(); let obj2 = {}; obj.s2='hello'; //报错 | 对象[Symbol]方法添加,注意:不能用点运算符 | |
let obj3 = {}; let s3 = Symbol(); Object.defineProperty(obj3,s3,{value:'hello'}); | 用defineProperty添加 | |
使用场景 | const obj={case1:Symbol()}; //将魔术字符case1值设为Symbol function getArea(shape){ switch(shaoe){ case obj.case1: //代码块 break;} } getArea(obj.case1); | 消除魔术字符(代码中多次出现,与代码形成强耦合的字符串或数值) |
Singleton 模式(调用类时,任何时候都返回同一个实例) |
Set和Map数据结构
Set
关注值,值唯一
类似于集合的数据结构,类似于数组,但是成员值是唯一的,没有重复的,因此Set可以用作去除字符串和数组中重复的成员,Set 内部,两个NaN是相等,两个对象总是不相等。Set的key和value相等
//1.生成
new Set()
//2.添加成员
//可接收有Interator接口的数据结构,包括数组,NodeList,字符串
const s=new Set([1,2,2,3]); //数组去除重复值
const s=new Set(document.querySelectorAll('p')); //NodeList
const s=new Set('12344'); //字符串去除重复值
//3.属性和方法
s.size; //返回Set实例成员总数
s.has(value); //检查实例中是否存在该value值,存在则返回ture
s.add(value); //添加value值,返回实例
s.delete(value); //删除value值,删除成功返回ture
s.clear(); //删除所有成员,无返回值
//4.遍历
for(let a of s.keys()){alert(a)} //遍历并返回键
for(let a of s.values()){alert(a)} //遍历并返回值(value()可省略)
for(let a of s.entries()){alert(a)} //遍历并返回键和值
s.forEach((value,key) => {alert(value+','+key)})
//5.Set结构转换成数组
Array.from(new Set('123'));
[...new Set('123345')];
//实现数组并集,交集,差集(数组filter方法和Set的has方法)
let a = new Set([1,2,3]);
let b = new Set([1,2,3]);
let c = new Set([...a,...b]);//并集
let c = new Set([...a].filter(x => b.has(x)));//交集
let c = new Set([...a].filter(x => !b.has(x)));
Map
关注键,键唯一
Map(键-值)是类似对象(键-值)的数据结构,但是Map中键不一定要是字符串,Map中除NaN外,键和键严格相等(+0,-0严格相等)才看作是同一键且键唯一存在,Map中两个对象(包括数组)作为键总是不相等
//生成
new Map();
//性质
const map = new Map([[NaN,111],[NaN,222]]); //NaN为相同键,重新赋值
const map = new Map([[{},111],[{},222]]) //对象总为不同键,对象的写法{a:1},{'a',1},{}
const map = new Map([[[],111],[[],222]]);//数组总为不同键
//添加成员
//可以接受二维数组,Set,Map作为参数(条件有Iterator接口且成员都为双元素)
const map = new Map([['ture',1],[NaN,1],[NaN,2]],[{p:'value'},'content']);
const map = new Map(new Set([['a',1],['b',2]]));
const map = new Map(new Map([['a',1],['b',2]]));
//属性和方法
map.size;//
map.set(key,value); //key若为对象和数组,无论如何都成为新成员,
map.get(key); //key为对象和数组时,value都为undefine
map.has(key); //按键查询,返回ture/false
map.delete(key);//按键删除,返回ture/false
map.clear(); //清除所有成员,没有返回值
//遍历
for(item of map.keys){console.log(item)}; //遍历键
for(item of map.values){console.log(item)}; //遍历值
for(item of map.entries){console.log(item[0]+item[1]+[2])}; //遍历键和值
map.forEach((value,key,map) => {console.log(value+key+map)})
Promise
获取异步操作的消息,相当于一个异步调用的容器,可以监听调用结果(成功或失败)
创建实例 new Promise() | const promise = new Promise( (resolve,reject) => { function(){ if( // 成功 ){ resolve(value,times); }else{ reject(error,times);} }; //代码块 }) | new Promise接收一个函数作为参数,这个函数又接受resolve和reject函数作为参数 成功:调用resolve函数(并传参 times:回调延迟执行时间,可不写) 失败:调用reject函数(并传参 times:回调延迟执行时间,可不写) |
指定回调函数 .then() .catch() .finally() | promise.then(value => { //成功 },error => { //失败 }); | promise原形链上的的then方法指定resolve和reject函数的回调函数 |
promise.then(value => { //成功 }).catch(err => { //出错 }); 相当于 promise.then(value => { //成功 }).then(null,(err) => { //出错 }) | promise原形链上的catch方法指定发生错误时(reject对应的回调函数)的回调函数相当于 .then(null,rejection)或.then(null,rejection) | |
promise.finally(() => { //无论如何都执行 }) 相当于 promise.then(value => { //成功 return value },error => { //失败 return error}); | promise原形链上的finally方法指定promise执行后无论如何都调用的函数(成功和失败都调用它)
| |
resolve后代码块 | const promise = new Promise( (resolve,reject) => { resolve(1); console.log(2); }).then( r => console.log(r) ) | 没有return时 resolve后代码块会执行,并且会比resolve先执行 先打印出2再打印出1 |
const promise = new Promise( (resolve,reject) => { return resolve(1); console.log(2); }).then( r => console.log(r) ) | return时 resolve后代码块不会执行 只打印出1 | |
Promise实例 | 实现异步加载图片 function loadImageAsync(url) { image.onload = function() { image.onerror = function() { image.src = url; | |
实现Ajax const getJSON = function(url){ //异步容器promise const promise = new Promise(resolve,reject){ //判断是否成功 const handler = function(){ if (this.readyState !== 4){ return; } //失败 if (this.state === 200){ resolve(this.response) } else{ reject( new Error(this.statusText() ) ; } }; //Ajax实例 const ajax1 = new XML.HttpRequest(); ajax1.open('GET',url); ajax1.setRequestHeader('Accept','application/json'); ajax1.responseType='json'; ajax1.onreadystatechange=handler; ajax.send(); }; return promise; }; getJSON('/posts.json').then(json => { console.log(json) },error => { console.log(error) }); | 结构: const getJSON = function(url){ const promise = new Promise(resolve,reject){ const handler = function(){ //获取异步操作,调用resolve和reject }; //Ajax实例(代码块) }; return promise; }; getJSON('/posts.json').then(,); | |
function getUsername(userId) { return database.users.get({id: userId}) .then(function(user) { return user.name; }); } | database.users.get({id: userId}返回一个Promise实例 | |
包装多个promise .all() .race() | const p1 = new Promise((resolve,reject) => { }).then() const p2 = new Promise((resolve,reject) => { }).then().catch Promise.all([p1,p2]).then().catch() | Promise实例p2有自己的catch函数,Promise中的catch不会被执行,如果p2没有catch,才可能会被执行,当实例全为resolve,执行all后then,若有其中一个为reject,执行catch |
.race()类似.all() | .race()类似.all() | |
.resolve() | //不带参数 const promise = Promise.resolve(); //生成Promise实例 //参数为Promise实例 const promise = Promise.resolve(p1);//返回实例 //参数为thenable(有then) let thenable = {then : () => { resolve(42) } } const promise = Promise.resolve(thenable).then(value=>{ console.log(value) }) //参数是对象但无then方法,或不是对象 const promise = Promise.resolve(“123”); p.then(val => console.log(val)); //123 |
无参数时,相当于const promise = new Promise((resolve,reject) => resolve() )
参数是thenable时,立即执行thenable中then
参数是无then方法的对象,或不是对象,生成新的Promise对象,状态为成功resolve |
.reject() | //无参数 const promise = Promise.reject(); //参数为thenable(有then) let thenable = {then : () => { reject(42) } } Promise.reject(thenable).catch(e=>{ console.log(e === thenable) }) | 无参数时,相当于const promise = new Promise((resolve,reject) => reject() )
参数为thenable是,thenable返回给catch的参数是thenable本身,而不是其抛出的42 |
.try() | const f = () => { // } //f是函数 Promise.try(f) //捕获同步和异步错误 Promise.try(() => database.users.get({id:userId})) .then(...) .catch(...) //捕获同步和异步异常 //实例 var Promise = require("bluebird"); function getUsername(userId) { return Promise.try(function() { return database.users.get({id: userID}); }) .then(function(user) { return user.name; }); } | 同步函数同步操作,异步函数异步操作
database.users.get()返回Promise对象
异步错误:reject 同步错误:如数据库连接错误 |
Generator
异步编程解决方案,是一个状态机,封装了多个状态,还会返回一个遍历器对象
有Interator接口的数据结构
NodeList,数组,字符串,Set结构,Map结构,TypeArray,函数argument对象
那些场合会调用Interator:数组和Map的解构赋值;扩展运算符;yield*;for...of遍历;Array.from转换为数组;Map(), Set(), WeakMap(), WeakSet();Promise.all();Promise.race();
for...of
对数组,对象,Map和Set进行遍历
数据类型 | 数据 | 遍历for...of |
数组 | let arr = [1,2,3]; | for(let v in arr){ // } //获取键名(少用) for(let k of arr){ // }; //获取键值 for(let k of arr.keys(obj)){ // } //获取键 for(let v of map.values(obj)){ // } //获取键值 for(let k of map.entries(obj)){ // } //获取键值对 |
对象 | //普通对象 const obj = {x:1,y:1}; | //普通对象 for(let v in obj){ // } //获取键名 for(let k of Object.keys(obj)){ // } //获取键 for(let v of Object.values(obj)){ // } //获取键值 for(let k of Object.entries(obj)){ // } //获取键值对 |
类似数组对象 | //有Interator接口 let paras = document.querySelectAll("p"); //NodeList对象 let str = "hello"; //字符串 //函数中arguments对象 function a(){ for(let x of arguments){ // } } | for(let v of paras){ // } for(let v of str){ // } |
//无Interator接口 const obj2 = {length:2,0:'x',1:'y'} | for(let x of Array.from(obj2)){ // } | |
Map | const map = new Map([[x,1],[y,2]]) | for(let k of map.keys()){ // } //获取键 for(let v of map.values()){ // } //获取键值 for(let k of map.entries()){ // } //获取键值对 |
Set | const map =new Set([a,b,c]) | for(let k of set.keys()){ // } //获取键 for(let v of set.values()){ // } //获取键值 for(let k of set.entries()){ // } //获取键值对 |