1.let 和 const / Set 和 Map / int 和 string转化
1.1 let
1)声明的变量仅在块级作用域内有效
2)无变量提升,要在声明后使用
3)暂时性死区,只要块级作用域内存在let命令,它所声明的变量就绑定这个区域,不再受外部的影响
4)不允许在相同作用域内重复声明同一变量
1.2 const
1)同let
2)对于复合类型的变量,变量名不指向数据,而是指向数据所在的地址
const a = [];
a.push('Hello'); // 可执行
a.length = 0; // 可执行
a = ['Dave']; // 报错
1.3 Set WeakSet 和 Map
1.3.1Set
类似于数组,但是成员的值都是唯一的,没有重复的值
操作方法:add() / delete() / has() / clear()
遍历方法:keys() / values() / entries() / forEach() (Set 的 keys 和 values 方法相同)
1)数组转set
var arr = ["1","2","1","2","3","1"];
var set = new Set(arr);
//得到一个新的Set:{"1","2","3"};
2)set转数组
var arr1= Array.from(set);
//得到一个新的数组:["1","2","3"];
3)数组去重
//法一
var arr1 = Array.from(new Set(arr));
//得到一个新的数组:["1","2","3"];
//法二
[...new Set(arr)]
4)使用Set实现并集 / 交集 / 差集
let a = new Set([1,2,3])
let b = new Set([4,3,2])
//并集
let union = new Set([...a,...b])
//交集
let intersect = new Set([...a].filter(x => b.has(x)))
//差集
let difference = new Set([...a].filter(x => !b.has(x)))
1.3.2 WeakSet
1)特点:成员只能是对象;弱引用
2)实例:保证了Foo的实例方法,只能在Foo的实例上调用
3)分析:Foo 类中想验证 this 对象的来源,于是需要一个集合来存所有通过构造函数构建的对象,Foo类却并不像参与到实例对象的生命周期中去,直接用 Set 的话,由于Set 对于实例对象存在引用,就会发生内存泄漏。(内存泄漏:没有正确释放内存;内存溢出:申请不到足够的内存)
const foos = new WeakSet()
class Foo {
constructor() {
foos.add(this)
}
method () {
if (!foos.has(this)) {
throw new TypeError('Foo.prototype.method 只能在Foo的实例上调用!');
}
}
}
1.3.3Map:键值对 {xx => xxx,xx =>xxx}
1.操作方法:size() / set(key,value) / get(key) / has(key) / delete(key) / clear()
2.遍历方法:keys() / values() / entries() / forEach()
var m = new Map(); // 空Map
m.set('Adam', 67); // 添加新的key-value
m.has('Adam'); // 是否存在key 'Adam': true
m.get('Adam'); // 67
m.delete('Adam'); // 删除key 'Adam'
for(let index of map.keys()){}
for(let item of map.values()){}
for(let [index, item] of map.entries()){}
3.与其他数据结构的交换
1)Map转为数组
[...myMap]
2)数组转为Map
new Map([[true, 7], [{foo: 3}, ['abc']]])
3)Map转为对象(所有Map的键都是字符串)
function strMapToObj(strMap){
let obj = Object.create(null) //创建空对象
for(let [k,v] of strMap){
obj[k] = v
}
return obj
}
let myMap = new Map().set('yes',true).set('no',false)
console.log(strMapToObj(myMap))
4)对象转为Map
function objToStrMap(obj){
let strMap = new Map()
for(let k of Object.keys(obj)){
strMap.set(k,obj[k])
}
return strMap
}
console.log(objToStrMap({yes:true,no:false}))
5)Map转为JSON
//Map键名都是字符串,转为对象JSON
function strMapToJson(strMap){
return JSON.stringify(strMapToObj(strMap))
}
let myMap = new Map().set('yes',true).set('no',false)
strMapToJson(myMap) //'{'yes':true,'no':false}'
//Map键名有非字符串,转为数组JSON
function mapToArrayJson(map){
return JSON.stringify([...map])
}
let myMap = new Map().set(true,7).set({foo:3},['abc'])
mapToArrayJson(myMap) //'[[true,7],[{'foo':3},['abc']]]'
6)JSON转为Map
//所有键名都是字符串
function jsonToStrMap(jsonStr){
return objToStrMap(JSON.parse(jsonStr))
}
jsonToStrMap('{"yes":true,"no":false}') //Map {'yes' => true,'no' => false}
//整个JSON就是一个数组,且每个数组成员本身,又是一个有两个成员的数组
function jsonToMap(jsonStr){
return new Map(JSON.parse(jsonStr))
}
jsonToMap('[[true,7],[{"foo":3},["abc"]]]') //Map {true => 7,Object {foo:3} => ['abc']}
1.4 int 和 string转化
1)int 转 string
法一:x.toString()
法二:x
2 json字符串 和 json对象转化 / 解构赋值 / 模板字符串
2.1json字符串和json对象转化
1)JSON字符串 转为 JSON对象
JSON.parse(str);
2)JSON对象 转为 JSON字符
JSON.stringify(obj);
2.2解构赋值
2.2.1已声明的变量解构赋值
// 错误的写法
var x;
{x} = {x: 1};//将大括号写在行首,会将{x}解释为代码块
// 正确的写法
({x} = {x: 1});
2.2.2将现有对象的方法赋值到某个变量
let { log, sin, cos } = Math;
2.2.3对数组进行对象属性的解构
var arr = [1, 2, 3];
var {0 : first, [arr.length - 1] : last} = arr;
first // 0键 1
last // 2键 3
2.3模板字符串
用`(反引号)标识,用${}将变量括起来
不需使用大量的“”(双引号)和 + 来拼接
//原js模板字符串
$("#result").append(
"He is <b>"+person.name+"</b>"+"and we wish to know his"+person.age+".That is all"
);
//ES6模板字符串
$("#result").append(
`He is <b>${person.name}</b>and we wish to know his${person.age}.that is all`
);
//ES6调用函数
function string(){ return "zzw likes es6!";}
console.log(`你想说什么?
嗯,${string()}`);
//模板字符串被嵌套
//标签模板,可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串
const tmpl = addrs =>`
<table>
${addrs.map(addr =>`
<tr><td>${addr.first}</td></tr>
<tr><td>${addr.last}</td></tr>
`).join("")}
</table>
`;
const data = [
{first:'Jane',last:'Bond'},
{first:'Lars',last:'Croft'}
];
console.log(tmpl(data))
//引入模板字符串本身
let str = 'return' + '`Hello ${name}`'
let func = new Function('name',str)//参数,函数体,所有的参数都为字符串形式
func('Jack')
3 RegExp
3.1 RegExp
1)直接给出字符,就是精确匹配。用\d可以匹配一个数字,\w可以匹配一个字母或数字
2).可以匹配任意字符
3)匹配变长的字符,用*表示任意个字符(包括0个),用+表示至少一个字符,用?表示0个或1个字符,用{n}表示n个字符,用{n,m}表示n-m个字符:
例:[0-9a-zA-Z_]可以匹配一个数字、字母或者下划线,后面加一个 + 匹配至少一个
4)A|B可以匹配A或B,所以(J|j)ava(S|s)cript可以匹配四种
5)^表示行的开头,
^\d表示必须以数字开头;
KaTeX parse error: Undefined control sequence: \d at position 8: 表示行的结束,\̲d̲表示必须以数字结束。
3.2创建正则表达式
第一种方式是直接通过/正则表达式/写出来,第二种方式是通过new RegExp(‘正则表达式’)创建一个RegExp对象
var re1 = /ABC\-001/;
var re2 = new RegExp('ABC\\-001');
var re = /^\d{3}\-\d{3,8}$/;
re.test('010-12345'); // 测试是否匹配用 test()
3.3分组
()表示的就是要提取的分组,如果正则表达式中定义了组,就可以在RegExp对象上用exec()方法提取出子串来
exec()方法在匹配成功后,会返回一个Array,第一个元素是正则表达式匹配到的整个字符串,后面的字符串表示匹配成功的子串。
var re = /^(\d+?)(0*)$/ //加个问号变为非贪婪匹配
re.exec('102300') ['102300', '1023', '00']
3.4特殊标志
1)g 全局匹配
var r1 = /test/g;
// 等价于:
var r2 = new RegExp('test', 'g');
2) i 忽略大小写
3)m 多行匹配
var str="This is an\n antzone good";
var reg=/an$/m; //如果没有加m,不能够匹配字符串"an",尽管"an"后面已经换行了,但是并没有采用多行匹配,所以不是字符串行的结尾,开头同理
console.log(str.match(reg));
4 数值 【Number / Math】/ 数组【Array.from / Array of / find / fill / 】
4.1数值
4.1.1 Number
1)2)ES5没有 Number,是将非数值的值转为数值,再进行判断;例如“10”转化为10
ES6增加 Number ,只对数值有效
3)4)转化可为字符串如“10.1”
1)Number.isFinite : 是否有限
2)Number.isNaN :是否为非数字
3)Number.parseInt
4)Number.parseFloat
5)Number.isInteger
4.1.2 Math
1)Math.trunc : 去除一个数的小数部分,返回整数部分
2)Math.sign :判断一个数到底是正数、负数、还是零
3)Math.cbrt :计算立方根
4.2数组
4.2.1 Array.from
可将两类对象转为真正的数组:类似数组的对象 和可遍历 的对象(包括Set和Map)
1)类似数组的对象(1它必须是一个对象,键名为数值 2有length属性)
let arrayLike = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
2)可以接收第二个参数,类似数组的map
Array.from(arrayLike, x => x * x);
// 等同于
Array.from(arrayLike).map(x => x * x);
4.3.3 Array.of
用于将一组值转化为数组
//与Array的不同
Array.of(3) // [3]
Array(3) // [, , ,]
4.3.4 find 和 findIndex
参数:当前的值、当前的位置和原数组
1) find:第一个返回值为true的成员,然后返回该成员
2)findIndex:返回第一个符合条件的数组成员的位置
[1, 4, -5, 10].find((n) => n < 0) // -5
[1, 5, 10, 15].find(function(value, index, arr) {
return value > 9;
}) // 10
4.3.5 fill
参数:填充值,起始位置,结束位置(之前)
new Array(3).fill(7) // [7, 7, 7]
['a', 'b', 'c'].fill(7, 1, 2) // ['a', 7, 'c']
5数组遍历【forEach / map / for of】/对象遍历【for in】
5.1 JS数组遍历
1)普通for循环
2)优化for循环:避免重复获取长度
3)forEach:不能使用break语句中断循环,也不能使用return语句返回到外层函数
4)map:同forEach,支持return返回值
5)for of:正确响应break、continue和return语句
ES6新方法:entries(),keys() 和 values(),entries()是对键值对的遍历
//优化for
for(var j = 0,len = arr.length; j < len; j++){ console.log(arr[j]); }
//forEach
arr.forEach(function(value,i){ console.log('forEach遍历:'+i+'--'+value); })
//map
var temp=arr.map(function(val,index){
console.log(val);
return val*val
})
//for of
for( let value of arr){ console.log(value); }
//entries() / keys() / values()
for (let index of ['a', 'b'].keys()) { console.log(index);} // 0 1
for (let elem of ['a', 'b'].values()) { console.log(elem); } // 'a' 'b'
for (let [index, elem] of ['a', 'b'].entries()) { console.log(index, elem); } // 0 "a" 1 "b"
5.2 JS 对象遍历
1)for in
for in遍历的是数组或对象的索引(即键名),而for of遍历的是数组元素值
//for in
for (var index in arr){ console.log(arr[index]);
6 函数参数 和 解构赋值 / rest / 扩展运算符 / 箭头函数
6.1函数参数 和 解构赋值 默认值
区别:写法一函数参数的默认值是空对象,但是设置了对象解构赋值的默认值;
写法二函数参数的默认值是一个有具体属性的对象,但是没有设置对象解构赋值的默认值
// 写法一
function m1({x = 0, y = 0} = {}) { return [x, y];}
// 写法二
function m2({x, y} = { x: 0, y: 0 }) { return [x, y]; }
// x有值,y无值的情况
m1({x: 3}) // [3, 0]
m2({x: 3}) // [3, undefined]
6.2 rest
形式:…变量名,搭配的变量是一个数组
function push(array, ...items) { //注意:rest参数只能是最后一个参数
items.forEach(function(item) {
array.push(item);
console.log(item);
});
}
var a = [];
push(a, 1, 2, 3)
6.3扩展运算符
形式:… 相当于rest参数的逆运算,将一个数组转为用逗号分隔的参数序列
1)注意:数组赋值只能放在参数的最后一位
function add(x, y) { return x + y; }
var numbers = [4, 38];
add(...numbers) // 将数组转为函数的参数
2)任何Iterator接口的对象,都可以用扩展运算符转为真正的数组
//例一:
var nodeList = document.querySelectorAll('div');//返回类似数组的对象,但没有部署Iterator接口无法转化
var array = [...nodeList];
//例二
//Map 和 Set
let map = new Map([ [1, 'one'], [2, 'two'], [3, 'three'] ]);
let arr = [...map.keys()]; // [1, 2, 3]
6.4箭头函数
1)定义:this对象是定义时所在的对象
var f = v => v;
//等同于
var f = function(v) { return v; };
例:
var handler = {
id: '123456',
init: function() {
document.addEventListener('click',
event => this.doSomething(event.type), false); //this指向handler对象,否则指向document对象
},
doSomething: function(type) { console.log('Handling ' + type + ' for ' + this.id); }
};
2)嵌套的箭头函数
let insert = (value) => ({into: (array) => ({after: (afterValue) => { //加(),可能原因被解析成代码块
array.splice(array.indexOf(afterValue) + 1, 0, value);
return array;
}})});
insert(2).into([1, 3]).after(1); //[1, 2, 3]
7 简洁表示 /对象/Map转数组/ Object.assign /浅拷贝和深拷贝
7.1简洁表示
1)属性
var foo = 'bar'
var baz = {foo} //{foo:'bar'}
//等同于
var baz = {foo:foo} //属性名为变量名,属性值为变量的值
2)方法
var o = {
method() { return "Hello!"; }
};
// 等同于
var o = {
method: function() { return "Hello!";}
};
//适用于CommonJS模块输出变量
module.exports = {getItem, setItem}
3)属性名表达式
注意:属性名表达式 与 简洁表示法 不能同时使用
//表达式作为对象的属性名
var lastWord = 'last word';
var a = {
'first word': 'hello',
[lastWord]: 'world'
};
a['first word'] // "hello"
a[lastWord] // "world"
//作为方法名
let obj = {
['h' + 'ello']() { return 'hi';}
};
obj.hello() // hi
7.2对象 / Map 转数组
7.2.1对象转数组
1)Array.from(object)
要求:1.object中必须有length属性,返回的数组长度取决于length长度
2.key 值必须是数值
2)Object.values(object)
3)Object.keys(object)
4)Object.entries(object)
const obj = { foo: 'bar', baz: 42 };
console.log(Object.entries(obj)); // [ ['foo', 'bar'], ['baz', 42] ]
5)push
let keys = []
for(let property in object)
keys.push(property)
}
7.2.2Map转数组
快捷方式:扩展运算符(注意与 对象转数组 用法区别)
let map = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);
[...map.keys()] // [1, 2, 3]
[...map.values()] // ['one', 'two', 'three']
[...map.entries()] // [[1,'one'], [2, 'two'], [3, 'three']]
[...map] // [[1,'one'], [2, 'two'], [3, 'three']]
7.3 Object.assign
定义:用于对象的合并,第一个参数是目标对象,后面的参数都是源对象
//例一
var target = { a: 1 };
var source1 = { b: 2 };
var source2 = { c: 3 };
Object.assign(target, source1, source2); //如果同名属性则覆盖
target // {a:1, b:2, c:3}
//例二
var v1 = 'abc';
var v2 = true;
var v3 = 10;
var obj = Object.assign({}, v1, v2, v3);//只有字符串的包装对象会产生可枚举的属性
console.log(obj); // { "0": "a", "1": "b", "2": "c" }
注意:Object.assign是浅拷贝,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用
var obj1 = {a: {b: 1}};//如果不是对象则不影响
var obj2 = Object.assign({}, obj1);
obj1.a.b = 2;
obj2.a.b // 2
7.4浅拷贝和深拷贝
1)浅拷贝
对于字符串类型,浅复制是对值的复制,对于对象来说,浅复制是对对象地址的复制,并没有开辟新的栈,修改其中一个对象的属性,则另一个对象的属性也会改变;
2)深拷贝
开辟新的栈,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性
将 浅拷贝 变为 深拷贝 方法:
1.通过JSON解析
var test ={
age :40,
}
var result = JSON.parse(JSON.stringify(test))
//如果直接 result = test,则result改变值后test也会改变,值相等
result.age = 30
2.扩展运算符
注意:用扩展运算符对数组或者对象进行拷贝时,同 Object.assign ,如果源对象某个属性的值是对象,那么目标对象拷贝得到的是这个对象的引用
let arr = [1, 2, 3, 4, 5, 6];
let arr1 = [...arr];
arr1.push(7);
console.log(arr); //[1, 2, 3, 4, 5, 6]
console.log(arr1); //[1, 2, 3, 4, 5, 6, 7]
3.Object.assign
let aClone = Object.assign({}, a);
8 Symbol / Proxy / Iterator /类似数组的对象 / Generator
8.1 Symbol
特点:每一个Symbol值都不等
1)作为属性名
//不能用.运算符,否则会被当做字符串而不是Symbol值
var mySymbol = Symbol();
var a = {
[mySymbol]: 'Hello!'
};
a[mySymbol] //'Hello!'
//对象中同理,必须放入[]中
let s = Symbol();
let obj = {
[s]: function (arg) { ... }
};
obj[s](123);
2)Symbol.for
定义:搜索有没有以该参数作为名称的Symbol值。如果有,就返回这个Symbol值,否则就新建并返回一个以该字符串为名称的Symbol值
var s1 = Symbol.for('foo');//与Symbol不同是Symbol.for会被登记在全局环境中供搜索
var s2 = Symbol.for('foo');
s1 === s2 // true
3)Symbol.keyfor
定义:返回一个已登记的 Symbol 类型值的key
var s1 = Symbol.for('foo')
Symbol.keyfor(s1) //'foo'
4)用途之一
避免实例自定义的属性或方法覆盖原型上的属性或方法
function Foo(name){ this.name = name }
Foo.prototype.say = function(){ return this.name }
var f = new Foo('f')
var say = Symbol('say')
f[say] = function(){ return 'other name' }
f.say() //'f'
f[say]() //'other name'
8.2 Proxy 代理
定义:在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截
1)get:用于拦截属性的读取操作
var person = {
name:'张三'
}
var proxy = new Proxy(person,{
get:function(target, property){
if(property in target){
return target[property]
}else{
throw new ReferenceError("不存在")
}
}
})
proxy.name //'张三'
proxy.age //错误
2)set:用于拦截属性的赋值操作
let validator = {
set:function(obj, prop, value){
if(prop === 'age'){
if(!Number.isInteger(value)){
throw new TypeError('The age is not an integer')
}
}
obj[prop] = value
}
}
let person = new Proxy({},validator)
person.age = 100
person.age //100
person.age = 'young' //报错
8.3 Iterator 迭代器
定义:只要部署了 Iterator 接口,具有Symbol.iterator属性,就是可遍历的
有三类数据结构原生具备Iterator接口:数组、某些类似数组的对象、Set和Map结构
const banji = {
name:"终极一班",
stus:[
'xiaoming',
'knight'
],
[Symbol.iterator](){ //直接无法遍历,要加迭代器
let index = 0;
let _this = this
return{
next:function(){ //next方法
if(index<_this.stus.length){
const result = {value:_this.stus[index], done:false} //直接使用this指向next方法
index++
return result
}else{
return {value:undefined, done:true}
}
}
}
}
}
for(let n of banji){ console.log(n) } //xiaoming knight
8.4类似数组的对象
1)字符串
2)DOM NodeList对象
let paras = document.querySelectorAll('p')
for(let p of paras){
p.classList.add("test") //classList得到类名,并添加test类名
}
3)arguments对象
定义:每个函数都会有一个Arguments对象实例arguments,引用函数的实参,可以用数组下标的方式"[]"引用arguments的元素
function printArgs() {
for (let x of arguments) {
console.log(x); //'a' 'b'
}
}
printArgs('a', 'b');
8.5 Generator
1)总结:调用Generator函数,返回一个遍历器对象,代表Generator函数的内部指针。以后,每次调用遍历器对象的next方法,就会返回一个有着value和done两个属性的对象。value属性表示当前的内部状态的值,是yield语句后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
hw.next() // { value: 'hello', done: false }
hw.next() // { value: 'world', done: false }
hw.next() // { value: 'ending', done: true }
hw.next() // { value: undefined, done: true } 为true的值就是最后返回的值
2)next参数
定义:next方法可以带一个参数,该参数就会被当作上一个yield语句的返回值
function* foo(x) {
var y = 2 * (yield (x + 1));
var z = yield (y / 3);
return (x + y + z);
}
var a = foo(5);
a.next() // Object{value:6, done:false}
a.next() // Object{value:NaN, done:false}
a.next() // Object{value:NaN, done:true}
var b = foo(5);
b.next() // { value:6, done:false }
b.next(12) // { value:8, done:false }
b.next(13) // { value:42, done:true } x=5,y=24
3)for…of / 扩展运算符(…)/ 解构赋值 / Array.from 可以自动遍历Generator函数时生成的Iterator对象
function *foo() {
yield 1;
yield 2;
return 3; //不包括return
}
for (let v of foo()) { console.log(v); } // 1 2
[...foo()] //[1,2]
Array.from(foo()) //[1,2]
let [x,y] = foo() //x为1,y为2
4)异步实例
function getUsers(){
setTimeout(() => {
let data = '用户数据'
iterator.next(data)//调用next方法,并且将数据传入
}, 1000);
}
function getOrders(){
setTimeout(() => {
let data = '订单数据'
iterator.next()
}, 1000);
}
function* generator(){
let users = yield getUsers();//返回用户数据
yield getOrders()
}
let iterator = generator()
iterator.next()
9 Promise
9.1定义
优点:将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数
缺点:1)无法取消Promise,一旦新建它就会立即执行,无法中途取消;2)如果不设置回调函数,Promise内部抛出的错误,不会反应到外部;3)当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
var promise = new Promise(function(resolve, reject) {
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
promise.then(function(value) {
// success
}, function(error) {
// failure
});
//.catch()方法是.then(null,rejection)的别名,更推荐使用catch
9.2 Promise.all() / Promise.race() / Promise.resolve() / Promise.reject() / Promist.try()
1)Promise.all()
定义:用于将多个Promise实例,包装成一个新的Promise实例。接受一个数组作为参数,p1、p2、p3都是Promise对象的实例
p的状态:1)p1、p2、p3的状态都为fulfilled,p的状态为fulfilled;p1、p2、p3的返回值组成一个数组,传递给p的回调函数
2)p1、p2、p3有一个被rejected,p的状态就变成rejected;第一个被reject的实例的返回值,传递给p的回调函数
用途:如 当一个页面需要在很多个模块的数据都返回回来时才正常显示,否则loading
var p = Promise.all([p1, p2, p3]);
2)Promise.race()
定义:有一个实例率先改变状态,p的状态就发生改变,率先改变的 Promise 实例的返回值,就传递给p的回调函数
用途:一般用于和定时器绑定,比如将一个请求和一个三秒的定时器包装成Promise实例,加入到race队列中,请求三秒中还没有回应时,给用户一些提示或一些相应的操作
3)Promise.resolve()
定义:将现有对象转为Promise对象
//参数是一个thenable对象(具有then方法的对象)
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
let p1 = Promise.resolve(thenable);
p1.then(function(value) {
console.log(value); // 42
});
//参数不是具有then方法的对象,或根本就不是对象
var p = Promise.resolve('Hello');
p.then(function (s){ console.log(s) }); // Hello
4)Promise.reject() 用法同上
5)Promise.try()
定义:同步函数同步执行,异步函数异步执行
const f = ()=> console.log('now')
Promise.try(f)
console.log('next')//now next
10 异步操作 和 Async函数
10.1异步
异步:一个任务分成两段,先执行第一段,然后转而执行其他任务,等做好了准备,再回过头执行第二段
例如,有一个任务是读取文件进行处理,任务的第一段是向操作系统发出请求,要求读取文件。然后,程序执行其他任务,等到操作系统返回文件,再接着执行任务的第二段(处理文件)。这种不连续的执行,就叫做异步。
同步:连续的执行就叫做同步
10.2 async函数
10.2.1定义:Generator函数的语法糖。就是将Generator函数的 * 替换成 async ,将 yield 替换成 await,使其看起来更像同步代码
一般在await后放Promise对象,async值和Promise的返回值相同(resolve),await接收结果
//Generator函数
var gen = function* (){
var f1 = yield readFile('/etc/fstab');
var f2 = yield readFile('/etc/shells');
};
//async函数
var asyncReadFile = async function(){
var f1 = await readFile('/etc/fstab')
var f2 = await readFile('/etc/shells')
}
10.2.2 async函数
1.async函数返回一个Promise对象
//await后放Promise对象
function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value)
}
asyncPrint('hello world', 50); //50毫秒后打印出hello world
//return语句返回的值,会成为then方法回调函数的参数
async function f(){
return 'hello world'
}
f().then(v => console.log(v)) //hello world
//内部抛出错误,会导致返回的Promise对象变为reject状态。抛出的错误对象会被catch方法回调函数接收到
async function f() {
throw new Error('出错了');
}
f().then(
v => console.log(v),
e => console.log(e)
) // Error: 出错了
2.注意:
1)await命令后面的Promise对象,运行结果可能是rejected,所以最好把await命令放在try…catch代码块中(因为rejected不执行下面代码)
async function myFunction() {
try {
await somethingThatReturnsAPromise();
} catch (err) {
console.log(err);
}
}
2)多个await命令后面的异步操作,如果不存在继发关系,最好让它们同时触发
//该写法只有getFoo完成以后,才会执行getBar
let foo = await getFoo();
let bar = await getBar();
//法一
let [foo, bar] = await Promise.all([getFoo(),getBar()])
//法二
let fooPromise = getFoo()
let barPromise = getBar()
let foo = await fooPromise
let bar = await barPromise
3)await命令只能用在async函数之中,不能用在普通函数
11 Class / Module
11.1 Class(ES5使用function)
1)子类的构造方法中,只有调用super之后才能使用this关键字
2)super指向父类的原型对象,定义在父类实例上的方法或属性无法通过super调用,例如constructor中的属性
super绑定子类的this
3)静态属性
静态成员属于类(es6)/函数(es5),不属于实例,只能通过对象调用
ES6的Class内部只有静态方法,没有静态属性;ES7中类的静态属性在实例属性前加上static
class Foo{
static myStaticProp = 42 //ES7静态属性写法
}
Foo.prop = 1 //ES6中Foo类定义静态属性
11.2继承
1)ES5构造函数继承
function Phone(brand,price){
this.brand = brand
this.price = price
}
Phone.prototype.call = function(){
console.log("打电话")
}
function SmartPhone(brand,price,color,size){
Phone.call(this,brand,price) //继承父构造函数的属性
this.color = color
this.size = size
}
//借用原型对象继承方法
SmartPhone.prototype = new Phone()
SmartPhone.prototype.constructor = SmartPhone
SmartPhone.prototype.phone = function(){
console.log("我可以拍照")
}
const chuizi = new SmartPhone('锤子',2499,'黑色',6.6)
2)ES6类继承(更符合面向对象)
注意:子类中普通成员方法不能使用super调父类的同名方法,只能重写
class Phone{
constructor(brand,price){
this.brand = brand
this.price = price
}
call(){
console.log('我可以打电话')
}
}
class SmartPhone extends Phone{
constructor(brand,price,color,size){
super(brand,price)//Phone.call(this,brand,price)
this.color = color
this.size = size
}
photo(){
console.log("拍照")
}
}
const xiaomi = new SmartPhone('小米',799,'黑色','6.6')
11.3 get 和 set
get 当访问该属性时调用该函数。可以应用在变化的属性,如sum值
set 当该属性被赋值时,所绑定的函数就会被调用。可以应用在判断设置值是否合法
class Fruit {
constructor(name='香蕉',size='10斤') {
this.name = name
this.size = size
}
get getName(){
return this.name
}
set setName(value){
this.name = value
}
}
let f1 = new Fruit()
f1.setName='柿子'
11.4 Module
export 和 export default 区别:
1)export default 对应的import语句不需要使用大括号;export 对应的import语句需要使用大括号。(因为 export default 用于指定模块的默认输出,一个模块只能有一个默认输出)
2)export,可以获取模块内部实时的值,不同脚本加载模块得到同一实例;而CommonJS不能动态更新
//CommonJS模块
let {stat, exists, readFile} = require('fs')//加载fs模块
//ES6模块
import {stat, exists, readFile} from 'fs'//加载三个方法
var firstName = 'Michael'
var lastName = 'Jackson'
export{firstName, lastName}//输出变量
function v1(){}
function v2(){}
export{
v1 as streamV1,
V2 as streamV2
}//输出重命名的函数
//import,不能使用表达式 / 变量 / if语句
import {lastName as surname} from './profile'//as为重命名输入变量
//整体加载,用*指定一个对象
import * as circle from './circle'
//合并
//constants/index.js
export {db} from './db'
export {users} from './users'//import 和 export 值相同可以的写法
//script.js
import {db,users} from './constants'