js基本类型
基本数据类型:Null、 undefined、 number、 string、 boolean、symbol
引用类型:Object对象类型(object、 array、 function、 Data等)
区别点:
基本数据类型,是按照值进行访问的,可以操作保存在变量中的实际的值。
引用类型,js是不允许直接访问值的,不能直接操作对象的内存空间。
基本数据类型是存在栈中的
引用类型的值是同时保存在栈内存和堆内存中的对象
深拷贝、浅拷贝抽象讲解
假设B复制了A,当修改A时,看B是否发生变化,
-
如果B
变化,说明就是浅拷贝。 -
如果B
没变,就是深拷贝。
深拷贝、浅拷贝使用场景
浅拷贝:只是简单的指针赋值。
深拷贝:指针赋值,且内容拷贝。深拷贝即拷贝实例,其作用是为了不影响拷贝后的数组对起原数组造成影响。
浅拷贝
定义:
浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。
第一种方法:for...in只循环第一层
function shadowClone(initalObj){
var obj = {}
for(var i in initalObj){
obj[i] = initalObj[i]
}
return obj
}
var obj = {
a:"hello",
b:{
a:"world",
b:20
},
c:["tom","jack","lay"],
d:function(){
console.log("ni hao")
}
};
var cloneObj = shadowClone(obj)
console.log(cloneObj.a) // hello
console.log(cloneObj.b) // {a:"world",b:20}
console.log(cloneObj.c) // ["tom","jack","lay"]
console.log(cloneObj.d) // f(){console.log("ni hao")}
// 更改原对象中的a,b,c,d,看拷贝过来的对象是否变化
cloneObj.a = "changed"
cloneObj.b.a = "changed"
cloneObj.b.b = "30"
cloneObj.c = [1,12,13]
cloneObj.d = function(){ console.log("你好")}
console.log(cloneObj.a) // hello
console.log(cloneObj.b) // {a:"changed",b:30}
console.log(cloneObj.c) // ["tom","jack","lay"]
console.log(cloneObj.d) // f(){console.log("ni hao"
总结:
浅拷贝只是拷贝了一层,除了对象是拷贝的引用类型,其他的都是直接将值传递,有自己的内存空间。
第二种方法:Object.assign方法
ES6中的Object.assign方法,Object.assign(target,...sources)
参数: target:目标对象 sources:任意多个源对象 返回值:目标对象会被返回
var obj1 = {
a: 1,
b: 2,
c: 3
}
var obj2 = Object.assign({}, obj1);
obj2.b = 5;
console.log(obj1.b); // 2
console.log(obj2.b); // 5
缺点:对象中有多种嵌套,则无法使用
var obj1 = {
a: 1,
b: 2,
c: ['a','b','c']
}
var obj2 = Object.assign({}, obj1);
obj2.c[1] = 5;
console.log(obj1.c); // ["a", 5, "c"]
console.log(obj2.c); // ["a", 5, "c"]
Object.assign 会跳过那些值为 [null] null 是一个 JavaScript 字面量,表示空值(null or an "empty" value),即没有对象被呈现(no object value is present)。它是 JavaScript 原始值 之一。") 或 undefined 的源对象。
深拷贝
定义:深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。
对数组做深拷贝
for循环
let arr1 = [1,2,3];
let arr2 = copyArr(arr1);
function copyArr(arr){
let res=[];
for(let i=0,length=arr.length;i<length;i++){
res.push(arr[i]);
}
return res;
}
slice
利用数组自身的方法,slice、concat方法在运行后会返回新的数组
let arr1 = [1,2,3];
let arr2 = arr1.slice(0);
let arr1 = [1,2,3];
let arr2 = arr1.concat();
扩展运算符
let arr1 = [1,2,3];
let [...arr2] = arr1;
对对象的深拷贝
手动复制
把一个对象的属性复制给另一个对象的属性
var obj1 = {a:"test",b:02,c:30}
var obj2 = {a:obj1.a,b:obj1.b,c:obj1.c}
通过JSON对象来实现深拷贝
JSON.stringify把对象转成字符串,在用JSON.parse把字符串转成新的对象
function deepClone(obj){
var obj = JSON.stringify(obj)
objClone = JSON.parse(obj)
return objClone
}
var a = [1,[2,3],4,5]
var b = deepClone(a)
b[1][0] = 7;
console.log(a) // [1,[2,3],4,5]
console.log(b) // [1,[7,3],4,5]
缺点:
会抛弃对象中的constructor,深拷贝后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。
1:无法拷贝对象中的方法属性
2:无法拷贝对象中值为undefined的属性
- jquery提供一个$.extend可以用来做深拷贝
import $ from 'jquery'
var array = [1,2,3,4]
var newArray = $.extend(true,[],array) // true为深拷贝,false为浅拷贝
缺点:1,需要引用jQuery库 2,无法拷贝对象中值为undefined的属性
- 递归拷贝
// 定义一个深拷贝函数 接收目标target参数
function deepClone(target) {
// 定义一个变量
let result;
// 如果当前需要深拷贝的是一个对象的话
if (typeof target === 'object') {
// 如果是一个数组的话
if (Array.isArray(target)) {
result = []; // 将result赋值为一个数组,并且执行遍历
for (let i in target) {
// 递归克隆数组中的每一项
result.push(deepClone(target[i]))
}
// 判断如果当前的值是null的话;直接赋值为null
} else if(target===null) {
result = null;
// 判断如果当前的值是一个RegExp对象的话,直接赋值
} else if(target.constructor===RegExp){
result = target;
}else {
// 否则是普通对象,直接for in循环,递归赋值对象的所有值
result = {};
for (let i in target) {
result[i] = deepClone(target[i]);
}
}
// 如果不是对象的话,就是基本数据类型,那么直接赋值
} else {
result = target;
}
// 返回最终结果
return result;
}
手写深拷贝
function deepCopy(obj){
let result = Array.isArray(obj)?[]:{};
if(obj && typeof obj === 'object'){
for(let key in obj){
if(obj.hasOwnProperty(key)){
if(obj[key]&&typeof obj[key]==='object'){
result[key]=deepCopy(obj[key]);
}else{
result[key]=obj[key];
}
}
}
}
return result;
}
对于拷贝中对象中值为undefined的属性的解决方法(object.keys)
const org = { a: undefined };
const copy = {};
Object.keys(org).forEach(key => {
copy[key] = origin[key];
});
console.log(copy); // copy: { a: undefined }
通用版的深拷贝、浅拷贝
/*
* 写一个通用的拷贝(包括深拷贝和浅拷贝都适用)
* 简单数据类型实现深拷贝,直接复制就可
* 引用数据类型
Array.isArray(obj):方法返回一个布尔值,
obj.hasOwnProperty(key):方法返回一个布尔值,判断对象是否包含特定的自身属性
*/
function copyObj(obj){
var cloneObj;
// 当输入数据为简单数据类型时直接复制
if(obj && typeof obj !== 'object'){
cloneObj = obj
}else if(obj && typeof obj === 'object'){ // 检测输入数据是数组还是对象
// 判断obj是否是数组还是对象
cloneObj = Array.isArray(obj)?[]:{}
for(let key in obj ){
if(obj.hasOwnProperty(key)){ //判断对象是否包含特定的自身属性
if(obj[key] && typeof obj[key] === 'object'){
// 若当前元素类型为对象时,递归调用
cloneObj[key] = copyObj(obj[key])
}
//若当前元素类型为基本数据类型
else {
cloneObj[key] = obj[key]
}
}
}
}
return cloneObj
}