💻在线代码调试:https://code.h5jun.com/?js,console

Symbol

ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值

  1. let s1 = Symbol('aa');
  2. let s2 = Symbol('aa');
  3. console.log(s1 === s2); //false
  4. let s3 = Symbol.for('aa'); // 声明全新的
  5. let s4 = Symbol.for('aa') // 把之前声明的拿过来用
  6. console.log(s3 === s4) //true

Symbol属性默认是不能枚举

  1. let obj = {
  2. name:'ccc',
  3. age:111,
  4. [s1]: 'ok'
  5. }
  6. for(let key in obj){
  7. console.log(obj[key]); // "ccc" 111
  8. }
  9. // 获取所有symbol
  10. console.log(Object.getOwnPropertySymbols(obj)); //[ Symbol(aa) ]
  11. // 获取普通类型的key
  12. console.log(Object.keys(obj)); //[ 'name', 'age' ]

元编程的能力

  1. // 判断类型时 Object.prototype.toString.call()
  2. let obj1 = {
  3. [Symbol.toStringTag]:'hhhh'
  4. }
  5. console.log(Object.prototype.toString.call(obj1)) //[object hhhh]
  1. // 隐式类型转化
  2. let obj = {
  3. [Symbol.toPrimitive](type){
  4. return '123'
  5. }
  6. };
  7. console.log(obj + '1');
  1. let instance = {
  2. [Symbol.hasInstance](value){
  3. return 'name' in value
  4. }
  5. }
  6. console.log({name:'aaaa'} instanceof instance); //true

Reflect

  • Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法
  • Reflect 不是一个构造函数,因此它是不能用 new 构造的

// ES6 后续新增的方法都放在Reflect上

  1. let s1 = Symbol('aaa');
  2. let obj = {
  3. name:'n',
  4. age:12,
  5. [s1]: 'ok'
  6. }
  7. Reflect.ownKeys(obj).forEach(item=>{ // 获取所有的key属性
  8. console.log(item) //name age Symbol(aaa)
  9. })
  1. const fn = (a,b) =>{
  2. console.log('fn',a,b)
  3. }
  4. // 自定了一个apply 会默认调用他
  5. fn.apply = function () { //
  6. console.log('apply');
  7. }
  8. // 想调用函数本身的apply方法如何调用
  9. Function.prototype.apply.call(fn,null,[1,2]);
  10. Reflect.apply(fn,null,[1,2])

Reflect 有13种方法

  1. Reflect.apply(target, thisArg, args)
  2. Reflect.construct(target, args)
  3. Reflect.get(target, name, receiver)
  4. Reflect.set(target, name, value, receiver)
  5. Reflect.defineProperty(target, name, desc)
  6. Reflect.deleteProperty(target, name)
  7. Reflect.has(target, name)
  8. Reflect.ownKeys(target)
  9. Reflect.isExtensible(target)
  10. Reflect.preventExtensions(target)
  11. Reflect.getOwnPropertyDescriptor(target, name)
  12. Reflect.getPrototypeOf(target)
  13. Reflect.setPrototypeOf(target, prototype)

Set/Map

  1. console.log(Object.prototype.toString.call(new Map())); //[object Map]
  2. console.log(Object.prototype.toString.call(new Set())); //[object set]
  1. let set = new Set([1, 2, 1, 1, 2, 1, 1, 3, 'a']);
  2. set.add({ a: 1 });
  3. set.add({ a: 1 }); // 两个对象不相同
  4. console.log(set.entries(set));
  5. console.log(set.has(5))// false
  1. function union(arr1,arr2){
  2. // 内部他有Symbol.iterator方法
  3. let s = new Set([...arr1,...arr2]); // 集合 集合可以被迭代
  4. return [...s]
  5. }
  6. console.log(union(arr1,arr2))
  7. function intersection(arr1,arr2){
  8. let s1 = new Set(arr1); // forEach
  9. let s2 = new Set(arr2);
  10. return [...s1].filter(item=>{
  11. return s2.has(item)
  12. })
  13. }
  14. console.log(intersection(arr1,arr2))
  1. let map = new Map([ // 不能有重复的key,重复的会覆盖掉
  2. ['a', 1],
  3. ['v', 1],
  4. ['v', 1]
  5. ])
  6. map.set({a:1},2);
  7. // 他的key 可以使用对象类型
  8. console.log(map)

weakMap 弱引用

  1. class MyTest{};
  2. let my = new MyTest(); // 对象
  3. let map = new WeakMap(); // key 只能是对象
  4. map.set(my,1);
  5. my = null;
  6. //当你给一个变量设置为null的时候 不会马上回收,会在合适的机会自己情况
  7. map 引用的对象 不会被回收掉
  8. weakMap引用的对象被置为null 时,后续会被清空

展开符/深拷贝

  1. let o1 = {name:'zf'};
  2. let o2 = {age:{n:12}};
  3. //展开符是浅拷贝,和 Object.assign()类似
  4. let assgin = {...o1,...o2};
  5. o2.age.n = 13
  6. console.log(assgin) //{ name: 'zf', age: { n: 13 } }

深拷贝

  1. function deepClone(obj,hash = new WeakMap()){// vue3 记录拷贝前和拷贝后的对应关系
  2. if(obj == null) return obj;
  3. if(obj instanceof RegExp) return new RegExp(obj);
  4. if(obj instanceof Date) return new Date(obj);
  5. // .... 基本类型和函数
  6. if(typeof obj !== 'object') return obj;
  7. // 对象类型 obj 数组 :[] 和 对象: {}
  8. //解决循环引用
  9. if(hash.has(obj)) return hash.get(obj); // 返回上次拷贝的结果 不在递归了
  10. const copy = new obj.constructor;
  11. hash.set(obj,copy); // 引用类型
  12. for(let key in obj){
  13. if(obj.hasOwnProperty(key)){
  14. copy[key] = deepClone(obj[key],hash)
  15. }
  16. }
  17. return copy
  18. }

reduce

是个收敛函数 可以把一个数组转化成其他格式

  • 数组不能为空 ```javascript let r = ([1, 2, 3, 4, 5]).reduce(function(previousValue, currentValue, index, arrary) { console.log(previousValue, currentValue) return previousValue + currentValue }); / 1 2 3 3 6 4 10 5 / console.log(r);//15

let r = ([1, 2, 3, 4, 5]).reduce(function(previousValue, currentValue, index, arrary) { return previousValue + currentValue },5); console.log(r);//20

  1. 手写实现:
  2. ```javascript
  3. Array.prototype.reduce = function(callback,prev){
  4. for(let i = 0; i < this.length;i++){
  5. if(!prev){
  6. prev = callback(this[i],this[i+1],i+1,this);
  7. i++; // 下次 从3开始
  8. }else{
  9. prev = callback(prev,this[i],i,this)
  10. }
  11. }
  12. return prev;
  13. }

实现 compose

组合函数

  1. const compose = (...fns) => (...args) => {
  2. let lastFn = fns.pop();
  3. return fns.reduceRight((prev, current) => current(prev), lastFn(...args))
  4. }
  5. const compose = (...fns) => fns.reduce((a, b) => (...args) => a(b(...args)))

Proxy

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy

  1. // Vue2 中用的是defineProperty 他的特点就是给本来的属性可以用此方法来定义,
  2. // 并且可以把值转化成 get和set
  3. let obj = {};
  4. // 使用defineProperty 需要定义第三方参数才能 控制set和 get
  5. let _value;
  6. Object.defineProperty(obj, 'a', {
  7. // 描述符号
  8. enumerable: true, // 遍历对象可以被遍历
  9. configurable: true, // 可以被删除
  10. writable:true,
  11. get() {
  12. return _value
  13. },
  14. set(newValue) {
  15. _value = newValue
  16. }
  17. })
  18. obj.a = 100;
  19. console.log(obj.a)
  20. // 把对象的属性 全部转化成 getter + setter,
  21. // 遍历所有对象,用Object.defineProperty重新定义属性 性能不好
  22. // 如果是数组 采用这种方式 性能很差
  23. // 如果对象里面嵌套对象 我需要递归处理
  24. // 没有对obj的属性进行重写,而且不需要递归
  25. // 放访问到的属性是对象时在代理即可
  26. let proxy = new Proxy(obj, {
  27. get() { //proxy.xxx
  28. },
  29. set() { // proxy.xxx = 100
  30. },
  31. has() { // 'xxx' in proxy
  32. },
  33. deleteProperty(){ // 删除属性的时候后执行此方法
  34. },
  35. ownKeys(){ // Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols
  36. }
  37. }); // proxy 是es6 的api 不用改写原对象 ,但是兼容差