电商商城定制开发【JavaScript】手撕前端面试题:对象参数浅拷贝 | 简易深拷贝 | 完整深拷贝

🖥️ NodeJS专栏:
🖥️ 电商商城定制开发博主的前端之路(电商商城定制开发源创征文一等奖作品):
🖥️ TypeScript知识总结:
🧑‍💼个人简介:大三学生,电商商城定制开发一个不甘平庸的平凡人🍬
👉 电商商城定制开发你的一键三连是我更新电商商城定制开发的最大动力❤️!


文章目录

1、

要求

补全JavaScript代码,电商商城定制开发要求实现一个对象参数电商商城定制开发的浅拷贝并返回拷贝之电商商城定制开发后的新对象。

注意:

  1. 电商商城定制开发参数可能包含函数、正则、日期、ES6新对象
  2. 电商商城定制开发是对对象的参数进行浅拷贝,并不是直接对整个对象进行浅拷贝(整个对象的浅拷贝直接赋值即可)

思路

  1. 先对参数进行判断,如果不是对象或者是null、函数、正则、日期、ES6新对象(SetMap)中的一种就直接返回原参数。

    通过对象上的constructor.name能够获取该对象的构造函数名,能够以此来判断该对象具体是什么。

    console.log([].constructor.name); // Arrayconsole.log(new Date().constructor.name); // Dateconsole.log({}.constructor.name); // Objectconsole.log(new Set().constructor.name); // Setconsole.log(new Map().constructor.name); // Mapconsole.log(new RegExp().constructor.name); // RegExpfunction fn() {}console.log(fn.constructor.name); // Function
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  2. 再根据参数是数组还是对象来并创建相应数据类型的新变量。
  3. 通过for in循环向新变量中克隆原对象的参数值。

代码

const _shallowClone = target => {    // 补全代码    if (typeof target !== 'object' || target === null || /^(RegExp|Date|Set|Map|Function)$/.test(target.constructor.name)) {        return target    }    const cloneTarget = Array.isArray(target) ? [] : {};    for (const key in target) {    	// hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性    	// 因为for in循环会遍历到原型链上的属性,所以我们需要排除掉这些原型链上的属性        if (Object.hasOwnProperty.call(target, key)) {           cloneTarget[key] = target[key]        }    }    return cloneTarget}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

2、简易

要求

补全JavaScript代码,要求实现对象参数的深拷贝并返回拷贝之后的新对象。

注意:

  1. 参数对象和参数对象的每个数据项的数据类型范围 仅在数组、普通对象({})、基本数据类型中
  2. 无需考虑循环引用问题。

思路

这个思路与上一题《对象参数浅拷贝》类似,不同的是这题明确提出数据的类型仅在数组、普通对象({})、基本数据类型中,所以我们在开始时只需判断参数是否是对象或null即可。

因为是深拷贝,需要考虑到函数参数的属性值是引用类型的情况,所以在向新变量中克隆参数值时对参数值进行该函数即可。

代码

const _sampleDeepClone = target => {    // 补全代码    if (typeof target !== 'object' || target === null) {        return target    }        const cloneTarget = Array.isArray(target) ? [] : {};    for (const key in target) {    	// hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性    	// 因为for in循环会遍历到原型链上的属性,所以我们需要排除掉这些原型链上的属性        if (Object.hasOwnProperty.call(target, key)) {	    	// 递归	        cloneTarget[key] = _sampleDeepClone(target[key])        }    }    return cloneTarget}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

3、完整深拷贝

要求

补全JavaScript代码,要求实现对象参数的深拷贝并返回拷贝之后的新对象。

注意:

  1. 需要考虑函数、正则、日期、ES6新对象
  2. 需要考虑循环引用问题。

思路

根据题目要求,实现对象参数的深拷贝并返回拷贝之后的新对象,因为需要考虑参数对象和参数对象的每个数据项的数据类型可能包括函数、正则、日期、ES6新对象且必须考虑循环引用问题,所以需要引入ES6新对象Map(用来存放循环引用的值)并且详细的判断数据类型,核心步骤有:

  1. 首先对函数参数进行判断,如果参数类型是函数,则创建一个新的函数并返回。

  2. 如果参数不是函数也不是“object”或者参数是“null”,则直接返回该参数。

  3. 如果参数是Error对象,不做处理直接返回即可。(这世界上应该没有对Error对象深拷贝的需求吧!)

  4. 获取到对象参数的构造函数名,判断是否为正则、日期、ES6新对象其中之一,如果是则直接返回通过该参数对象对应的构造函数生成的新实例对象

  5. Map对象中获取当前参数对象,如果能获取到,则说明这里为循环引用,直接返回Map对象中该参数对象的值。

  6. 如函数到此还没结束,就根据该参数的数据类型是否为数组创建新变量。

  7. 保存该参数对象到Map中,值为上一步创建的新变量。

  8. 遍历该对象参数,将每一项递归调用该函数本身的返回值赋给新变量。

代码

function deepClone(obj, map = new Map()) {    // 1. obj是函数时 返回一个新函数    if (typeof obj === "function") {    	// new Function接收的参数是字符串        return new Function('return ' + obj.toString())()    };    // 2. obj是原始类型时 返回原值    if (typeof obj !== "object" || obj === null) {        return obj    };    // 3. obj是Error对象时,不做处理 (这还要做处理那就真丧尽天良)    if (obj.constructor.name === 'Error') {        return obj    };    // 4. obj是除了函数和Error对象以外的引用类型    // 以下涉及到原型链:obj对象实例 --> 构造函数的原型对象 <--> 构造函数 --> obj实例(obj对象实例是构造函数new出的)    // 对象实例(obj)本身不存在constructor属性,该属性存在于创建obj实例的构造函数的原型对象上(即obj.__proto__上),    // 这个属性指向创建obj实例的构造函数,所以obj.constructor.name指定就是创建obj实例的构造函数的名字    if (/^(Date|RegExp|Map|Set)$/i.test(obj.constructor.name)) {        // 获取到对象参数的构造函数名,判断是否为函数、正则、日期、ES6新对象其中之一,        // 如果是则直接返回通过该参数对象对应的构造函数生成的新实例对象。        return new obj.constructor(obj);    };    // map用来存放存放循环引用的值,如map中存在以该对象为key的值,说明这个obj是循环引用的,直接返回它在map中对应的值    if (map.get(obj)) {        return map.get(obj);    };    // 创建一个新对象    let newObj = Array.isArray(obj) ? [] : {};    // 向map中添加,key为obj,值为newObj(obj的副本),这里存的newObj是地址,所以下面改变newObj时map中obj对应的值也能随之改变    map.set(obj, newObj);    // 遍历    for (const key in obj) {        // for in会遍历到原型链上的属性,但我们不需要原型链上的属性,可以使用hasOwnProperty排除        if (Object.hasOwnProperty.call(obj, key)) {            // hasOwnProperty() 方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(也就是,是否有指定的键)。            newObj[key] = deepClone(obj[key], map);        };    };    return newObj;};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

注意:第一次调用deepClone 时不加第二个参数。

网站建设定制开发 软件系统开发定制 定制软件开发 软件开发定制 定制app开发 app开发定制 app开发定制公司 电商商城定制开发 定制小程序开发 定制开发小程序 客户管理系统开发定制 定制网站 定制开发 crm开发定制 开发公司 小程序开发定制 定制软件 收款定制开发 企业网站定制开发 定制化开发 android系统定制开发 定制小程序开发费用 定制设计 专注app软件定制开发 软件开发定制定制 知名网站建设定制 软件定制开发供应商 应用系统定制开发 软件系统定制开发 企业管理系统定制开发 系统定制开发