首页 >> js开发 >> jsJS面试题中深拷贝的实现讲解js大全
jsJS面试题中深拷贝的实现讲解js大全
发布时间: 2021年1月13日 | 浏览:
| 分类:js开发
在面试中你是否遇到过如下场景:Q:小朋友,你是否了解如何拷贝一个对象?Q:小朋友,你是否了解如何拷贝一个对象?R:此时,机智的你可能会想到
Object.assign({}, obj);
Object.assign({}, obj);Q:那如何深拷贝一个对象呢?Q:那如何深拷贝一个对象呢?R:机智的你
JSON.parse(JSON.stringify(obj));
JSON.parse(JSON.stringify(obj));Q:使用stringify这种方式有何弊端?
性能问题,stringify再解析其实需要耗费较多时间,特别是数据量大的时候。
一些类型无法拷贝,例如函数(不输出),正则(输出空对象),时间对象(输出时间字符串),Undefiend(不输出)
遇到循环引用的对象会出错
同层(非同层)同引用的问题,理论下两个key对应的val如果指向同一个对象,拷贝也应该指向一个相同新地址才对
性能问题,stringify再解析其实需要耗费较多时间,特别是数据量大的时候。一些类型无法拷贝,例如函数(不输出),正则(输出空对象),时间对象(输出时间字符串),Undefiend(不输出)遇到循环引用的对象会出错同层(非同层)同引用的问题,理论下两个key对应的val如果指向同一个对象,拷贝也应该指向一个相同新地址才对Q:那你能自己实现个深拷贝函数?Q:那你能自己实现个深拷贝函数?R:如下:
const deepClone = (obj) => {
// 非引用类型及函数将直接返回
if (!obj || typeof obj !== 'object') return obj;
// 特殊的引用类型处理
switch(Object.prototype.toString.call(obj).slice(8, -1)) {
case 'Date':
return new Date(obj);
break;
case 'RegExp':
return new RegExp(obj);
break;
case 'String':
return new String(obj);
break;
case 'Number':
return new Number(obj);
break;
case 'Boolean':
return new Boolean(obj);
break;
}
const result = obj instanceof Array ? [] : {};
for (let propName in obj) {
if (obj.hasOwnProperty(propName)) {
result[propName] = deepClone(obj[propName]);
}
}
return result;
}
const deepClone = (obj) => {
// 非引用类型及函数将直接返回
if (!obj || typeof obj !== 'object') return obj;
// 特殊的引用类型处理
switch(Object.prototype.toString.call(obj).slice(8, -1)) {
case 'Date':
return new Date(obj);
break;
case 'RegExp':
return new RegExp(obj);
break;
case 'String':
return new String(obj);
break;
case 'Number':
return new Number(obj);
break;
case 'Boolean':
return new Boolean(obj);
break;
}
const result = obj instanceof Array ? [] : {};
for (let propName in obj) {
if (obj.hasOwnProperty(propName)) {
result[propName] = deepClone(obj[propName]);
}
}
return result;
}优点:实现了大多数数据类型的拷贝,所有非引用类型及引用类型的String Number Boolean Function Array Date RegExp缺点:未考虑一些特殊的引用类型如Error Math Symbol Map Set JSON,函数属于引用拷贝,未解决循环引用的问题Q:如何解决循环引用?Q:如何解决循环引用?R:将父层级的数据缓存对比(可以顺带解决同层(非同层)同引用的问题)
const deepClone = (obj) => {
// 非引用类型及函数将直接返回
if (!obj || typeof obj !== 'object') return obj;
// 特殊的引用类型处理
switch (Object.prototype.toString.call(obj).slice(8, -1)) {
case 'Date':
return new Date(obj);
break;
case 'RegExp':
return new RegExp(obj);
break;
case 'String':
return new String(obj);
break;
case 'Number':
return new Number(obj);
break;
case 'Boolean':
return new Boolean(obj);
break;
}
const map = deepClone.map = deepClone.map || new Map();
// 使用map结构可以不必循环缓存,提高效率
if (map.get(obj)) {
return map.get(obj);
}
const result = obj instanceof Array ? [] : {};
// 如果仔细观察可以发现解决了同层同引用的问题
map.set(obj, result);
for (let propName in obj) {
if (obj.hasOwnProperty(propName)) {
result[propName] = deepClone(obj[propName]);
}
}
return result;
}
const deepClone = (obj) => {
// 非引用类型及函数将直接返回
if (!obj || typeof obj !== 'object') return obj;
// 特殊的引用类型处理
switch (Object.prototype.toString.call(obj).slice(8, -1)) {
case 'Date':
return new Date(obj);
break;
case 'RegExp':
return new RegExp(obj);
break;
case 'String':
return new String(obj);
break;
case 'Number':
return new Number(obj);
break;
case 'Boolean':
return new Boolean(obj);
break;
}
const map = deepClone.map = deepClone.map || new Map();
// 使用map结构可以不必循环缓存,提高效率
if (map.get(obj)) {
return map.get(obj);
}
const result = obj instanceof Array ? [] : {};
// 如果仔细观察可以发现解决了同层同引用的问题
map.set(obj, result);
for (let propName in obj) {
if (obj.hasOwnProperty(propName)) {
result[propName] = deepClone(obj[propName]);
}
}
return result;
}Q:为什么函数还是指向原来的函数,而不创建新函数? Q:为什么函数还是指向原来的函数,而不创建新函数? R:理论下函数也可以通过new Function(code)来创建新的函数,但是如果遇到闭包函数,我们无法得到原函数的外层定义的变量及其原有作用域链,这些在JS词法解析时完成的步骤我们无法得知,所有只能引用原函数比较好。Sum: 上面实现的缺点主要是没有完全覆盖特殊引用类型,但其实我们平时应该不会遇到那些类型,所以可以凑合使用。如果还有其它的问题没有考虑到或者有出错的,希望大家可以帮忙指出。以上就是JS面试题中深拷贝的实现讲解的详细内容,关于JS深拷贝的实现的资料请关注其它相关文章!
Object.assign({}, obj);
Object.assign({}, obj);Q:那如何深拷贝一个对象呢?Q:那如何深拷贝一个对象呢?R:机智的你
JSON.parse(JSON.stringify(obj));
JSON.parse(JSON.stringify(obj));Q:使用stringify这种方式有何弊端?
性能问题,stringify再解析其实需要耗费较多时间,特别是数据量大的时候。
一些类型无法拷贝,例如函数(不输出),正则(输出空对象),时间对象(输出时间字符串),Undefiend(不输出)
遇到循环引用的对象会出错
同层(非同层)同引用的问题,理论下两个key对应的val如果指向同一个对象,拷贝也应该指向一个相同新地址才对
性能问题,stringify再解析其实需要耗费较多时间,特别是数据量大的时候。一些类型无法拷贝,例如函数(不输出),正则(输出空对象),时间对象(输出时间字符串),Undefiend(不输出)遇到循环引用的对象会出错同层(非同层)同引用的问题,理论下两个key对应的val如果指向同一个对象,拷贝也应该指向一个相同新地址才对Q:那你能自己实现个深拷贝函数?Q:那你能自己实现个深拷贝函数?R:如下:
const deepClone = (obj) => {
// 非引用类型及函数将直接返回
if (!obj || typeof obj !== 'object') return obj;
// 特殊的引用类型处理
switch(Object.prototype.toString.call(obj).slice(8, -1)) {
case 'Date':
return new Date(obj);
break;
case 'RegExp':
return new RegExp(obj);
break;
case 'String':
return new String(obj);
break;
case 'Number':
return new Number(obj);
break;
case 'Boolean':
return new Boolean(obj);
break;
}
const result = obj instanceof Array ? [] : {};
for (let propName in obj) {
if (obj.hasOwnProperty(propName)) {
result[propName] = deepClone(obj[propName]);
}
}
return result;
}
const deepClone = (obj) => {
// 非引用类型及函数将直接返回
if (!obj || typeof obj !== 'object') return obj;
// 特殊的引用类型处理
switch(Object.prototype.toString.call(obj).slice(8, -1)) {
case 'Date':
return new Date(obj);
break;
case 'RegExp':
return new RegExp(obj);
break;
case 'String':
return new String(obj);
break;
case 'Number':
return new Number(obj);
break;
case 'Boolean':
return new Boolean(obj);
break;
}
const result = obj instanceof Array ? [] : {};
for (let propName in obj) {
if (obj.hasOwnProperty(propName)) {
result[propName] = deepClone(obj[propName]);
}
}
return result;
}优点:实现了大多数数据类型的拷贝,所有非引用类型及引用类型的String Number Boolean Function Array Date RegExp缺点:未考虑一些特殊的引用类型如Error Math Symbol Map Set JSON,函数属于引用拷贝,未解决循环引用的问题Q:如何解决循环引用?Q:如何解决循环引用?R:将父层级的数据缓存对比(可以顺带解决同层(非同层)同引用的问题)
const deepClone = (obj) => {
// 非引用类型及函数将直接返回
if (!obj || typeof obj !== 'object') return obj;
// 特殊的引用类型处理
switch (Object.prototype.toString.call(obj).slice(8, -1)) {
case 'Date':
return new Date(obj);
break;
case 'RegExp':
return new RegExp(obj);
break;
case 'String':
return new String(obj);
break;
case 'Number':
return new Number(obj);
break;
case 'Boolean':
return new Boolean(obj);
break;
}
const map = deepClone.map = deepClone.map || new Map();
// 使用map结构可以不必循环缓存,提高效率
if (map.get(obj)) {
return map.get(obj);
}
const result = obj instanceof Array ? [] : {};
// 如果仔细观察可以发现解决了同层同引用的问题
map.set(obj, result);
for (let propName in obj) {
if (obj.hasOwnProperty(propName)) {
result[propName] = deepClone(obj[propName]);
}
}
return result;
}
const deepClone = (obj) => {
// 非引用类型及函数将直接返回
if (!obj || typeof obj !== 'object') return obj;
// 特殊的引用类型处理
switch (Object.prototype.toString.call(obj).slice(8, -1)) {
case 'Date':
return new Date(obj);
break;
case 'RegExp':
return new RegExp(obj);
break;
case 'String':
return new String(obj);
break;
case 'Number':
return new Number(obj);
break;
case 'Boolean':
return new Boolean(obj);
break;
}
const map = deepClone.map = deepClone.map || new Map();
// 使用map结构可以不必循环缓存,提高效率
if (map.get(obj)) {
return map.get(obj);
}
const result = obj instanceof Array ? [] : {};
// 如果仔细观察可以发现解决了同层同引用的问题
map.set(obj, result);
for (let propName in obj) {
if (obj.hasOwnProperty(propName)) {
result[propName] = deepClone(obj[propName]);
}
}
return result;
}Q:为什么函数还是指向原来的函数,而不创建新函数? Q:为什么函数还是指向原来的函数,而不创建新函数? R:理论下函数也可以通过new Function(code)来创建新的函数,但是如果遇到闭包函数,我们无法得到原函数的外层定义的变量及其原有作用域链,这些在JS词法解析时完成的步骤我们无法得知,所有只能引用原函数比较好。Sum: 上面实现的缺点主要是没有完全覆盖特殊引用类型,但其实我们平时应该不会遇到那些类型,所以可以凑合使用。如果还有其它的问题没有考虑到或者有出错的,希望大家可以帮忙指出。以上就是JS面试题中深拷贝的实现讲解的详细内容,关于JS深拷贝的实现的资料请关注其它相关文章!
相关文章:
- jsAngular利用HTTP POST下载流文件的步骤记录js大全
- jsVUE项目axios请求头更改Content-Type操作js大全
- jsVue-CLI 3 scp2自动部署项目至服务器的方法js大全
- js使用React-Router实现前端路由鉴权的示例代码js大全
- JavaScriptthree.js欧拉角和四元数的使用方法
- js关于angular浏览器兼容性问题的解决方案js大全
- jsElement Input输入框的使用方法js大全
- jsvue项目使用$router.go(-1)返回时刷新原来的界面操作js大全
- jsVue组件跨层级获取组件操作js大全
- js解决vuex数据页面刷新后初始化操作js大全