一、解构赋值
- 数组的解构赋值
{
let a, b, rest;
[a, b, ...rest] = [1, 2, 3, 4, 5, 6]
console.log(a,b,rest) // 1,2,[3,4,5,6]
}
{
let a, b, c;
[a, b, c=3] = [1, 2]
console.log(a,b,c) // 1,2,3
}
// 应用场景
// 变量交换
{
let a = 1;
let b = 2;
[a,b] = [b,a]
console.log(a,b) // 2,1
}
// 返回值
{
function f(){
return [1,2]
}
let a,b;
[a,b] = f()
console.log(a,b) // 1,2
}
{
function f(){
return [1,2,3,4,5]
}
let a,b,c;
[a,,,b] = f()
console.log(a,b) // 1,4
}
{
function f(){
return [1,2,3,4,5]
}
let a,b,c;
[a,,...b] = f()
console.log(a,b) // 1,[3,4,5]
}
二、 对象解构赋值
{
let a,b;
({a,b} = {a:1,b:2})
console.log(a,b) // 1,2
}
{
let o = {p:42,q:true}
let {p,q} = o;
console.log(p,q) // 42 true
}
{
let {a=5,b=10} = {a:3}
console.log(a,b) // 3 10
}
// 应用场景
{
let metaData = {
title: 'abc',
test:[{
title: 'test',
desc: 'description'
}]
}
let {title:esTitle,test:[{title:cnTitle}]} = metaData
console.log(esTitle,cnTitle) // abc test
}
// 对象内写函数时不需要再加function,而且对象内支持变量
const k = "arr";
const s = "s"
const result = {
[k+1]: 1,
s,
q(){
console.log("🐔")
}
}
result.q()
console.log(result.arr1)
console.log(c.startsWith("we")) // 以什么开始
console.log(c.endsWith("!")) // 以什么结束
console.log(c.includes("family")) // 包含什么
const c = test `${a} ${b} family!`
function test(strs,...values) {
console.log(strs,values)
}
// NaN与NaN不相等,如果想要想等需要采用以下方法
console.log(NaN === NaN);
console.log(Object.is(NaN, NaN));
三、正则新特性
{
let regex = new RegExp('xyz','i'); // i表示忽略大小写
let regex2 = new RegExp(/xyz/i);
console.log(regex.test('xyz123'),regex2.test('xyz123')); // true true
let regex3 = new RegExp(/xyz/ig,'i'); // es6中后面的修饰符会覆盖掉前面的修饰符
console.log(regex3.flags); // i
}
// y修饰符
{
let s = 'bbb_bb_b';
let a1 = /b+/g;
let a2 = /b+/y;
console.log('one',a1.exec(s),a2.exec(s)); // one ["bbb", index: 0, input: "bbb_bb_b"] ["bbb", index: 0, input: "bbb_bb_b"]
console.log('two',a1.exec(s),a2.exec(s)); // two ["bb", index: 4, input: "bbb_bb_b"] null
// g修饰符是找到就可以,y修饰符必须从上一次匹配的位置开始
console.log(a1.sticky,a2.sticky); // 判断正则对象是否开启了y修饰符 false true
}
// u修饰符
{
console.log('u-1',/^\uD83D/.test('\uD83D\uDC2A')); // \uD83D\uDC2A当作两个字符
console.log('u-2',/^\uD83D/u.test('\uD83D\uDC2A')); // \uD83D\uDC2A当作一个字符
console.log(/\u{61}/.test('a')); // false
console.log(/\u{61}/u.test('a')); // true
console.log(/\u{20BB7}/u.test('𠮷')); // true
// 点(.)字符不能识别码点大于0xFFFF的Unicode字符,必须加上u修饰符。
let s = '𠮷';
console.log('大于0xFFFF的Unicode字符',/^.$/.test(s)); // false
console.log('使用u字符',/^.$/u.test(s)); // true
// 使用u修饰符后,所有量词都会正确识别大于码点大于0xFFFF的Unicode字符。
console.log('量词',/a{2}/.test('aa')); // true
console.log('量词',/a{2}/u.test('aa')); // true
console.log('量词',/𠮷{2}/.test('𠮷𠮷')); // false
console.log('量词',/𠮷{2}/u.test('𠮷𠮷')); // true
}
{
// #正则表达式中,点(.)是一个特殊字符,代表任意的单个字符,但是行终止符(line terminator character)除外
// U+000A 换行符(\n)
// U+000D 回车符(\r)
// U+2028 行分隔符(line separator)
// U+2029 段分隔符(paragraph separator)
// 只是一个提案目前还不支持
// let reg=/test.go/s;
// console.log(reg.test('test\ngo'));
// console.log(reg.test('test\ngo'));
console.log('s变通方法',/foo.bar/.test('foo\nbar'));
console.log('s变通方法',/foo[^]bar/.test('foo\nbar'));
}
四、字符串扩展
// 字符串扩展
// 处理unicode编码处理大于0xFFFF
{
console.log('a', '\u0061'); // a a
console.log('s', '\u20BB7'); // s ₻7 \u20BB7太长,被当成了\u20BB和7两个字符
console.log('s', '\u{20BB7}'); // s 𠮷 es6方法,将字符集用{}包起来
}
{
let s = '𠮷';
console.log('length',s.length) // 2 码值大于两个字节,所以当作4个字节处理,两个字节为1个长度
console.log('0',s.charAt(0)); // 0 � 取第一个位置的字符
console.log('1',s.charAt(1)); // 1 �
console.log('at0',s.charCodeAt(0)); // at0 55362 // 取第一个位置的码值
console.log('at1',s.charCodeAt(1)); // at1 57271
// es6 取码值
let s1 = '𠮷a';
console.log('length',s1.length) // 3
console.log('code0',s1.codePointAt(0)); // code0 134071
console.log('code0',s1.codePointAt(0).toString(16)); // code0 20bb7
console.log('code1',s1.codePointAt(1)); // code1 57271
console.log('code2',s1.codePointAt(2)); // code2 97
}
// 转换为字符
{
console.log(String.fromCharCode('0x20bb7')); // ஷ
console.log(String.fromCodePoint('0x20bb7')); // 𠮷
}
// 遍历器
{
let str = '\u{20bb7}abc';
for(let i=0;i<str.length;i++){
console.log('es5',str[i]); // es5 � es5 � es5 a es5 b es5 c
}
for(let code of str){
console.log('es6',code); // es6 𠮷 es6 a es6 b es6 c
}
}
// 字符串中是否包含某些字符
{
let str="string";
console.log('includes',str.includes("c")); // false
console.log('start',str.startsWith('str')); // true
console.log('end',str.endsWith('ng')); // true
}
// 重复
{
let str="abc";
console.log(str.repeat(2)); // abcabc
}
// 模版字符串
{
let name="list";
let info="hello world";
let m=`i am ${name},${info}`;
console.log(m); // i am list,hello world
}
// es7草案
{
console.log('1'.padStart(2,'0')); // 01 第一个参数是长度,第二个是补什么 比如日期小于10月补0
console.log('1'.padEnd(2,'0')); // 10
}
// 标签模版
{
let user={
name:'list',
info:'hello world'
};
console.log(abc`i am ${user.name},${user.info}`); // i am ,,,listhello world
function abc(s,v1,v2){
console.log(s,v1,v2); // ["i am ", ",", "", raw: Array(3)] "list" "hello world"
return s+v1+v2
}
}
// String.raw对所有字符串进行转译
{
console.log(String.raw`Hi\n${1+2}`); // Hi\n3
console.log(`Hi\n${1+2}`); // Hi 3
}
五、数值扩展
// es6中二进制以0B开头,八进制以0o开头,大小写都可以
{
console.log('B',0B111110111);
console.log(0o767);
}
{
// 是否有尽之内
console.log('15',Number.isFinite(15)); // true
console.log('NaN',Number.isFinite(NaN)); // false
console.log('1/0',Number.isFinite('true'/0)); // false
// 是不是数
console.log('NaN',Number.isNaN(NaN)); // true
console.log('0',Number.isNaN(0)); // false
}
{
// 判断是否是整数
console.log('25',Number.isInteger(25)); // true
console.log('25.0',Number.isInteger(25.0)); // true
console.log('25.1',Number.isInteger(25.1)); // false
console.log('25',Number.isInteger('25')); // false
}
// 判断一个数是否在-2^53与2^53之间,超过这个范围数就不准了
{
console.log(Number.MAX_SAFE_INTEGER,Number.MIN_SAFE_INTEGER); // 9007199254740991 -9007199254740991
console.log('10',Number.isSafeInteger(10)); // 10 true
console.log('a',Number.isSafeInteger('a')); // a false
}
// 返回一个小数的整数部分
{
console.log(4.1,Math.trunc(4.1)); // 4
console.log(4.9,Math.trunc(4.9)); // 4
}
// 判断正负
{
console.log('-5',Math.sign(-5)); // -1
console.log('0',Math.sign(0)); // 0
console.log('5',Math.sign(5)); // 1
console.log('50',Math.sign('50')); // 1
console.log('foo',Math.sign('foo')); // NaN
}
// 立方根计算
{
console.log('-1',Math.cbrt(-1)); // -1
console.log('8',Math.cbrt(8)); // 2
}
// 三角函数,对数,查api
六、数组扩展
// of把一组数据变量转化为数据类型
{
let arr = Array.of(3,4,7,9,11);
console.log('arr=',arr); // [3, 4, 7, 9, 11]
let empty=Array.of();
console.log('empty',empty); // []
}
// Array.from把类数组转化为数组
{
let p=document.querySelectorAll('p');
let pArr=Array.from(p);
pArr.forEach(function(item){
console.log(item.textContent); // hello es6 world
});
console.log(Array.from([1,3,5],function(item){return item*2})); // [2, 6, 10]
}
// fill替换
{
console.log('fill-7',[1,'a',undefined].fill(7)); // [7, 7, 7]
console.log('fill,pos',['a','b','c'].fill(7,1,3)); // ["a", 7, 7] 从位置1开始替换到位置3
}
{
for(let index of ['1','c','ks'].keys()){ // keys() 返回数组下标的集合
console.log('keys',index); // 0 1 2
}
for(let value of ['1','c','ks'].values()){ // values() 返回数组值
console.log('values',value); // 1,c,ks
}
for(let [index,value] of ['1','c','ks'].entries()){ // entries() 值和键
console.log('values',index,value); // 0 1 1 c 2 ks
}
for(let value of ['1','c','ks']){
console.log('values',value); // 1 c ks
}
}
// 当前数组内部改变位置
{
console.log([1,2,3,4,5].copyWithin(0,3,4)); // [4, 2, 3, 4, 5]
}
// 查找
{
console.log([1,2,3,4,5,6].find(function(item){return item>3})); // 4 返回第一个值
console.log([1,2,3,4,5,6].findIndex(function(item){return item>3})); // 返回第一个下标
}
// 数组中是否包括某个值
{
console.log('number',[1,2,NaN].includes(1)); // true
console.log('number',[1,2,NaN].includes(NaN)); // true
}
七、函数扩展
- 箭头函数没有arguments(建议使用更好的语法,剩余运算符替代)
- 箭头函数没有prototype属性,没有constructor,即不能用作与构造函数(不能用new关键字调用)
- 箭头函数没有自己this,它的this是词法的,引用的是上下文的this,即在你写这行代码的时候就箭头函数的this就已经和外层执行上下文的this绑定了(这里个人认为并不代表完全是静态的,因为外层的上下文仍是动态的可以使用call,apply,bind修改,这里只是说明了箭头函数的this始终等于它上层上下文中的this)
// 参数默认值
{
function test(x, y = 'world'){ // 有默认值的参数后面不可以再声明没有默认值的参数 x, y = 'world', c是错误的
console.log('默认值',x,y);
}
test('hello'); // hello world
test('hello','kill'); // hello kill
}
{
let x='test';
function test2(x,y=x){
console.log('作用域',x,y);
}
test2('kill'); // kill kill
}
{
function test3(...arg){
for(let v of arg){
console.log('rest',v); // rest 1 rest 2 rest 3 rest 4 rest a
}
}
test3(1,2,3,4,'a');
}
// 展开运算符
{
console.log(...[1,2,4]); // 1 2 4
console.log('a',...[1,2,4]); // a 1 2 4
}
// 箭头函数
{
let arrow = v => v*2;
let arrow2 = () => 5;
console.log('arrow',arrow(3)); // 6
console.log(arrow2()); // 5
}
// 伪调用,提升性能
{
function tail(x){
console.log('tail',x); // tail 123
}
function fx(x){
return tail(x)
}
fx(123)
}
八、对象扩展
{
// 简洁表示法
let o=1;
let k=2;
let es5={
o:o,
k:k
};
let es6={
o,
k
};
console.log(es5,es6); // {o: 1, k: 2} {o: 1, k: 2}
// 以下两种写法是等价的
let es5_method={
hello:function(){
console.log('hello');
}
};
let es6_method={
hello(){
console.log('hello');
}
};
console.log(es5_method.hello(),es6_method.hello()); // hello hello
}
{
// 属性表达式
let a='b';
let es5_obj={
b:'c'
};
let es6_obj={
[a]:'c'
}
console.log(es5_obj,es6_obj); // {b: "c"} {b: "c"}
}
{
// 新增API
console.log('字符串',Object.is('abc','abc'),'abc'==='abc'); // 字符串 true true
console.log('数组',Object.is([],[]),[]===[]); // 数组 false false
// 注意这个是浅拷贝,浅拷贝只拷贝引用地址
console.log('拷贝',Object.assign({a:'a'},{b:'b'})); // 拷贝 {a: "a", b: "b"},第一个是要拷贝到的对象,第二个是拷贝的内容
let test={k:123,o:456};
for(let [key,value] of Object.entries(test)){
console.log([key,value]); // ["k", 123] ["o", 456]
}
}
{
// 扩展运算符 babel支持不好,会报错,实践中暂时没法用
// let {a,b,...c}={a:'test',b:'kill',c:'ddd',d:'ccc'};
// console.log(c) // c={c:'ddd',d:'ccc'}
}
九、Symbol
{
// 声明
let a1 = Symbol();
let a2 = Symbol();
console.log(a1===a2); // false
// for会查找全局中是否有a3,如果有,取a3的值,如果没有,会执行Symbol()
let a3 = Symbol.for('a3');
let a4 = Symbol.for('a3');
console.log(a3===a4); // true
}
// 作用
{
let a1 = Symbol.for('abc');
let obj = {
[a1]: '123',
'abc': '234',
'c': '456'
};
console.log('obj',obj); // obj {abc: "234", c: "456", Symbol(abc): "123"}
// 遍历的时候是拿不到Symbol(abc)值的
for(let [key,value] of Object.entries(obj)){
console.log('let of',key,value); // let of abc 234 let of c 456
}
// 拿到Symbol(abc)值
Object.getOwnPropertySymbols(obj).forEach(function(item){
console.log(obj[item]); // 123
})
Reflect.ownKeys(obj).forEach(function(item){
console.log('ownkeys',item,obj[item]); // ownkeys abc 234 ownkeys c 456 ownkeys Symbol(abc) 123
})
}
十、数据结构(set, map)
// set中的内容不可重复
{
let list = new Set();
list.add(5);
list.add(7);
// 数组长度size
console.log('size',list.size); // 2
}
{
let arr = [1,2,3,4,5];
let list = new Set(arr);
console.log('size',list.size); // 5
}
{
let list = new Set();
list.add(1);
list.add(2);
list.add(1);
console.log('list',list); // {1, 2}
let arr=[1,2,3,1,'2'];
let list2=new Set(arr);
console.log('unique',list2); // {1, 2, 3, "2"}
}
{
let arr=['add','delete','clear','has'];
let list=new Set(arr);
console.log('has',list.has('add')); // has true
list.delete('add');
console.log('delete',list); // delete {"delete", "clear", "has"}
list.clear();
console.log('list',list); // list Set(0) {}
}
{
let arr=['add','delete','clear','has'];
let list=new Set(arr);
for(let key of list.keys()){
console.log('keys',key); // keys add keys delete keys clear keys has
}
for(let value of list.values()){
console.log('value',value); // value add value delete value clear value has
}
// 默认就是values
for(let value of list){
console.log('value',value); // value add value delete value clear value has
}
for(let [key,value] of list.entries()){
console.log('entries',key,value); // entries add add entries delete delete entries clear clear entries has has
}
list.forEach(function(item){console.log(item);}) // add delete clear has
}
// weakSet和set支持的数据类型不同,只能是对象,并且是弱引用,只拷贝引用地址,他没有size等属性,且不能遍历
{
let weakList=new WeakSet();
let arg={};
weakList.add(arg);
// weakList.add(2); // Invalid value used in weak set
console.log('weakList',weakList); // weakList WeakSet {{…}}
}
// map对object的补充,key可以事任何东西,object的key是字符串
{
let map = new Map();
let arr=['123'];
// 用数组arr作key,添加用set
map.set(arr,456); // map Map(1) {Array(1) => 456} 456
// 获取arr的值用get
console.log('map',map,map.get(arr));
}
{
let map = new Map([['a',123],['b',456]]);
console.log('map args',map); // map args Map(2) {"a" => 123, "b" => 456}
console.log('size',map.size); // size 2
map.delete('a');
console.log('delete',map); // delete Map(1) {"b" => 456}
console.log('clear',map.clear(),map); // clear undefined Map(0) {}
}
// 与Set和weakSet区别相同
{
let weakmap=new WeakMap();
let o={};
weakmap.set(o,123);
console.log(weakmap.get(o)); // 123
}
// 数据结构横向对比,增,查,改,删
// map与array对比
{
let map=new Map();
let array=[];
// 增
map.set('t',1);
array.push({t:1});
console.info('map-array',map,array); // map-array Map(1) {"t" => 1} [{…}]
// 查
let map_exist=map.has('t');
let array_exist=array.find(item=>item.t);
console.info('map-array',map_exist,array_exist); // map-array true {t: 1}
// 改
map.set('t',2);
array.forEach(item=>item.t?item.t=2:'');
console.info('map-array-modify',map,array); // map-array-modify Map(1) {"t" => 2} [{…}]
// 删
map.delete('t');
let index=array.findIndex(item=>item.t);
array.splice(index,1);
console.info('map-array-empty',map,array); // map-array-empty Map(0) {} []
}
// set和array的对比
{
let set=new Set();
let array=[];
// 增
set.add({t:1});
array.push({t:1});
console.info('set-array',set,array); // set-array Set(1) {{…}} [{…}]
// 查
let set_exist=set.has({t:1});
let array_exist=array.find(item=>item.t);
console.info('set-array',set_exist,array_exist); // set-array false {t: 1}
// 改
set.forEach(item=>item.t?item.t=2:'');
array.forEach(item=>item.t?item.t=2:'');
console.info('set-array-modify',set,array); // set-array-modify Set(1) {{…}} [{…}]
// 删
set.forEach(item=>item.t?set.delete(item):'');
let index=array.findIndex(item=>item.t);
array.splice(index,1);
console.info('set-array-empty',set,array); // set-array-empty Set(0) {} []
}
// map,set,object对比
{
let item={t:1};
let map=new Map();
let set=new Set();
let obj={};
// 增
map.set('t',1);
set.add(item);
obj['t']=1;
console.info('map-set-obj',obj,map,set); // map-set-obj {t: 1} Map(1) {"t" => 1} Set(1) {{…}}
// 查
console.info({
map_exist:map.has('t'),
set_exist:set.has(item),
obj_exist:'t' in obj
}) // {map_exist: true, set_exist: true, obj_exist: true}
// 改
map.set('t',2);
item.t=2;
obj['t']=2;
console.info('map-set-obj-modify',obj,map,set); // map-set-obj-modify {t: 2} Map(1) {"t" => 2} Set(1) {{…}}
// 删除
map.delete('t');
set.delete(item);
delete obj['t'];
console.info('map-set-obj-empty',obj,map,set); // map-set-obj-empty {} Map(0) {} Set(0) {}
}
十一、Proxy与Reflect 代理,反射
// Proxy 保护一些对象
{
let obj={ // 原始对象
time:'2017-03-11',
name:'net',
_r:123
};
// 拦截代理商
let monitor=new Proxy(obj,{
// 读
get(target,key){
return target[key].replace('2017','2018'); // 把有2017的替换成2018
},
// 设置,例如只能修改name,其他不能修改
set(target,key,value){ // 第一个参数指obj对象,第二个指key,第三个是key值
if(key==='name'){
return target[key]=value;
}else{
return target[key];
}
},
// 拦截key in object操作, 判断是否拥有某个属性
has(target,key){
if(key==='name'){
return target[key]
}else{
return false;
}
},
// 拦截delete
deleteProperty(target,key){
if(key.indexOf('_')>-1){
delete target[key];
return true;
}else{
return target[key]
}
},
// 拦截Object.keys,Object.getOwnPropertySymbols,Object.getOwnPropertyNames
ownKeys(target){ // 不能遍历key为time的属性
return Object.keys(target).filter(item=>item!='time')
}
});
console.log('get',monitor.time); // get 2018-03-11
monitor.time='2016';
monitor.name='mukewang';
console.log('set',monitor.time,monitor); // set 2018-03-11 Proxy {time: "2017-03-11", name: "mukewang", _r: 123}
console.log('has','name' in monitor,'time' in monitor); // has true false
console.log('ownKeys',Object.keys(monitor)); // ownKeys (2) ["name", "_r"]
delete monitor.time;
console.log('delete',monitor); // delete Proxy {time: "2017-03-11", name: "mukewang", _r: 123}
delete monitor._r;
console.log('delete',monitor); // delete Proxy {time: "2017-03-11", name: "mukewang"}
console.log('obj',obj); // obj {time: "2017-03-11", name: "mukewang"}
}
// Reflect 用object的可以用Reflect
{
let obj={
time:'2017-03-11',
name:'net',
_r:123
};
console.log('Reflect get',Reflect.get(obj,'time')); // Reflect get 2017-03-11
Reflect.set(obj,'name','mukewang');
console.log(obj); // {time: "2017-03-11", name: "mukewang", _r: 123}
console.log('has',Reflect.has(obj,'name')); // has true
}
// 实际应用
{
function validator(target,validator){ // 校验模块
return new Proxy(target,{
_validator:validator,
set(target,key,value,proxy){
if(target.hasOwnProperty(key)){ // 是否有值
let va=this._validator[key];
if(!!va(value)){ // 如果存在
return Reflect.set(target,key,value,proxy) // 返回到真实对象上
}else{
throw Error(`不能设置${key}到${value}`)
}
}else{
throw Error(`${key} 不存在`)
}
}
})
}
const personValidators={
name(val){
return typeof val==='string'
},
age(val){
return typeof val === 'number' && val>18
},
mobile(val){
}
}
class Person{
constructor(name,age){
this.name=name;
this.age=age;
this.mobile='1111';
return validator(this,personValidators)
}
}
const person=new Person('lilei',30);
console.info(person); // Proxy {name: "lilei", age: 30, mobile: "1111"}
// person.name = 48; // 不能设置name到48
person.name='Han mei mei';
console.info(person); // Proxy {name: "lilei", age: 30, mobile: "1111"}
}
十二、 类与对象
class MathHandle {
//
}
console.log(typeof MathHandle) // "function"
console.log(MathHandle === MathHandle. prototype. constructor) // true
//这种语法糖形式,看起来和实际原理不一样的东西,我个人不太赞同
//形式上强行模仿java C#,却失去了它的本性和个性
// 基本定义和生成实例
{
class Parent{
constructor(name='mukewang'){ // 构造函数
this.name=name;
}
}
let v_parent=new Parent('v');
console.log('构造函数和实例',v_parent); // 构造函数和实例 Parent {name: "v"}
}
// // 继承
{
class Parent{
constructor(name='mukewang'){
this.name=name;
}
}
class Child extends Parent{
}
console.log('继承',new Child()); // 继承 Child {name: "mukewang"}
}
// 继承传递参数
{
class Parent{
constructor(name='mukewang'){
this.name=name;
}
}
class Child extends Parent{
constructor(name='child'){
super(name); // 如果super()为空,将默认使用父类所有参数值
this.type='child'; // 自定义的一定要放在super()后面,即super()在第一行
}
}
console.log('继承传递参数',new Child('hello')); // 继承传递参数 _Child {name: "hello", type: "child"}
}
// getter,setter
{
class Parent{
constructor(name='mukewang'){
this.name=name;
}
get longName(){ // 这是属性,不是函数,下面set同样
return 'mk'+this.name
}
set longName(value){
this.name=value;
}
}
let v=new Parent();
console.log('getter',v.longName); // getter mkmukewang
v.longName='hello';
console.log('setter',v.longName); // setter mkhello
}
// 静态方法,静态方法通过类取调用而不是通过实例去调用
{
class Parent{
constructor(name='mukewang'){
this.name=name;
}
static tell(){
console.log('tell');
}
}
Parent.tell(); // // tell
}
// 静态属性
{
class Parent{
constructor(name='mukewang'){
this.name=name;
}
static tell(){
console.log('tell');
}
}
Parent.type='test'; // 静态属性,直接在类上定义即可,注意不是实例
console.log('静态属性',Parent.type); // 静态属性 test
}
十三、Promise
// 基本定义
{
let ajax=function(callback){
console.log('执行');
setTimeout(function () {
callback&&callback.call()
}, 1000);
};
ajax(function(){
console.log('timeout1'); // 执行 timeout1
})
}
{
let ajax=function(){
console.log('执行2');
return new Promise(function(resolve,reject){
setTimeout(function () {
resolve()
}, 1000);
})
};
ajax().then(function(){
console.log('promise','timeout2'); // 执行2 promise timeout2
})
}
{
let ajax=function(){
console.log('执行3');
return new Promise(function(resolve,reject){
setTimeout(function () {
resolve()
}, 1000);
})
};
ajax()
.then(function(){
return new Promise(function(resolve,reject){
setTimeout(function () {
resolve()
}, 2000);
});
})
.then(function(){
console.log('timeout3');
})
}
{
let ajax=function(num){
console.log('执行4');
return new Promise(function(resolve,reject){
if(num>5){
resolve()
}else{
throw new Error('出错了')
}
})
}
ajax(6).then(function(){
console.log('log',6);
}).catch(function(err){
console.log('catch',err);
});
ajax(3).then(function(){
console.log('log',3);
}).catch(function(err){
console.log('catch',err);
});
}
// Promise.all 所有图片加载完再添加到页面
{
function loadImg(src){
return new Promise((resolve,reject)=>{
let img=document.createElement('img');
img.src=src;
img.onload=function(){
resolve(img);
}
img.onerror=function(err){
reject(err);
}
})
}
function showImgs(imgs){
imgs.forEach(function(img){
document.body.appendChild(img);
})
}
// 把多个promise作为一个promise实例
Promise.all([
loadImg('http://i4.buimg.com/567571/df1ef0720bea6832.png'),
loadImg('http://i4.buimg.com/567751/2b07ee25b08930ba.png'),
loadImg('http://i2.muimg.com/567751/5eb8190d6b2a1c9c.png')
]).then(showImgs)
}
// Promise.race 有一个图片加载完就添加到页面
{
function loadImg(src){
return new Promise((resolve,reject)=>{
let img=document.createElement('img');
img.src=src;
img.onload=function(){
resolve(img);
}
img.onerror=function(err){
reject(err);
}
})
}
function showImgs(img){
let p=document.createElement('p');
p.appendChild(img);
document.body.appendChild(p)
}
Promise.race([
loadImg('http://i4.buimg.com/567571/df1ef0720bea6832.png'),
loadImg('http://i4.buimg.com/567751/2b07ee25b08930ba.png'),
loadImg('http://i2.muimg.com/567751/5eb8190d6b2a1c9c.png')
]).then(showImgs)
}
promise中使用map
let data = [1, 2, 3, 4, 5, 6]
Promise.all(data.map((arr) => {
console.log("arr", arr)
return new Promise(function(resolve, reject) {
setTimeout(() => {
console.log("arr-set", 1)
resolve(2)
}, 2000)
})
})).then(res => {
console.log('res', res)
})
十四、iterator和for...of循环
// iterator用法
{
let arr=['hello','world'];
let map=arr[Symbol.iterator]();
console.log(map.next()); // {value: "hello", done: false}
console.log(map.next()); // {value: "world", done: false}
console.log(map.next()); // {value: "world", done: false}
}
{
let obj={
start:[1,3,2],
end:[7,9,8],
[Symbol.iterator](){
let self=this;
let index=0;
let arr=self.start.concat(self.end);
let len=arr.length;
return {
next(){
if(index<len){
return {
value:arr[index++],
done:false
}
}else{
return {
value:arr[index++],
done:true
}
}
}
}
}
}
for(let key of obj){
console.log(key); // 1 3 2 7 9 8
}
}
{
let arr=['hello','world'];
for(let value of arr){
console.log('value',value); // value hello value world
}
}
十五、Generator,一种异步编程解决方案
JavaScript 代码运行时,会产生一个全局的上下文环境(context,又称运行环境),包含了当前所有的变量和对象。然后,执行函数(或块级代码)的时候,又会在当前上下文环境的上层,产生一个函数运行的上下文,变成当前(active)的上下文,由此形成一个上下文环境的堆栈(context stack)。
这个堆栈是“后进先出”的数据结构,最后产生的上下文环境首先执行完成,退出堆栈,然后再执行完成它下层的上下文,直至所有代码执行完成,堆栈清空。
Generator 函数不是这样,它执行产生的上下文环境,一旦遇到yield命令,就会暂时退出堆栈,但是并不消失,里面的所有变量和对象会冻结在当前状态。等到对它执行next命令时,这个上下文环境又会重新加入调用栈,冻结的变量和对象恢复执行。
// genertaor基本定义
{
let tell=function* (){
yield 'a';
yield 'b';
return 'c'
};
let k=tell();
console.log(k.next()); // {value: "a", done: false}
console.log(k.next()); // {value: "b", done: false}
console.log(k.next()); // {value: "c", done: true}
console.log(k.next()); // {value: undefined, done: true}
}
// genertaor与iterator
{
let obj={};
obj[Symbol.iterator]=function* (){
yield 1;
yield 2;
yield 3;
}
for(let value of obj){
console.log('value',value); // value 1 value 2 value 3
}
}
// 状态机
{
let state=function* (){
while(1){
yield 'A';
yield 'B';
yield 'C';
}
}
let status=state();
console.log(status.next()); // {value: "A", done: false}
console.log(status.next()); // {value: "B", done: false}
console.log(status.next()); // {value: "C", done: false}
console.log(status.next()); // {value: "A", done: false}
console.log(status.next()); // {value: "B", done: false}
}
// async await写法,效果同上,它是Generator的语法糖
// {
// let state=async function (){
// while(1){
// await 'A';
// await 'B';
// await 'C';
// }
// }
// let status=state();
// console.log(status.next());
// console.log(status.next());
// console.log(status.next());
// console.log(status.next());
// console.log(status.next());
// }
// 实例
// 抽奖
{
let draw=function(count){
//具体抽奖逻辑
console.info(`剩余${count}次`)
}
let residue=function* (count){
while (count>0) {
count--;
yield draw(count);
}
}
let star=residue(5);
let btn=document.createElement('button');
btn.id='start';
btn.textContent='抽奖';
document.body.appendChild(btn);
document.getElementById('start').addEventListener('click',function(){
star.next();
},false)
}
// 长轮询(服务端某个数据定期变换,前端需要定时去取这个状态)
{
let ajax=function* (){
yield new Promise(function(resolve,reject){
setTimeout(function () {
resolve({code:0})
}, 200);
})
}
let pull=function(){
let genertaor=ajax();
let step=genertaor.next();
step.value.then(function(d){
if(d.code!=0){
setTimeout(function () {
console.info('wait');
pull()
}, 1000);
}else{
console.info(d);
}
})
}
pull();
}
十六、Decorator 修饰器是一个函数,用来修改类的行为
{
let readonly=function(target,name,descriptor){ // 第一个参数修改的类本身,第二个参数是修改的属性名称,第三个是该属性的描述对象
descriptor.writable=false; // 把属性描述对象的写属性置为false
return descriptor
};
class Test{
@readonly
time(){
return '2017-03-11'
}
}
let test=new Test();
// test.time=function(){
// console.log('reset time'); // Cannot assign to read only property 'time' of object '#<Test>' 不允许修改只读属性
// };
console.log(test.time()); // 2017-03-11
}
{
let typename=function(target,name,descriptor){
target.myname='hello';
}
@typename // 在类里面和类外边写都可以
class Test{
}
console.log('类修饰符',Test.myname); // 类修饰符 hello
// 第三方库修饰器的js库:core-decorators; npm install core-decorators
}
// 实例,埋点
{
let log=(type)=>{
return function(target,name,descriptor){
let src_method=descriptor.value;
descriptor.value=(...arg)=>{
src_method.apply(target,arg);
console.info(`log ${type}`);
}
}
}
class AD{
@log('show')
show(){
console.info('ad is show')
}
@log('click')
click(){
console.info('ad is click');
}
}
let ad=new AD();
ad.show(); // ad is show log show
ad.click(); // ad is click log click
}
十七、module
// 第一种写法
// export let A=123;
// export function test(){
// console.log('test');
// }
// export class Hello{
// test(){
// console.log('class');
// }
// }
// 第二种写法
let A=123;
let test=function(){
console.log('test');
}
class Hello{
test(){
console.log('class');
}
}
export default {
A,
test,
Hello
}
export function test () {} // 第一种
const test = function () {}
const gogo = function () {}
export {
test,
gogo
}
export default {test,gogo}
import {test,gogo} from "index.js"
import data from "index.js"
data.test();
十八、let,const
es6是在严格模式下的 let,const是块级作用域,没有变量提升
// 1.const不能被改变
// 2.const更符合函数式编程
// 3.js对let与const内部处理机制不同,const更加优化
let,const声明的变量是在一个叫script作用域下的,而var声明的变量因为变量提升所以提升到了全局变量window对象中,这使我们能放心的使用新语法,不用担心污染全局的window对象
for循环用var,var只执行一次,用let,let执行次数等于循环次数
// 将类似于数组的东西转换为数组
const s = "1234"
const result = Array.from(s)
console.log(result)
// NaN与NaN不相等,如果想要想等需要采用以下方法
console.log(NaN === NaN);
console.log(Object.is(NaN, NaN));
网友评论