目录:
1、深拷贝与浅拷贝
2、浅拷贝实现
3、深拷贝实现
传值与传址
相关笔记:https://www.cnblogs.com/xiaoxuStudy/p/12185177.html
原始数据类型的拷贝是传值,应用数据类型的拷贝是传址。
深拷贝与浅拷贝
因为原始类型的拷贝是传值,所以对于原始数据类型并没有深浅拷贝的区别。深浅拷贝都是对于引用数据类型而言的。
深拷贝与浅拷贝的使用场景:1、都是复杂对象,即对象的属性还是对象
如果要赋值对象的所有属性都不是引用类型的时候,可以使用浅拷贝,遍历并复制。
浅拷贝只复制一层对象,当对象的属性是引用类型时,实质复制的是其引用,当引用值指向发生改变时,也会跟着改变。
使用 for-in
下面实现一个浅拷贝:
//实现浅拷贝
let shallowCopy = obj => {
let rst = {};
//遍历对象
for(let key in obj){
//只复制本身拥有的(非继承过来的)枚举属性
if(obj.hasOwnProperty(key)){
rst[key] = obj[key];
}
}
return rst;
}
let star = {
name:‘虞书欣‘,
age : 20,
//又是一个对象
friend : {
name : ‘孔雪儿‘
}
}
let otherStar = shallowCopy(star);
otherStar.name = ‘刘雨昕‘;
otherStar.age = ‘22‘;
otherStar.friend.name = ‘金子涵‘;
console.log( star );

输出:
{ name: ‘虞书欣‘, age: 20, friend: { name: ‘孔雪儿‘ } }
上面创建一个 shallowCopy 函数,传入一个对象作为参数,该函数遍历该对象将该对象的属性复制到一个空对象 rst 中,最后返回 rst 对象。创建一个star 对象, 注意这里 star 对象有一个属性 friend, friend 是引用类型,将 star 作为参数传给 shallowCopy 函数,shallowCopy 函数返回一个 rst 对象,otherStar 指向 rst 对象。这里看一下修改 otherStar 会不会影响到 star 。修改 otherStar 的 name 属性、age 属性跟 friend 属性的对象的 name 属性。输出 star 发现 friend 属性改变了,name属性跟age属性都没有变。
所以,要记得:浅拷贝只复制一层对象,当对象的属性是引用类型时,实质复制的是其引用,当引用值指向发生改变时,也会跟着改变。
用 Object.assign() 拷贝也是一样。
使用 Object.assign( )
let xiaoxu = {
name:‘小许‘,
info:{
gender:‘女‘,
hobby:‘sleep‘
}
}
let a = Object.assign( {}, xiaoxu );
a.name = "nana";
console.log( xiaoxu.name ); //没变 //输出:小许
a.info.gender = ‘男‘;
console.log( xiaoxu.info.gender ); //变了 //输出:男

使用对象的扩展运算符
扩展运算符的 value 是原始数据类型的时候,是深拷贝。当 value 是引用类型的时候,是浅拷贝。
let xiaoxu = {
name:‘小许‘,
info:{
gender:‘女‘,
hobby:‘sleep‘
}
}
let a = { ...xiaoxu };
a.name = "nana";
console.log( xiaoxu.name ); //没变 //输出:小许
a.info.gender = ‘男‘;
console.log( xiaoxu.info.gender ); //变了 //输出:男

深复制递归复制了所有层级。
使用 JSON.stringify()
注意:如果需要拷贝的是纯的JSON数据,不需要循环引用,可以使用 JSON.stringify 实现。
let obj = {
name : ‘小明‘,
songs : [‘想见你想见你想见你‘, ‘暮阳少年‘]
}
let obj1 = JSON.parse(JSON.stringify(obj));
obj1.name = ‘小华‘;
obj1.songs[0] = ‘飘‘;
let girl = [{
name : ‘小许‘,
colors : [‘black‘,‘pink‘],
fn : function(){},
age : undefined
}]
let boy = JSON.parse(JSON.stringify(girl));
console.log(boy); //输出:[ { name: ‘小许‘, colors: [ ‘black‘, ‘pink‘ ] } ]

使用递归
let deepClone = obj => {
let newObj = Array.isArray(obj) ? [] : {};
if( obj && typeof obj === ‘object‘ ){
for( let key in obj ){
if( obj.hasOwnProperty(key) ){
//如果对象的属性是引用类型
if( obj[key] && typeof obj[key] ){
newObj[key] = deepClone(obj[key]);
}else{
//如果对象的属性不是引用类型,直接拷贝
newObj[key] = obj[key];
}
}
}
}
return newObj;
}
let xiaoxu = {
name :‘xiaoxu‘,
idols : [‘虞书欣‘,‘刘雨昕‘],
fn : function(){},
age : undefined
}
let girl = deepClone(xiaoxu);
girl.name = ‘nana‘;
girl.idols = [‘林宥嘉‘,‘JonyJ‘];
girl.fn = ‘亲一口=3=‘;
girl.age = 20;
console.log(xiaoxu);
console.log(girl);

输出:

混合模式 Mixin
不通过继承去扩展方法
let mixin = {
say(){
console.log(`${this.name}在说话`);
},
sing(){
console.log(`${this.name}在唱歌`);
},
run(){
console.log(`${this.name}在跑步`);
}
}
class Student{
constructor(name){
this.name = name;
}
}
Object.assign( Student.prototype, mixin );
let student = new Student(‘小许‘);
student.sing(); //输出:小许在唱歌

为什么要把 mixin 复制到 prototype 上?因为这样子维护性好且减少内存占用。
Vue 的混入(Mixin)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="vue.js"></script>
</head>
<body>
<div id="app">
<h1>{{name}}..{{age}}</h1>
</div>
<script>
Vue.mixin({
data(){
return{
name:‘小许‘
}
},
methods:{
say(){
console.log(‘hello‘);
}
}
})
new Vue({
el:‘#app‘,
data(){
return{
age:22
}
},
mounted(){
this.say();
}
})
</script>
</body>
</html>

使用 pick
先使用命令 yarn add -D underscore 安装 underscore 依赖
const _ = require(`underscore`); //引进underscore
let obj = {
name : ‘小许‘,
age : 22
}
//返回一个 obj 的副本
let age = _.pick(obj, ‘age‘);
console.log( age ); //输出:{ age: 22 }
console.log( obj ); //输出:{ name: ‘小许‘, age: 22 }

原文:https://www.cnblogs.com/xiaoxuStudy/p/12724196.html