美文网首页
ES6基础1-2(手写深拷贝、Vue数据劫持、Object.de

ES6基础1-2(手写深拷贝、Vue数据劫持、Object.de

作者: 星星的成长之路 | 来源:发表于2020-10-20 17:19 被阅读0次
    1.var都要改为let和const
    1. var声明的变量 (污染全局变量)
    2. 使用var导致变量提升的问题
    3. var可以被重复声明;let可以解决重复定义的问题
    4. var作用域的问题(全局作用域);let(函数作用域)
    2.常见的作用域

    全局作用域
    函数作用域
    块作用域{} + let

    3.let

    问题:暂存死区

    let a = 100;
    {
      console.log(a); //这里会报错:a is not defined
      //当前作用域有a,就不会去外面找;但是let不会变量提升,所以a在打印的时候还未被声明,不会是undefined
      let a = 200;
    }
    
    4.const 常量 不会变的量(地址不变即可)

    const的值习惯性大写

    const PI = { r: '3.14' };
    PI.r = 3.15; // 此时不会报错,地址没有变
    
    
    5.展开运算符...
    1. 数组和对象都可以使用
    2. ...只能拷贝一层,是浅拷贝
    3. 浅拷贝(拷贝之后还有关)
    4. 深拷贝(拷贝之后无关)
    5. Object.assign也是浅拷贝
    6.不靠谱的深拷贝尝试:

    我们可以把对象先转化成字符串 在把字符串转换成对象。会有一个问题,完全无法处理fn

    Object.assign = ...
    let school = {name:'zfpx',fn:function(){},aa:undefined,b:null,arr:[1,2,3,[4,5]]};
    let my = {age:{count:18},name:'jw'};
    let all = JSON.parse(JSON.stringify({...school,...my}));
    my.age.count = 100;
    console.log(all);
    
    7.自己实现一个深拷贝方法(递归拷贝)

    先掌握类型判断:

    • typeof
    • instanceof
    • Object.prototype.toString.call
    • constructor

    小技巧:

    • [].constructor 返回一个 fn,即:Array();new Array()返回[]
    • {}.constructor 返回一个fn,即:Object();new Object()返回{}
    • new obj.constructor会返回一个[]或者{}

    注意:

    • function直接返回;typeof function() {} == 'function'
    • Symbol不是对象,直接返回;typeof Symbol == 'function'
    • null == undefined true
    • 用weakMap来解决“循环引用”
    function deepClone(obj, hash = new WeakMap()) {
      if (obj == null) return obj; // 判断obj是null还是undefined
      if (obj instanceof Date) return new Date(obj);
      if (obj instanceof RegExp) return new RegExp(obj);
      if (typeof obj !== 'object') return obj; // 不是对象就不用拷贝了
      if (hash.has(obj)) return hash.get(obj); // 如果weakmap中有对象就直接返回之前拷贝过得obj
    
      let cloneObj = new obj.constructor(); // 适配数组和对象
     // 如果是对象把他放到weakMap中,如果再拷贝这个对象这个对象就存在了,直接返回这个对象即可
      hash.set(obj, cloneObj);   // 防止循环调用问题,(程序会崩溃)
    
      for (let key in obj) {
        if (obj.hasOwnProperty(key)) { // for in会遍历出原型上的属性
          // 只拷贝私有属性,不考虑原型链上的属性
          // 如果赋予的值是对象 我就把这个对象放到weakmap中
          cloneObj[key] = deepClone(obj[key], hash); // 实现深拷贝
        }
      }
    
      return cloneObj;
    }
    
    8.set
    • set是集合;不能重复的东西,否则就白放了;没顺序
    • Set有symbol.iterator能被迭代,能被...展开
    • add,delete 添加和删除
    • 基础类型 string number boolean undefined object symbol ???
    let s = new Set([1, 2, 3, 4, 1, 2, 3, 4]);
    console.log(s); // Set { 1, 2, 3, 4 }
    console.log(typeof s); // object
    s.add('5');
    s.delete('5');
    let arr = [...s]; // 有迭代,才能被展开
    console.log(arr); // [ 1, 2, 3, 4 ]
    

    集合:并集、交集、差集

    let s01 = [1, 2, 3, 1, 2, 6];
    let s02 = [3, 4, 5, 1, 2];
    
    // 并集:
    function union() {
      let s1 = new Set(s01);
      let s2 = new Set(s02);
      console.log([...new Set([...s1, ...s2])]);
    }
    union(); // [ 1, 2, 3, 6, 4, 5 ]
    
    // 交集:
    function intersection() {
      return [...new Set(s01)].filter(function (item) {
        // filter返回true表示留下
        return new Set(s02).has(item);
      });
    }
    console.log(intersection()); // [ 1, 2, 3 ]
    
    // 差集: 要看谁差谁,顺序不同结果也不同
    function diff() {
      return [...new Set(s01)].filter(function (item) {
        return !new Set(s02).has(item); // 跟intersection相比就加了一个!
      });
    }
    console.log(diff()); // [6]
    
    9.Map
    • map 映射表
    • 跟set唯一的不同是:map有key。
    • map也不能放重复的
    • 在Map里销毁obj,有引用关系。
    let m = new Map(); 
    m.set('name', '123');
    m.set('name', '111');
    let obj = { age: 1 };
    m.set(obj, '123');
    m.set(obj, '456'); // 这个obj的引用的空间被set所引用
    obj = null; // 把obj清空,但是这个空间还是在的
    console.log(m.obj); // undefined
    console.log(m); // Map { 'name' => '123', { age: 1 } => '456' }
    
    10.WeakMap
    • WeakMap的key,必须是对象类型,否则会报错:Invalid value used as weak map key;
    • 作为对象key的对象,其应用关系会被销毁掉。
    • 在WeakMap里可以销毁obj,因为没有引用关系,也不会再引用原来的对象。
    let m = new WeakMap(); 
    let obj = { age: 1 };
    m.set(obj, '123');
    obj = null; // 把obj清空,但是这个空间还是在的
    console.log(m.obj); // undefined
    console.log(m); // WeakMap { <items unknown> }
    
    11.weakMap和Map的区别(与回收机制有关
    1. weakMap是弱链接,可以清空,对象删除了也不会有引用关系。
    2. Map即便删除了,还是会有引用关系,会继续占用空间,不会被销毁。
    12.Object.defineProperty

    ES5语法,使用场景很多:vue,react...

    • 通过Object.defineProperty定义属性,可以增加拦截器;
    • 定义的属性是隐藏属性,不可枚举,不能用for...in遍历到。
    • 通过Object.defineProperty定义属性 可以增加拦截器
    • 只能用在对象上,数组是不行的
    let obj = {};
    let other = '';
    // 不可枚举 函数的原型 Array.protoype
    Object.defineProperty(obj, 'name', {
      enumerable: true, // 是否可以枚举
      configurable: true, // 是否可以配置: 能不能删除这个属性
      //writable:true, // 是否可以重写
      get() { // 读取方法
        console.log('----');
        return other;
      },
      set(val) {  // 设置方法
        other = val;
      }
    });
    // delete obj.name;  // 如果configurable为false,那么会删不掉对象的属性
    obj.name = 456;
    console.log(obj.name);  // 456
    
    13.对象的setter和getter(Vue中的数据双向绑定)
    let obj = {
      other: '123',
      get name() {
        return this.other;
      },
      set name(val) {
        this.other = val;
      }
    };
    obj.name = 456;
    console.log(obj.name);
    
    14.vue的数据劫持 (把所有的属性都改成 get和set方法)
    function update() {   // 模拟的更新方法
      console.log('更新视图');
    }
    let data = {
      name: 'zfpx',
      age: 18,
      address: {
        location: '回龙观'
      }
    };
    function observer(obj) {
      // Object.defineProperty只能用在 对象上 (数组也不识别)
      if (typeof obj !== 'object') return obj;
      for (let key in obj) {
        defineReactive(obj, key, obj[key]);
      }
    }
    // 定义响应式
    function defineReactive(obj, key, value) {
      observer(value); // 递归,嵌套的数据也会被观测到
      Object.defineProperty(obj, key, {
        get() {
          return value;
        },
        set(val) {
          if (val !== value) {
            observer(val);
            update();
            value = val;
          }
        }
      });
    }
    observer(data);
    data.address = [1, 2, 3];
    let methods = ['push', 'slice', 'pop', 'sort', 'reverse', 'unshift'];
    methods.forEach((method) => {
      // 面相切片开发 装饰器
      let oldMethod = Array.prototype[method];
      Array.prototype[method] = function () {
        update();
        oldMethod.call(this, ...arguments);
      };
    });
    data.address.push(4);
    data.address.push(4);
    
    15.箭头函数
    • 没有this,没有arguments
    • 53min开始举的this例子没看懂???
    • obj是一个对象,不是作用域,也就没有this
    • let声明的变量,不属于window属性;属于自己window下的作用域???
    let a = 1;
    let obj = { //obj是一个对象,不是作用域
      a: 2,
      fn: () => {
        setTimeout(() => {
          console.log(this.a); // undefined
          // 因为定时器是window在调用,let的a不会挂载到window上
        });
      }
    };
    obj.fn();
    

    相关文章

      网友评论

          本文标题:ES6基础1-2(手写深拷贝、Vue数据劫持、Object.de

          本文链接:https://www.haomeiwen.com/subject/woeopktx.html