Symbol
ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值
let s1 = Symbol('aa');let s2 = Symbol('aa');console.log(s1 === s2); //falselet s3 = Symbol.for('aa'); // 声明全新的let s4 = Symbol.for('aa') // 把之前声明的拿过来用console.log(s3 === s4) //true
Symbol属性默认是不能枚举
let obj = {name:'ccc',age:111,[s1]: 'ok'}for(let key in obj){console.log(obj[key]); // "ccc" 111}// 获取所有symbolconsole.log(Object.getOwnPropertySymbols(obj)); //[ Symbol(aa) ]// 获取普通类型的keyconsole.log(Object.keys(obj)); //[ 'name', 'age' ]
元编程的能力
// 判断类型时 Object.prototype.toString.call()let obj1 = {[Symbol.toStringTag]:'hhhh'}console.log(Object.prototype.toString.call(obj1)) //[object hhhh]
// 隐式类型转化let obj = {[Symbol.toPrimitive](type){return '123'}};console.log(obj + '1');
let instance = {[Symbol.hasInstance](value){return 'name' in value}}console.log({name:'aaaa'} instanceof instance); //true
Reflect
- Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法
 - Reflect 不是一个构造函数,因此它是不能用 new 构造的
 
// ES6 后续新增的方法都放在Reflect上
let s1 = Symbol('aaa');let obj = {name:'n',age:12,[s1]: 'ok'}Reflect.ownKeys(obj).forEach(item=>{ // 获取所有的key属性console.log(item) //name age Symbol(aaa)})
const fn = (a,b) =>{console.log('fn',a,b)}// 自定了一个apply 会默认调用他fn.apply = function () { //console.log('apply');}// 想调用函数本身的apply方法如何调用Function.prototype.apply.call(fn,null,[1,2]);Reflect.apply(fn,null,[1,2])
Reflect 有13种方法
Reflect.apply(target, thisArg, args)Reflect.construct(target, args)Reflect.get(target, name, receiver)Reflect.set(target, name, value, receiver)Reflect.defineProperty(target, name, desc)Reflect.deleteProperty(target, name)Reflect.has(target, name)Reflect.ownKeys(target)Reflect.isExtensible(target)Reflect.preventExtensions(target)Reflect.getOwnPropertyDescriptor(target, name)Reflect.getPrototypeOf(target)Reflect.setPrototypeOf(target, prototype)
Set/Map
console.log(Object.prototype.toString.call(new Map())); //[object Map]console.log(Object.prototype.toString.call(new Set())); //[object set]
let set = new Set([1, 2, 1, 1, 2, 1, 1, 3, 'a']);set.add({ a: 1 });set.add({ a: 1 }); // 两个对象不相同console.log(set.entries(set));console.log(set.has(5))// false
function union(arr1,arr2){// 内部他有Symbol.iterator方法let s = new Set([...arr1,...arr2]); // 集合 集合可以被迭代return [...s]}console.log(union(arr1,arr2))function intersection(arr1,arr2){let s1 = new Set(arr1); // forEachlet s2 = new Set(arr2);return [...s1].filter(item=>{return s2.has(item)})}console.log(intersection(arr1,arr2))
let map = new Map([ // 不能有重复的key,重复的会覆盖掉['a', 1],['v', 1],['v', 1]])map.set({a:1},2);// 他的key 可以使用对象类型console.log(map)
weakMap 弱引用
class MyTest{};let my = new MyTest(); // 对象let map = new WeakMap(); // key 只能是对象map.set(my,1);my = null;//当你给一个变量设置为null的时候 不会马上回收,会在合适的机会自己情况map 引用的对象 不会被回收掉weakMap引用的对象被置为null 时,后续会被清空
展开符/深拷贝
let o1 = {name:'zf'};let o2 = {age:{n:12}};//展开符是浅拷贝,和 Object.assign()类似let assgin = {...o1,...o2};o2.age.n = 13console.log(assgin) //{ name: 'zf', age: { n: 13 } }
深拷贝
function deepClone(obj,hash = new WeakMap()){// vue3 记录拷贝前和拷贝后的对应关系if(obj == null) return obj;if(obj instanceof RegExp) return new RegExp(obj);if(obj instanceof Date) return new Date(obj);// .... 基本类型和函数if(typeof obj !== 'object') return obj;// 对象类型 obj 数组 :[] 和 对象: {}//解决循环引用if(hash.has(obj)) return hash.get(obj); // 返回上次拷贝的结果 不在递归了const copy = new obj.constructor;hash.set(obj,copy); // 引用类型for(let key in obj){if(obj.hasOwnProperty(key)){copy[key] = deepClone(obj[key],hash)}}return copy}
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
手写实现:```javascriptArray.prototype.reduce = function(callback,prev){for(let i = 0; i < this.length;i++){if(!prev){prev = callback(this[i],this[i+1],i+1,this);i++; // 下次 从3开始}else{prev = callback(prev,this[i],i,this)}}return prev;}
实现 compose
组合函数
const compose = (...fns) => (...args) => {let lastFn = fns.pop();return fns.reduceRight((prev, current) => current(prev), lastFn(...args))}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
// Vue2 中用的是defineProperty 他的特点就是给本来的属性可以用此方法来定义,// 并且可以把值转化成 get和setlet obj = {};// 使用defineProperty 需要定义第三方参数才能 控制set和 getlet _value;Object.defineProperty(obj, 'a', {// 描述符号enumerable: true, // 遍历对象可以被遍历configurable: true, // 可以被删除writable:true,get() {return _value},set(newValue) {_value = newValue}})obj.a = 100;console.log(obj.a)// 把对象的属性 全部转化成 getter + setter,// 遍历所有对象,用Object.defineProperty重新定义属性 性能不好// 如果是数组 采用这种方式 性能很差// 如果对象里面嵌套对象 我需要递归处理// 没有对obj的属性进行重写,而且不需要递归// 放访问到的属性是对象时在代理即可let proxy = new Proxy(obj, {get() { //proxy.xxx},set() { // proxy.xxx = 100},has() { // 'xxx' in proxy},deleteProperty(){ // 删除属性的时候后执行此方法},ownKeys(){ // Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols}}); // proxy 是es6 的api 不用改写原对象 ,但是兼容差
