一、 基本数据类型的拷贝(复制copy)深拷贝和浅拷贝
深拷贝和浅拷贝是针对复杂数据类型来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝
基本数据类型 值传递
a = 1.1;b = a;b = 2; console.log(a,b) Number
a = 'hello';b = a;b = 3; console.log(a,b) String
a = false;b = a;b = 'sss'; console.log(a,b) Boolean
a = undefined;b = a;b = false; console.log(a,b) Undefined
a = null;b = a;b = undefined; console.log(a,b) Null
深拷贝
深拷贝复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。 深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象。
浅拷贝
浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。
可以看出浅拷贝只最第一层属性进行了拷贝,当第一层的属性值是基本数据类型时,新的对象和原对象互不影响,但是如果第一层的属性值是复杂数据类型,那么新对象和原对象的属性值其指向的是同一块内存地址。
二、复杂数据类型(object)的拷贝 地址传递
常用的复杂数据类型包括:{ }、[ ]、function(){} 、Date(时间) 、RegExp 、null(这个比较特殊)等
1、我们依然用一的简单赋值(=)来进行一遍操作(赋值)
经过实践我们会发现:
1、当类型为{}、[]的时候,改变b的值,a也会跟着一起变化。
2、当类型为Date、function、RegExp的时候,a保持不变。
总结:我们发现{}或者[]时,简单的赋值操作并不能实现它们的拷贝,只是改了b的指向,使a和b都指向同一个引用,随意改变一个,都会影响另外一个的值。
// {}
// a = {name: 'abc'};b = a;b.name = 'sss';
// console.log(a,b)
// // []
// a = ['a','b','c'];b = a;b[1] = 'd';
// console.log(a,b)
// // function
// a = function(){ alert('aaa'); };b = a;b = function(){ alert('bbb'); };
// console.log(a.toString(),b.toString())
// // Date
// a = new Date('2018-10-11 00:00:00');b = a;b = new Date('1970-01-01 00:00:00');
// console.log(a,b)
// // RegExp
// a = new RegExp('abc');b = a;b = new RegExp('aaa');
// console.log(a,b)
// 2、Object.assign 和 for in进行{}和[]的拷贝(浅拷贝--只能拷贝一层)
// Object.assign
// a = {name: 'aaa'};b = Object.assign({}, a);
// b.name = 'bbb';
// console.log(a,b)
// a = [1,2,3];b = Object.assign([], a);b[1] = 4;
// console.log(a,b)
// // for in
// var copy = function(a) {
// var res = a.constructor();
// console.log(res)
// for(var key in a) {
// if(a.hasOwnProperty(key)) {
// res[key] = a[key];
// }
// }
// return res;
// }
// a = {name: 'aaa'};b = copy(a);b.name = 'bbb';
// console.log(a,b)
// a = [1,2,3];b = copy(a);b[1] = 4;
// console.log(a,b)
// a = {name:'aaa',people:{name: 'abc'}};b = Object.assign({}, a);b.people.name = 'def';
// console.log(a,b)
// // for in
// var copy = function(a) {
// var res = a.constructor();
// for(var key in a) {
// if(a.hasOwnProperty(key)) {
// res[key] = a[key];
// }
// }
// return res;
// }
// a = {name:'aaa',people:{name: 'abc'}};b = copy(a);b.people.name = 'def';
// console.log(a,b)
// a = [1,2, {name: 'aaa'}];b = Object.assign([], a);b[2].name = 'bbb';
// console.log(a,b)
// a = [1,2, {name: 'aaa'}];b = copy(a);b[2].name = 'bbb';
// console.log(a,b)
深拷贝和浅拷贝是针对复杂数据类型来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝。
深拷贝
深拷贝复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。 深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象。
浅拷贝
浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。 可以使用 for in、 Object.assign、 扩展运算符 ... 、Array.prototype.slice()、Array.prototype.concat() 等
// var array = [
// { number: 1 },
// { number: 2 },
// { number: 3 }
// ];
// var copyArray = array.slice();
// copyArray[0].number = 100;
// console.log(array);
// console.log(copyArray);
// let obj = {
// name: 'Yvette',
// age: 18,
// hobbies: ['reading', 'photography']
// }
// let obj2 = Object.assign({}, obj);
// let obj3 = {...obj};
// obj.name = 'Jack';
// obj.hobbies.push('coding');
// console.log(obj);
// console.log(obj2);
// console.log(obj3);
可以看出浅拷贝只最第一层属性进行了拷贝,当第一层的属性值是基本数据类型时,新的对象和原对象互不影响,但是如果第一层的属性值是复杂数据类型,那么新对象和原对象的属性值其指向的是同一块内存地址。
1.深拷贝最简单的实现是: JSON.parse(JSON.stringify(obj))
JSON.parse(JSON.stringify(obj)) 是最简单的实现方式,但是有一些缺陷:
//对象的属性值是函数时,无法拷贝。
// 原型链上的属性无法拷贝
// 不能正确的处理 Date 类型的数据
// 不能处理 RegExp
// 会忽略 symbol
// 会忽略 undefined
递归函数
如果一个函数在内部调用自身,这个函数就叫做递归函数
递归函数:
实现一个 deepClone 函数 (深拷贝,完美)
// 如果是基本数据类型,直接返回
// 如果是 RegExp 或者 Date 类型,返回对应类型
// 如果是复杂数据类型,递归。
// 考虑循环引用的问题
// var show={
// btn:"btn",
// init:function(){
// var that=this;
// alert(this);
// this.btn.click(function(){
// that.change();
// alert(this);
// })
// },
// change:function(){
// this.btn.css({'background':'green'});
// person={
// name:"king",
// show:function(){
// console.log(this.name)
// }
// }
// }
// }
// function deepClone(obj, hash = new WeakMap()) { //递归拷贝
// if (obj instanceof RegExp) return new RegExp(obj);
// if (obj instanceof Date) return new Date(obj);
// if (obj === null || typeof obj !== 'object') {
// //如果不是复杂数据类型,直接返回
// return obj;
// }
// if (hash.has(obj)) {
// return hash.get(obj);
// }
/**
* 如果obj是数组,那么 obj.constructor 是 [Function: Array]
* 如果obj是对象,那么 obj.constructor 是 [Function: Object]
*/
// let t = new obj.constructor();
// hash.set(obj, t);
// for (let key in obj) {
// //递归
// if (obj.hasOwnProperty(key)) {//是否是自身的属性
// t[key] = deepClone(obj[key], hash);
// }
// }
// return t;
// }
// var show2 = cloneObject(show)
// console.log(show2)
//递归函数
// function cloneObject (obj) {
// var newObj = {} //如果不是引用类型,直接返回
// if (typeof (obj) !== 'object') {
// return obj
// }
// //如果是引用类型,遍历属性
// else{
// for (var attr in obj) {
// //如果某个属性还是引用类型,递归调用
// newObj[attr] = cloneObject(obj[attr])
// }
// }
// return newObj
// }