ES6-10进阶学习作用域,win10命令行新建文件,类,正则u修饰符,模板字符串&函数,Reflect反射,Proxy,监控错误-拦截并上报,随机ID生成,yield,迭代器,Module

1、作用域

全局作用域
函数作用域( 局部作用域 )
块级作用域
动态作用域

全局作用域引申:

不通过var(var a = 1;)声明。而是直接声明的变量(a=1;),无论在哪均会挂载到 window对象上,作为window对象的属性(configurable为true)
var abc = '2016011172'; // 真全局变量,不可被delete。 
abcd = '石路'; // 伪全局变量,可被delete。被挂载到window上,作为属性

来自大佬:
ES6-10进阶学习作用域,win10命令行新建文件,类,正则u修饰符,模板字符串&函数,Reflect反射,Proxy,监控错误-拦截并上报,随机ID生成,yield,迭代器,Module_第1张图片

作用域链,会向上查找,不会向下查找。
// 闭包
var decLive = (function () {
  var live = 30;
  // 拿不到b
  function decline(count) {
    var b = 2;
    // 此处能向上查找,拿到live
    live = live - count
    return live > 0 ? live : '没命了';
  }
  return decline;
})();

2、win10命令行新建文件

PowerShell 中 new-item xxx.js 即可

3、类(杂记)

1、原型链的方式做继承:

Persons.prototype.say = function() { console.log('我是人类') };

2、类的静态方法拿不到实例对象的信息。

4、正则u修饰符(匹配标准unicode字节)

场景一:u前u后

var s = ''; // utf16编码字符 表示 4个字节的字符
var s2 = '\uD842\uDFB7'; // utf16编码 4个字节

console.log(/^\ud842/.test(s2)); // true × 
console.log(/^\ud842/u.test(s2)); // false √ 符合逻辑

正则默认只匹配 两个字节 的字符,而’’ 是 四个字节 的字符

如果不加u修饰,则就当常规匹配,匹配英文等(2个字节的字符)。
加了u修饰符,则可以会严格按照unicode码匹配(大于2个字节的字符),而 ‘\uD842\uDFB7’ 是4字节,是一个汉字。故\ud842 2字节是不匹配的。

场景二: 通过码点判断字符(任意字节)

/\u{61}/u.test('a'); // true a的码点:61
\u{20BB7}/u.test(''); // true 的码点: 20BB7
// 注: \u {} u修饰符  三者缺一不可

场景三: 量词

/{2}/.test(''); // false 因为该汉字为4字节,需要u修饰符,进行unicode多字节匹配。
/{2}/u.test(''); // true 

/[a-z]/i.test('\u212A') // false
/[a-z]/iu.test('\u212A') // true 212A是大写K的码点

总结: 到了es6,匹配字符,加个u 绝对没毛病,如果不加可能出现匹配异常。

5、模板字符串&函数

模板字符串 可以配合函数。

function price(string, ...args) {
  console.log(string); // ["您此次的", "字符串2", "字符串3", raw: Array(3)]
  console.log(args); // ["rabbit", "1"]
  return (string + args); 
}

let txt = price`您此次的${'rabbit'}字符串2${'1'}字符串3`;
console.log(txt); // 您此次的,字符串2,字符串3rabbit,1

6、Reflect反射

Reflect.apply(fn, ctx, [args])
const price = 13.8;
// es5 apply 非反射
const rs1 = Math.floor.apply(null, [price]); // 编译阶段已指定方法

// es6 Reflect.apply 反射
const rs2 = Reflect.apply(price > 100 ? Math.floor : Math.ceil, null, [price]) // 在执行阶段指定方法
console.log(rs1, rs2); // 13 14
Reflect.construct(class, [args])
const c1 = Reflect.construct(String, ['shoushou']);
console.log(c1); // String {"shoushou"}
Reflect.defineProperty(obj, field, opts)

使用方式和效果和Object.defineProperty基本一样,仅返回值不同。

Reflect.get(obj | array, key | index)
var obj = {a:1,b:2};
var arr = [2020,888];
Reflect.get(obj,'b') // 2
Reflect.get(arr,0) // 2020
Reflect其余静态方法

// 见console.log(Reflect)

Reflect.getOwnPropertyDescriptor(obj, field)

// 查看对象的所有属性的描述(enumerable,configurable,writable,…)

Reflect.has(obj,field)

// 对象是否拥有某属性

Reflect.isExtensiable(obj)

// 对象是否可扩展(有没有被freeze)

Reflect.getOwnPropertyDescriptor(obj, 'name');
// {value: "die", writable: true, enumerable: true, configurable: true}

7、Proxy

const obj = {
  name: '欢乐家园A栋501',
  price: 190
};

const p = new Proxy(obj, {
  get(target, key) {// target: 代理的对象,key: 读操作时的键值
    if (key === 'price') {
      return target[key] + 30;
    } else {
      return target[key];
    }
  }
});

console.log(p.name); // 欢乐家园A栋501
console.log(p.price); // 220
Proxy 的应用场景:

1、数据只读化

const obj = {
  name: '欢乐家园A栋501',
  price: 190
};

const p = new Proxy(obj, {
  // ... get
  set(target, key, value) {
    return false; // ++
  }
});

p.name = '卖nima的房子';
console.log(p.name); // 欢乐家园A栋501 // 中介已无权修改
obj.name = '卖nima的房子';
console.log(p.name); // 卖nima的房子 // 卖家自身可以修改

注: 虽然中介即遍历p,是只读的。但是obj自身还是可修改的。
这点和Object.freeze 不一样,后者是完全锁死,不能修改。

2、校验
// 即使用set进行if else逻辑处理。
3、监控(下述)

8、监控错误-拦截并上报

前言: 比如验证逻辑,我们应该解耦,尽量使函数满足多场景,强复用。而不是对每一个参数进行验证或者写重复逻辑。故,可以监控参数是否异常,进行异常的触发,然后交由某个收集者(如EventListener)进行汇总以及上报。


// 绑定监听器
window.addEventListener('error', (e) => {
  console.log('监控到错误: ', e.message);
}, true);

const obj = {
  name: '石路',
  age: 24
};

const p = new Proxy(obj, {
  set(target, key, value) {
    if (key === 'age') {
      if (value > 100) {
        throw new TypeError('age is exceed')
      } else {
        target[key] = value;
      }
    } else {
      return false;
    }
  }
});

p.age = 250;
console.log(obj); // 因触发Error 故,代码已被强行终止,log不会执行

9、随机ID生成

Math.random().toString(36).slice(-8) // "wy1lb7en"

10、generator - yield

1、yield * (带星号):跟上 可迭代的对象 | generator实例
2、高级用法,next传参

function* gen() {
  // next内的值,每次都替换上一次的 yield部分。
  // 而第一次没有yield可以替换。
  // 当next第二次传入后,开始替换 ,即20 + 7 = 27
  let val = (yield [1, 3, 5]) + 7;
  console.log(val);
}
let fn = gen();
console.log(fn.next(10)); //  {value: Array(3), done: false}
console.log(fn.next(20)); // 27 \n {value: undefined, done: true}

3、l.throw()外部抛出异常,内部try catch捕获

function* gen() {
  while (true) {
    try {
      yield 1;
    } catch (e) {
      console.log(e.message);
    }
  }
}

let g = gen();
console.log(g.next());
g.throw(new Error('nmb'));
console.log(g.next());

小结:
1、l.next() 会返回yield 携带的参数或generator实例
2、若next传入的参数会覆盖上一次yield返回值,控制下一次运行结果。
3、若next不传参数,上一次yield的返回值回undefined

11、迭代器相关

1、可代器协议
authors[Symbol.iterator] = function () { // Symbol.iterator 可迭代协议
2、迭代器协议
// ... Symbol.iterator function
return {
  next() {
    // 具有next方法 并返回指定结构    
  }
}
3、迭代器iterator与生成器generator
let authors = {
  allAuthors: {
    science: ['Ben', 'Kitty', 'Alice'],
    kartoon: ['AuToMan', 'FlashMan'],
    fantasy: ['SuperMan', 'SpiderMan', 'IronMan']
  },
  address: []
}
// 1、迭代器协议 正常代码逻辑
authors[Symbol.iterator] = function () { // Symbol.iterator 可迭代协议
  let allAuthors = this.allAuthors;
  let keys = Reflect.ownKeys(allAuthors);
  let currentKey = '';
  let currentVal = '';
  return {
    next() {
      if (!currentVal.length) {
        if (keys.length) {
          currentKey = keys.shift();
          currentVal = allAuthors[currentKey];
        }
      }
      return {
        value: currentVal.shift(),
        done: !keys.length && !currentVal.length
      }
    }
  }
};
for (let key of authors) {
  console.log(key);
}

// 2、迭代器协议 与 生成器的混合使用
authors[Symbol.iterator] = function* () {
  let allAuthors = this.allAuthors;
  let keys = Reflect.ownKeys(allAuthors);
  let currentKey = '';
  let currentVal = '';
  while (true) {
    if (!currentVal.length) {
      if (keys.length) {
        currentKey = keys.shift();
        currentVal = allAuthors[currentKey];
      } else {
        break;
      }
      yield currentVal.shift();
    } else {
      yield currentVal.shift();
    }
  }
};

for (let key of authors) {
  console.log(key);
}

两种迭代器方法都是为了个性化提取数据,而第二种显得更为优雅。

12、Module

注意点:
1、默认导出和花括号连用

// module.js
class Dog {
  say() {
    console.log('dog身体健康');
  }
}

class Cat {
  say() {
    console.log('cat身体健康');
  }
}

export default class People {
  say() {
    console.log('people身体健康');
  }
}

export {
  Dog,
  Cat
}

// enter.js
import P, { Dog, Cat } from './lesson2-14-mod';

2、星号导出(不能再括号导出)

import * as Mod  from '1.js' // *即将模块全部导入在Mod对象下

3、没有解构赋值,仅有 as 别名 // named Module

你可能感兴趣的:(ES6-10进阶学习作用域,win10命令行新建文件,类,正则u修饰符,模板字符串&函数,Reflect反射,Proxy,监控错误-拦截并上报,随机ID生成,yield,迭代器,Module)