• JavaScript中的Null+浮点数你了解多少?


    我们在开发过程中深浅拷贝可谓是经常需要使用,那么实现深浅拷贝的方法具体有哪些呢?他们各自的优势与劣势又是怎么样的呢?

    浅拷贝

    Object.assign

    作为ES6新增的方法,它的作用就是合并对象,有点类似于数组的concat方法。但是Object.assign是有自己的特点的:

    • 它改变源对象,并返回新对象
    • 它只可以将目标对象的可枚举属性进行复制合并
    • 它不会合并继承属性
    • 可以复制Symbol类型的属性

    所以我们看以下这段代码:

    let obj1 = {name:'zs',love:['play','girl'],[Symbol(1)]:'Symbol'
    }
    Object.defineProperty(obj1,'noMerge',{value:'nonono',enumerable:false
    })
    let obj2 = Object.assign({},obj1)
    console.log(obj1);
    console.log(obj2); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    我们来看结果:

    同时如果我们修改了obj2中的love,给它新增一个’eat’,那么obj1和obj2将变成:

    {name:'zs',love:['play','girl','eat'],...
    } 
    
    • 1
    • 2

    扩展运算符

    展运算符(…)是ES6的语法,用于取出参数对象的所有可遍历属性,然后拷贝到当前对象之中。

    • 包括Symbol类型
    • 不包括继承来的属性
    • 包括可枚举属性
    let obj1 = {name:'zs',love:['play','girl'],[Symbol(1)]:'Symbol'
    }
    Object.defineProperty(obj1,'noMerge',{value:'nonono',enumerable:false
    })
    let obj2 = {...obj1}
    console.log(obj2) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    现在来看结果:

    如果我们修改了obj2的love属性:

    obj2.love.push('30')
    console.log(obj1); 
    
    • 1
    • 2

    数组的concat

    数组的concat和对象的assign有点类似:

    let arr = [1,2,{name:'zs'}]
    let arr2 = [].concat(arr);
    arr2[2].name='ls';
    console.log(arr); 
    
    • 1
    • 2
    • 3
    • 4

    数组的slice

    数组的slice也是浅拷贝的:

    let arr = [{name:'zs'},{name:'ls'},{name:'ww'}]
    arr2 = arr.slice(1);
    arr2[0].name='erer';
    console.log(arr); 
    
    • 1
    • 2
    • 3
    • 4

    深拷贝

    JSON序列化

    作为最简单的深拷贝方法,但是它有一些需要注意的地方:

    • 如果拷贝对象的值有函数、Symbol、undefined这几种类型,经过JSON.stringify序列化后的字符串中这个键值对会消失
    • 拷贝Date引用类型为变为字符串
    • 无法拷贝不可枚举的属性
    • 无法拷贝对象的原型链
    • 拷贝正则引用类型会变为空对象
    • 对象中含有NAN、infinity以及-infinity,JSON序列化的结果会变成null
    • 无法拷贝对象的循环引用

    比如:

    function Obj() {this.func = function(){console.log(1)};this.obj={a:1};this.arr=[1,2];this.und=undefined;this.nul=null;this.Nan=NaN;this.sym=Symbol(1);this.date = new Date();this.infi = Infinity;this.reg = /123/;
    }
    let obj1 = new Obj();
    Object.defineProperty(obj1,'ennu',{enumerable:false,value:'ennu'
    })
    let obj2 = JSON.parse(JSON.stringify(obj1));
    console.log(obj1);
    console.log(obj2); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    递归实现(基本版)

    function deepCopy(origin){if((typeof origin === 'object' || typeof origin === 'function' ) && origin!==null) {let target = Array.isArray(origin)?[]:{};for(let [key,value] of Object.entries(origin)){if(value instanceof Object) {target[key] = deepCopy(value)} else {target[key] = value;}}return target;}
    } 
    
    • 1
    • 2

    虽然这种能实现深拷贝,且能应付日常开发中的大部分需求,但是它仍有一些地方需要注意:

    • Symbol类型的不能拷贝
    • 不能解决循环引用的问题
    • 不可枚举的属性不能拷贝(这个看需求,一般都不需要拷贝继承上面的属性)
    • 不能拷贝正则、日期等对象
    let a = {name:'11',arr:[1,2,3,4],[Symbol(1)]:1,date:new Date(),reg:/123/
    }
    let b = deepCopy(a) 
    
    • 1
    • 2
    • 3

    改进版的递归实现深拷贝

    function isComplexDataType(origin) {return ((typeof origin === 'object' || typeof origin === 'function') && origin!==null)
    }
    
    function deepCopy(origin,hash=new WeakMap()){if(origin.constructor === Date) {return new Date(origin)}if(origin.constructor === RegExp) {return new RegExp(origin)}if(hash.has(origin)) {return hash.get(origin)}let allDesc = Object.getOwnPropertyDescriptors(origin);//遍历传入参数所有键的特性let cloneObj = Object.create(Object.getPrototypeOf(origin),allDesc);//继承原型链hash.set(origin,cloneObj);for(key of Reflect.ownKeys(origin)) {cloneObj[key]=(isComplexDataType(origin[key])&&typeof origin[key]!=='function') ?deepCopy(origin[key],hash):origin[key]}return cloneObj;
    }
    
    let a = {name:'11',arr:[1,2,3,4],[Symbol(1)]:1,date:new Date(),reg:/123/
    }
    let b = deepCopy(a) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    最后

    整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。



    有需要的小伙伴,可以点击下方卡片领取,无偿分享

  • 相关阅读:
    过滤对象数组中有重复值的项
    Java版分布式微服务云开发架构 Spring Cloud+Spring Boot+Mybatis 电子招标采购系统功能清单
    【05】基础知识:React组件实例三大核心属性 - props
    vue中 el-tab-plane 如何显示使用el-badge显示小红点
    浅入浅出分布式事务
    基于Android平台的手机安全卫士的设计与实现
    数据插值——对不同量级的数据进行归一化
    材料数据库设计问题
    【C++笔试强训】第二十四天
    微信小程序会议OA系统其他页面
  • 原文地址:https://blog.csdn.net/web2022050903/article/details/127444748