1. let,const关键词
// ES6强制开启严格模式(ES5:use strict)
function test() {
for (let i = 1; i < 3; i++) {
console.log(i);
}
console.log(i); // 错误:let声明变量作用域为块作用域(不能在花括号外引用);
let a = 1; // 错误:使用let不能重复声明
let a = 2;
}
function last() {
const PI = 3.1415926; // const声明变量是块作用域,声明时必须赋值
const k = { // const声明变量为常量,const声明对象时内部指针可以改变
a: 1
};
k.b = 3;
console.log(PI, k);
}
test();
last();
2. 结构赋值
// 数组结构赋值
{
let a, b, rest;
[a, b] = [1, 2];
console.log(a, b); // let a = 1, b = 2;
}
{
let a, b, rest;
[a, b, ...rest] = [1, 2, 3, 4, 5, 6];
console.log(a, b, rest); // let a = 1, b = 2, rest = [3, 4, 5, 6]
}
// 对象结构赋值
{
let a, b;
({a, b} = {a: 1, b: 2}); // let a = 1, b = 2;
console.log(a, b);
}
{
let a, b, c, rest;
[a, b, c = 3] = [1, 2]; // 如果c没有默认值,则会undefined
console.log(a, b, c);
}
{
let a = 1;
let b = 2;
[a, b] = [b, a]; // 变量交换
console.log(a, b);
}
{
function f() {
return [1, 2]
}
let a, b;
[a, b] = f(); // 多个返回值(解包)
console.log(a, b);
}
{
function f() {
return [1, 2, 3, 4, 5]
}
let a, b, c;
[a, , , b] = f(); // 只获取特定位置上的返回值
console.log(a, b);
}
{
function f() {
return [1, 2, 3, 4, 5]
}
let a, b, c;
[a, , ...b] = f(); // 跳过不需要的返回值,并把剩余的不定个值赋到数组上
console.log(a, b);
}
{
let o = {p: 42, q: true};
let {p, q} = o; // 传递后解包赋值
console.log(p, q);
}
{
let {a = 10, b = 5} = {a: 3};
console.log(a, b); // let a = 3, b = 5
}
{
let metaData = {
title: 'abc',
test: [{
title: 'test',
desc: 'description'
}]
};
let {title: esTitle, test: [{title: cnTitle}]} = metaData; // 左右格式一致,则可以获取对应位置上的值
console.log(esTitle, cnTitle); // let esTitle = 'abc', enTitle = 'test'
Object.assign(metaData, {'title': 'def'}) // 对metaData的title赋值为def
}
3. 正则扩展
{
// // ES5的正则对象构造函数
let regex = new RegExp('xyz', 'i'); // 第一个参数是字符串,第二个是修饰符
let regex2 = new RegExp(/xyz/i); // 第一个参数是正则表达式,不接受第二个参数,否则会报错
console.log(regex.test('xyz123'), regex2.test('xyz123')); // true, true
let regex3 = new RegExp(/abc/ig, 'i');
console.log(regex3.flags); // 原有正则对象的修饰符是ig,它会被第二个参数i覆盖
}
// 字符串对象的4个使用正则表达式的方法: match(),replace(),search(),split()这四个方法全部调用RegExp的实例的方法。
// {
// let regex = new RegExp('xyz', 'ig');
// console.log(regex.test('xyz0XYZ1xyz2'), regex.exec('xyz0XYZ1xyz2'));
// }
// y修饰符
{
let s = 'bbbb_bbb_bb_b';
let a1 = /b+/g;
let a2 = /b+/y;
console.log(a1.exec(s), a2.exec(s)); // ["bbbb"],["bbbb"]
console.log(a1.exec(s), a2.exec(s)); // ["bbb"],null
console.log(a1.sticky, a2.sticky); //表示是否开启了粘连模式
}
// u修饰符(Unicode编码,正则表达式中待匹配的字符串含有大于0xFFFF的字符则必须加u)
{
console.log('u修饰符', /^\uD83D/.test('\uD83D\uDC2A')); // true
console.log('u修饰符', /^\uD83D/u.test('\uD83D\uDC2A')); // false(u把后面当成一个字符)
// 大括号表示Unicode字符,只有加上u才能识别
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'));
}
4. 字符串扩展
// Unicode字符表示
{
console.log('a', `\u0061`); // 反引号把Unicode转换成字符串
console.log('s', `\u20BB7`); // 大于0xFFFF时不能按一个字符处理,需要使用花括号
console.log('s', `\u{20BB7}`);
}
{
let s = '𠮷';
console.log('length', s.length); // 2
console.log('0', s.charAt(0));
console.log('1', s.charAt(1));
console.log('at0', s.charCodeAt(0));
console.log('at1', s.charCodeAt(1));
let s1 = '𠮷a';
console.log('length', s1.length);
console.log('code0', s1.codePointAt(0)); // 134071(10进制)
console.log('code0', s1.codePointAt(0).toString(16)); // 20BB7(16禁止)
console.log('code1', s1.codePointAt(1)); // 57271
console.log('code2', s1.codePointAt(2));
}
{
console.log(String.fromCharCode("0x20bb7")); // xxx
console.log(String.fromCodePoint("0x20bb7")); // 吉
}
{
let str = '\u{20bb7}abc';
for (let i = 0; i < str.length; i++) {
console.log('es5', str[i]);
}
for (let code of str) { // 字符串遍历
console.log('es6', code);
}
}
// 字符串扩展
{
let str = "string";
console.log('includes', str.includes("c"));
console.log('start', str.startsWith('str'));
console.log('end', str.endsWith('ng'));
}
{
let str = "abc";
console.log(str.repeat(2)); // 字符串重复2此
}
// 字符串模板
{
let name = "list";
let info = "hello world";
let m = `i am ${name},${info}`; // 反引号定义嵌入模板字符串(scala为s,python为f)
console.log(m);
}
{
console.log('1'.padStart(2, '0')); // 字符串必须满足长度为2,不足则以0补全
console.log('1'.padEnd(2, '0'));
}
{
// 标签模板(防止csrf攻击)
let user = {
name: 'list',
info: 'hello world'
};
console.log(`i am ${user.name},${user.info}`); // i am list,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
}
}
{
console.log(String.raw`Hi\n${1 + 2}`); // 对所有\转义
console.log(`Hi\n${1 + 2}`);
}
5. 数值扩展
{
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.1', Number.isInteger('25')); // false
}
{
console.log(Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER);
console.log('10', Number.isSafeInteger(10)); // // 是否在正负2^50之间
console.log('a', Number.isSafeInteger('a'));
}
{
console.log(4.1, Math.trunc(4.1)); // 取整数部分
console.log(4.9, Math.trunc(4.9));
}
{
console.log('-5', Math.sign(-5)); // -1
console.log('0', Math.sign(0)); // 0
console.log('5', Math.sign(5));
console.log('50', Math.sign('50')); // 1
console.log('foo', Math.sign('foo')); // NaN
}
{
console.log('-1', Math.cbrt(-1)); // 立方根
console.log('8', Math.cbrt(8));
}
6. 数组扩展
{
let arr = Array.of(3, 4, 7, 9, 11);
console.log('arr=', arr);
let empty = Array.of();
console.log('empty', empty);
}
{
let p = document.querySelectorAll('p'); // 获取所有p标签
let pArr = Array.from(p); // 把p标签集合转化为数组
pArr.forEach(function (item) {
console.log(item.textContent);
});
console.log(Array.from([1, 3, 5], function (item) { // 相当于map()函数
return item * 2
}));
}
{
console.log('fill-7', [1, 'a', undefined].fill(7)); // 把数组元素替换为7
console.log('fill,pos', ['a', 'b', 'c'].fill(7, 1, 3)); // 从下标为1开始、一直到第3个都替换为7
}
{
// 需要import Lottery from './lottery';
for (let index of ['1', 'c', 'ks'].keys()) { // 获取数组下标
console.log('keys', index);
}
for (let value of ['1', 'c', 'ks'].values()) { // 获取数组值
console.log('values', value);
}
for (let [index, value] of ['1', 'c', 'ks'].entries()) { // 相当与python的enumerate
console.log('values', index, value);
}
}
{
console.log([1, 2, 3, 4, 5].copyWithin(0, 3, 4));
}
{
console.log([1, 2, 3, 4, 5, 6].find(function (item) { // 查找第一个满足条件的元素
return item > 3
}));
console.log([1, 2, 3, 4, 5, 6].findIndex(function (item) {
return item > 3
}));
}
{
console.log('number', [1, 2, NaN].includes(1)); // 判断是否包含元素
console.log('number', [1, 2, NaN].includes(NaN));
}
7. 函数扩展
// 默认参数
{
function test(x, y = 'world') {
console.log('默认值', x, y);
}
test('hello');
test('hello', 'kill');
}
{
let x = 'test';
function test2(x, y = x) {
console.log('作用域', x, y);
}
function test3(c, y = x) {
console.log('作用域', c, y);
}
test2('kill'); // kill, kill
test(); // undefined, undefined
test3('kill') // kill, test
}
// 动态参数
{
function test3(...arg) {
for (let v of arg) {
console.log('rest', v);
}
}
test3(1, 2, 3, 4, 'a');
}
// 扩展运算符
{
console.log(...[1, 2, 4]); // 1, 2, 4,把数组拆成三个离散值
console.log('a', ...[1, 2, 4]);
}
// 箭头函数(匿名函数)
{
let arrow = v => v * 2;
let arrow2 = () => 5; // 无参数时用()
console.log('arrow', arrow(3));
console.log(arrow2());
}
// 尾调用(提升性能)
{
function tail(x) {
console.log('tail', x);
}
function fx(x) { // 返回tail函数的调用结果
return tail(x)
}
fx(123)
}
8. 对象扩展
{
let o = 1;
let k = 2;
// ES5对象
let es5 = {
o: o,
k: k
};
// ES6对象
let es6 = {
o,
k
};
console.log(es5, es6);
// ES5方法
let es5_method = {
hello: function () {
console.log('hello');
}
};
// ES6方法
let es6_method = {
hello() {
console.log('hello');
}
};
console.log(es5_method.hello(), es6_method.hello());
}
{
// ES5
let a = 'b';
let es5_obj = {
a: 'c',
b: 'c'
};
// ES6(key可以为变量)
let es6_obj = {
[a]: 'c'
};
console.log(es5_obj, es6_obj);
}
{
console.log('字符串', Object.is('abc', 'abc'), 'abc' === 'abc'); // true, true
console.log('数组', Object.is([], []), [] === []); // true, true
console.log('拷贝', Object.assign({a: 'a'}, {b: 'b'})); // 两个对象合并成一个(不拷贝继承、不可枚举的属性)
let test = {k: 123, o: 456};
for (let [key, value] of Object.entries(test)) { // 相当python的items()
console.log([key, value]);
}
}
// {
// // 扩展运算符
// let {a, b, ...c} = {a: 'test', b: 'kill', c: 'ddd', d: 'ccc'};
// c = {
// c: 'ddd',
// d: 'ccc'
// }
// }
9. 唯一类型:Symbol
// Symbol:独一无二的值
{
// 声明
let a1 = Symbol();
let a2 = Symbol();
console.log(a1 === a2); // false
let a3 = Symbol.for('a3'); // 类似于“常量池”
let a4 = Symbol.for('a3');
console.log(a3 === a4); // true
}
{
let a1 = Symbol.for('abc');
let obj = {
[a1]: '123', // 如a1的值不是Symbol则会报错
'abc': 345,
'c': 456
};
console.log('obj', obj); // 则对象中的key有Symbol('123')、'123'和'c'
for (let [key, value] of Object.entries(obj)) { // 获取对象中非Symbol属性
console.log('let of', key, value);
}
Object.getOwnPropertySymbols(obj).forEach(function (item) { // 获取对象中的Symbol属性
console.log(obj[item]);
});
Reflect.ownKeys(obj).forEach(function (item) { // 获取对象中所有属性
console.log('ownkeys', item, obj[item]);
})
}
10. 数据结构Set、Map
// Set
{
let list = new Set();
list.add(5);
list.add(7);
console.log('size', list.size); // 2
}
{
let arr = [1, 2, 3, 4, 5];
let list = new Set(arr);
console.log('size', list.size);
}
{
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')); // 存在于集合
console.log('delete', list.delete('add'), list); // 从集合中删除
list.clear();
console.log('list', list);
}
{
let arr = ['add', 'delete', 'clear', 'has'];
let list = new Set(arr);
for (let key of list.keys()) { // key和value是一样的
console.log('keys', key);
}
for (let value of list.values()) {
console.log('value', value);
}
for (let [key, value] of list.entries()) {
console.log('entries', key, value);
}
list.forEach(function (item) {
console.log(item);
})
}
// WeakSet,元素只能是对象(弱引用,不检测GC),不能遍历
{
let weakList = new WeakSet();
let arg = {};
weakList.add(arg);
// weakList.add(2); // 不能存放对象以外的值
console.log('weakList', weakList);
}
// Map
{
let map = new Map();
let arr = ['123'];
map.set(arr, 456); // 注意添加元素方法与Set不同
console.log('map', map, map.get(arr));
}
{
let map = new Map([['a', 123], ['b', 456]]);
console.log('map args', map); // Map {"a" => 123, "b" => 456}
console.log('size', map.size); // 2
console.log('delete', map.delete('a'), map); // Map {"b" => 456}
console.log('clear', map.clear(), map); // Map {}
// 遍历方法与Set一样
}
// WeakMap
{
let weakmap = new WeakMap();
let o = {};
weakmap.set(o, 123);
console.log(weakmap.get(o));
}
// Map、Array对比(增查改删)
{
let map = new Map();
let array = [];
map.set('t', 1); // 加入一个key-value
array.push({t: 1}); // 加入一个存在t属性为1的元素
let map_exist = map.has('t'); // true
let array_exist = array.find(i => i.t); // Object {t: 1}
map.set('t', 2); // 把key为t的value修改为2
array.forEach(i => i.t? i.t = 2: ''); // 先在数组中找到存在t属性的元素,再把它改为2,否则不操作
map.delete('t');
let index = array.findIndex(i => i.t); // 删除存在t属性的元素
array.splice(index, 1)
}
// Set、Array对比(增查改删)
{
let set = new Set();
let array = [];
set.add({t: 1});
array.push({t: 1});
let set_exist = set.has({t: 1}); // 查不到(不能根据对象来查,应该在加入前先保存其引用,通过引用来查)
let array_exist = array.find(i => i.t); // Object {t: 1}
set.forEach(i => i.t? i.t = 2: '');
array.forEach(i => i.t? i.t = 2: ''); // 先在数组中找到存在t属性的元素,再把它改为2,否则不操作
set.forEach(i => i.t? set.delete(i): ''); // 遍历,根据值删除
let index = array.findIndex(i => i.t); // 删除存在t属性的元素(根据索引)
array.splice(index, 1)
}
// 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;
let map_exist = map.has('t');
let set_exist = set.has(item);
let obj_exist = 't' in obj;
map.set('t', 2);
item.t = 2; // 对于Set,直接修改所存放的引用,不需要在Set中修改
obj['t'] = 2;
map.delete('t');
set.delete(item);
delete obj['t'];
}
// 优先使用Map,需确保唯一时使用Set
11. 代理:Proxy和Reflect
// Proxy
{
// 原始对象(存放数据)
let obj = {
time: '2017-03-11',
name: 'net',
_r: 123
};
// 代理对象(存放访问方式)
let monitor = new Proxy(
obj,
{
// monitor.time,代理对象属性的读取,把从obj取出的time属性值中的2017修改为2018并返回
get(target, key) {
return target[key].replace('2017', '2018')
},
// monitor.name = 'test',代理对象设置属性,只允许修改name属性
set(target, key, value) {
if (key === 'name') {
return target[key] = value;
}
else {
return target[key];
}
},
// 'name' in monitor,代理key in object操作,只允许访问name属性
has(target, key) {
if (key === 'name') {
return target[key]
}
else {
return false;
}
},
// delete monitor.name,代理delete
deleteProperty(target, key) {
if (key.indexOf('_') > -1) {
delete target[key];
return true;
}
else {
return target[key]
}
},
// monitor.keys,代理Object.keys, Object.getOwnPropertySymbols, Object.getOwnPropertyNames
ownKeys(target) {
return Object.keys(target).filter(item => item != 'time')
}
}
);
console.log('get', monitor.time);
monitor.time = '2018';
monitor.name = 'mukewang';
console.log('set', monitor.time, monitor);
console.log('has', 'name' in monitor, 'time' in monitor);
delete monitor.time;
console.log('delete',monitor);
delete monitor._r;
console.log('delete',monitor);
console.log('ownKeys', Object.keys(monitor));
}
// Reflect
{
let obj = {
time: '2017-03-11',
name: 'net',
_r: 123
};
console.log('Reflect get', Reflect.get(obj, 'time'));
Reflect.set(obj, 'name', 'mukewang');
console.log(obj);
console.log('has', Reflect.has(obj, 'name'));
}
// 实践
{
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}`);
}
else
throw Error(`${key} 不存在`);
}
}
)
}
const personValidators = {
name(val) {
return typeof val === 'string';
},
age(val) {
return typeof val === 'number' && val > 18;
}
};
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
return validator(this, personValidators);
}
}
const person = new Person('lilei', 30);
console.info(person);
}
12. 类与对象
{
// 基本定义和生成实例
class Parent {
constructor(name = 'mukewang') {
this.name = name;
}
}
let v_parent = new Parent('v');
console.log('构造函数和实例', v_parent);
}
{
// 继承
class Parent {
constructor(name = 'mukewang') {
this.name = name;
}
}
class Child extends Parent {
}
console.log('继承', new Child());
}
{
// 继承传递参数
class Parent {
constructor(name = 'mukewang') {
this.name = name;
}
}
class Child extends Parent {
constructor(name = 'child') {
super(name);
this.type = 'child';
}
}
console.log('继承传递参数', new Child('hello'));
}
{
// getter,setter
class Parent {
constructor(name = 'mukewang') {
this.name = name;
}
get longName() {
return 'mk' + this.name
}
set longName(value) {
this.name = value;
}
}
let v = new Parent();
console.log('getter', v.longName);
v.longName = 'hello';
console.log('setter', v.longName);
}
{
// 静态方法
class Parent {
constructor(name = 'mukewang') {
this.name = name;
}
static tell() {
console.log('tell');
}
}
Parent.tell();
}
{
// 静态属性
class Parent {
constructor(name = 'mukewang') {
this.name = name;
}
static tell() {
console.log('tell');
}
}
Parent.type = 'test';
console.log('静态属性', Parent.type);
}
13. 异步:Promise
{
// 基本定义
let ajax = function (callback) {
console.log('执行'); // 回调:先输出执行,1s后才执行下面的函数
setTimeout(function () {
callback && callback.call()
}, 1000);
};
ajax(function () {
console.log('timeout1');
})
}
{
let ajax = function () {
console.log('执行2');
return new Promise(
function (resolve, reject) {
setTimeout(function () {
resolve()
}, 1000);
}
)
};
ajax().then(function () {
console.log('promise', 'timeout2');
// 使用ajax()返回的对象,执行下一步操作,then的第一个参数即Promise中的resolve
}, '')
}
{
let ajax = function () {
console.log('执行3');
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve()
}, 1000);
})
};
ajax() // 执行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);
}) // 执行ajax中的下一步操作
.catch(function (err) {
console.log('catch', err);
}); // 处理ajax中出现的异常
ajax(3)
.then(function () {
console.log('log', 3);
})
.catch(function (err) {
console.log('catch', err);
});
}
// 模拟加载图片:所有图片加载完成才显示
{
// 图片记载完再添加到页面
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.all([ // 数组所有promise实例视为一个,当所有promise实例发生变化时才会执行then
loadImg('http://xxxx'),
loadImg('http://xxx')
//
]).then(showImgs)
}
// 模拟加载图片:先加载完先显示
{
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://xxxx'),
loadImg('http://xxx')
]).then(showImgs)
}
14. 迭代器:iterator
// 使用for...of必须实现iterator接口
{
let arr = ['hello', 'world'];
let map = arr[Symbol.iterator](); // 创建迭代器
console.log(map.next());
console.log(map.next());
console.log(map.next());
}
// 可迭代对象
{
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);
}
{
let arr = ['hello', 'world'];
for (let value of arr)
console.log('value', value);
}
15. 生成器:generator
{
// genertaor基本定义
let tell = function* () {
yield 'a';
yield 'b';
return 'c'
};
// 每次调用next时会调用yield之前的语句,然后停止等待下一次调用以此类推
let k = tell();
console.log(k.next());
console.log(k.next());
console.log(k.next());
console.log(k.next());
}
// 使用generator实现迭代
{
let obj = {};
obj[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
};
for (let value of obj)
console.log('value', value);
}
// 使用generator实现状态机
{
let state = function* () {
while (1) {
yield 'A';
yield 'B';
yield '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 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.log(`剩余${count}次`);
};
let residue = function* (count) {
while (count > 0) {
count--;
yield draw(count);
}
};
let star = residue(5); // 初始抽奖次数
let btn = document.createElement('buttot');
btn.id = 'start';
btn.textContent = '抽奖';
document.body.appendChild(btn);
document
.getElementById('start')
.addEventListener('click', function () {
star.next();
}, false)
}
// 长轮询(Websocket浏览器兼容性不好)
{
let ajax = function* () {
yield new Promise(
function (resolve, reject) {
setTimeout(
function () {
resolve({code: 0}) // 成功后返回{code: 0}
}, 200 // 等待200毫秒
)
}
)
};
let pull = function () {
let generator = ajax();
let step = generator.next();
step.value.then(
function (d) {
if (d.code != 0) // 返回状态不为0,则继续轮询,间隔1秒
setTimeout(
function () {
console.log('wait');
pull()
}, 1000
);
else
console.info(d);
}
)
}
}
16. 装饰器:decorator
// 使用装饰器函数扩展类的功能
{
let readonly = function (target, name, descriptor) {
descriptor.writable = false;
return descriptor
};
class Test {
@readonly
time() {
return '2017-03-11'
}
}
let test = new Test();
// test.time=function(){
// console.log('reset time');
// };
console.log(test.time());
}
{
let typename = function (target, name, descriptor) {
target.myname = 'hello';
};
@typename
class Test {
}
console.log('类修饰符', Test.myname);
// 第三方库修饰器的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('show');
}
@log('click')
click() {
console.info('click');
}
}
let ad = new AD();
ad.show();
ad.click();
}
网友评论