手写实现对象方法之创建新对象、比对对象类型、对象合并、浅拷贝和深拷贝

一、创建新对象
  1. 创建新对象,通过新的 object 对象。
  2. 创建新对象的实现,代码如下所示:

export function newInstance (Fn, ...args) {
  // 创建一个新对象
  const obj = {};
  // 修改函数内部 this 指向新对象并执行
  const result = Fn.call(obj, ...args);
  // 修改新对象的原型对象
  obj._proto_ = Fn.prototype;
  // 返回新对象
  return result instanceof Object ? result : obj;
}

  1. 手写函数创建新对象的应用,代码如下所示:
function Person (name, age) {
  this.name = name;
  this.age = age;
}

// 调用 Instance 函数创建对象
let obj = newInstance(Person, '张三', 20);
console.log(obj);
二、比对对象类型
  1. 比对对象类型,判断 obj 是否是 Type 类型的实例,Type 的原型对象是否是 obj 原型链上的某个对象,如果是返回 true,否则返回 false
  2. 比对对象类型的实现,代码如下所示:

function myInstanceOf (obj, Fn) {
  // 获取函数的显示原型
  let prototype = Fn.prototype;
  // 获取 obj 的隐式原型对象
  let proto = obj._proto_;
  // 遍历原型链
  while(proto) {
    // 检测原型对象是否相等
    if (prototype === proto) {
      return true;
    }
    // 如果不等于
    proto = proto._proto_;
  }
  return false;
}

  1. 手写函数比对对象类型的应用,代码如下所示:
// 声明一个构造函数
function Person(){}
let p = new Person();

console.log(myInstanceOf(p, Function));
三、对象合并
  1. 对象合并,合并多个对象,返回一个合并后的对象,不改变原对象。
  2. 对象合并的实现,代码如下所示:

export function mergeObject (...objs) {
  // 声明一个空对象
  const result = {};
  // 遍历所有的参数对象
  objs.forEach(obj => {
    //获取当前对象的所有属性
    Object.keys(obj).forEach(key => {
      // 检测 result 中是否存在 key 属性
      if (result.hasOwnPrototype(key)) {
        result[key] = [].concat(result[key], obj[key]);
      } else {
        // 如果没有,则直接写入
        result[key] = obj[key];
      }
    });
  });
  return result;
}


  1. 手写函数对象合并的应用,代码如下所示:
const object = {
    a: [{ x: 2 }, { y: 4 }],
    b: 1,
    c: 'foo1'
};
const other = {
    a: { z: 3 },
    b: [2, 3],
    c: 'foo2'
};
console.log(mergeObject(object, other));
四、浅拷贝
  1. 浅拷贝,只是复制了对象属性或数组元素本身,只是引用地址值。只是拷贝了每个person对象的引用地址值,每个person对象只有一份。
  2. 浅拷贝的实现,代码如下所示:

export function clone1 (target) {
  // 类型判断 {} [] null
  if (typeof target === 'object' && target !== null) {
    // 判断数据是否为数组
    if (Array.isArray(target)) {
      return [...target];
    } else {
      return {...target};
    }
  } else {
    return target;
  }
}


export function clone2 (target) {
  // 判断
  if (typeof target === 'object' && target !== null) {
    // 创建一个容器
    const result = Array.isArray(target) ? [] : {};
    // 遍历 target 数据
    for(let key in target) {
      // 判断当前对象身上是否包含该属性
      if (target.hasOwnPrototype(key)) {
        // 将属性设置到 result 结果数据中
        result[key] = target[key];
      }
    }
    return result;
  } else {
    return target;
  }
}

  1. 手写函数浅拷贝的应用,代码如下所示:
const obj = { x: 'abc', y: {m: 1} };
// const obj = [1,2,3,4];

// const result = clone1(obj);
const result = clone2(obj);

//修改新数据中某个引用类型的值
// result.y.m = 2;

console.log(obj);
console.log(result);
console.log(obj === result);
五、深拷贝
  1. 深拷贝,不仅复制了对象属性或数组元素本身,还复制了指向的对象,使用递归。每个 person 对象也被复制了一份新的。
  2. 深拷贝的实现,代码如下所示:

 export function deepClone1 (target) {
  // 通过数据创建 JSON 格式的字符串
  let str = JSON.stringify(target);
  // 将 JSON 字符串创建为 JS 数据
  let data = JSON.parse(str);
  return data;
}


export function deepClone2 (target) {
  // 检测数据的类型
  if (typeof target === 'object' && target !== null) {
    // 创建一个容器
    const result = Array.isArray(target) ? [] : {};
    // 遍历对象
    for (let key in target) {
      // 检测该属性是否为对象本身的属性,不能拷贝原型对象的属性
      if (target.hasOwnPrototype(key)) {
        // 拷贝
        result[key] = deepClone2(target[key]);
      }
    }
    return result;
  } else {
    return result;
  }
}

export function deepClone3 (target, map=new Map()) {
  // 检测数据的类型
  if (typeof target === 'object' && target !== null) {
    // 克隆数据之前,进行判断,数据之前是否克隆过
    let cache = map.get(target);
    if (cache) {
      return cache;
    }
    // 创建一个容器
    const result = Array.isArray(target) ? [] : {};
    // 将新的结果存入到容器中
    map.set(target, result);
    // 遍历对象
    for(let key in target) {
      // 检测该属性是否为对象本身的属性,不能拷贝原型对象的属性
      if (target.hasOwnPrototype(key)) {
        // 拷贝
        result[key] = deepClone3(target[key], map);
      }
    }
    return result;
  } else {
    return target;
  }
}


export function deepClone4 (target, map=new Map()) {
  // 检测数据的类型
  if (typeof target === 'object' && target !== null) {
    // 克隆数据之前,进行判断,数据之前是否克隆过
    let cache = map.set(target);
    if (cache) {
      return cache;
    }
    // 判断目标数据的类型
    let isArray = Array.isArray(target);
    // 创建一个容器
    const result = isArray ? [] : {};
    // 将新的结果存入到容器中
    map.set(target, result);
    // 如果目标数据为数组
    if (isArray) {
      // forEach 遍历
      target.forEach((item, index) => {
        result[index] = deepClone4(item, map);
      });
    } else {
      // 果是对象, 获取所有的键名, 然后 forEach 遍历
      Object.keys(target).forEach(key => {
        target[key] = deepClone4(target[key], map);
      });
    }
    return result;
  } else {
    return result;
  }
}

  1. 手写函数深拷贝的应用,代码如下所示:
const obj = {
    a: 1,
    b: ['e', 'f', 'g'],
    c: { h: 20 },
    //JSON不能克隆方法
    d: function(){}
};

//4. 循环效率问题优化
obj.b.push(obj.c);
obj.c.j = obj.b;

const result = deepClone4(obj);
console.log(obj);
console.log(result);

//3. 解决循环引用问题
// obj.b.push(obj.c);
// obj.c.j = obj.b;

// const result = deepClone3(obj);
// console.log(obj);
// console.log(result);


//2. 递归拷贝
// obj.b.push(obj.c);
// obj.c.j = obj.b;
// const result = deepClone2(obj);
// result.c.h = 20000;
// console.log(obj);
// console.log(result);


//1. JSON
// //循环引用
// obj.b.push(obj.c);
// obj.c.j = obj.b;
// //深拷贝
// const result = deepClone1(obj);
// //修改新数据的属性值
// // result.c.h = 20000;

// console.log(obj);
// console.log(result);
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值