1:数据类型:
① 基本数据类型:Number、string、null、undefined、boolean ② 引用数据类型: Object =>{object、Array、Function}
2:栈(stack)、堆(heap):
① 基本数据类型是直接存储在栈中的数据,栈的存取速度比堆要快,存在栈中的数据大小是确定的 问:为什么基本数据类型存储在栈中? 存储结构不一样,引用数据类型一般占空间大 答:(http://www.javashuo.com/article/p-gkhlbedc-gg.html) 问:基本数据类型一定存在栈中么? 答:(https://www.cnblogs.com/linliquan/p/11273932.html) ② 引用数据类型存储的是该对象在栈中引用,真实的数据存放在堆内存里
3:基本数据类型和引用数据类型最大的区别:传值和传址
let arr = [1, 2, 3, 4, 5]
let arr1 = arr
console.log(arr,'arr')
console.log(arr1,'arr1')
let arr2 = arr[2]
console.log(arr2,'arr2')
arr1[2] = 33
console.log(arr1,'arr1-1')
console.log(arr,'arr-1')
arr2 = 4
console.log(arr2,'arr2-1')
console.log(arr,'arr-2')
4:深浅拷贝:针对引用数据类型
① 浅拷贝:只复制指向某个对象的指针而不复制对象本身,新旧对象还是共享同一块内存。 ② 深拷贝:指源对象与拷贝对象互相独立,其中任何一个对象的改动都不会对另外一个对象造成影响。
5:对象的直接赋值和浅拷贝的区别:
① 直接赋值:将一个对象赋值给一个新的对象的时候,赋的其实是该对象在栈中的地址,而不是堆中的数据。 也就是一个对象的改变就会改变另外一个对象。 ② 浅拷贝:会创建一个对象,再去遍历原始对象,如果原对象的属性值是基础类型,那么就拷贝基础类型, 如果是引用类型,则拷贝的是指针。
let arr =[11,22,33,44,55]
let arr1 = arr
let arr2 = [...arr]
6:浅拷贝的实现方式:
① Object.assign():可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。 注:当object只有一层的时候,是深拷贝
let query = {name:'原数据',content:['前端','学习']}
let query1 = Object.assign({}, query)
console.log(query,'query')
console.log(query1,'query1')
query1.name = '浅拷贝'
query1.content[1] = '浅拷贝学习'
console.log(query,'query-1')
console.log(query1,'query1-1')
② Array.prototype.concat()
let query = [1,3,{userName:'浅拷贝'}]
let query1 = query.concat()
query1[1] = 33
query1[2].userName = 'concat'
console.log(query,'query')
console.log(query1,'query1')
③ Array.prototype.slice()
let query = [1,3,{userName:'浅拷贝'}]
let query1 = query.slice(0)
query1[1] = 33
query1[2].userName = 'concat'
console.log(query,'query')
console.log(query1,'query1')
说明:Array的slice和concat方法不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。 浅拷贝的方式有很多:for…in 等等
var person = {
name: "浅拷贝",
age: 111,
sex: '保密'
};
var person2 = {};
for (var key in person1) {
person2[key] = person1[key];
}
console.log(person2)
7:深拷贝的实现方式:
① JSON.parse(JSON.stringify()): 用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象, 一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。 说明:JSON.parse(JSON.stringify())自身存在小问题:比如:不能处理函数, 因为 JSON.stringify() 方法是将一个JavaScript值(对象或者数组)转换为一个JSON字符串,不能接受函数。 另外还有 将undefined,’ ',empty 都转换为null,
let arr = ['深拷贝',' ','',null,undefined, ,{userName:'深拷贝1'},function(){}]
let arr1 = JSON.parse(JSON.stringify(arr))
console.log(arr1,'arr1')
arr1[6].userName = '拷贝'
console.log(arr,'arr')
console.log(arr1,'arr1-1')
? 如果对象中存在循环引用的情况也无法正确实现深拷贝。
const a = {
b: 1,
}
a.c = a;
JSON.parse(JSON.stringify(a));
? 如果 data 里面有时间对象,则JSON.stringify后再JSON.parse的结果,时间将只是字符串的形式。而不是时间对象。
const a = {
b: new Date(1536627600000),
}
console.log(a)
console.log(JSON.parse(JSON.stringify(a)))
? 如果 data 里有RegExp、Error对象,则序列化的结果将只得到空对象;
const a = {
b: new RegExp(/\d/),
c: new Error('错误')
}
console.log(a)
console.log(JSON.parse(JSON.stringify(a)))
? 如果 data 里有NaN、Infinity和-Infinity,则序列化的结果会变成null
const a = {
b: NaN,
c: 1.7976931348623157E+10308,
d: -1.7976931348623157E+10308,
}
console.log(JSON.parse(JSON.stringify(a)))
② 手写递归方法: 递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝。
function deepClone(target){
if(target !== null && typeof target === 'object'){
let result = Object.prototype.toString.call(target) === "[object Array]" ? [] : {};
for (let k in target){
if (target.hasOwnProperty(k)) {
result[k] = deepClone(target[k])
}
}
return result;
}else{
return target;
}
}
? hasOwnProperty(链接跳转至详情:https://blog.csdn.net/i_dont_know_a/article/details/84324051)
function deepCopy(source) {
if (!source && typeof source !== 'object') { 判断source 是不是引用类型。
throw new Error('error arguments', 'deepClone')
}
const targetObj = source.constructor === Array ? [] : {}
Object.keys(source).forEach((keys) => {
if (source[keys] && typeof source[keys] === 'object') {
targetObj[keys] = deepCopy(source[keys])
} else {
targetObj[keys] = source[keys]
}
})
return targetObj
}
var obj = {
name: 'test',
main: {
a: 1,
b: 2,
},
fn: function () {},
friends: [1, 2, 3, [22, 33]],
}
let query = deepCopy(obj)
query.friends[2]=4
console.log(obj)
console.log(query)
function deepClone(target) {
function getType(target) {
return Object.prototype.toString.call(target)
}
function isObject(target) {
return target !== null && (typeof target === 'object' || typeof target === 'function');
}
function handleOherData(target) {
const type = getType(target);
switch (type) {
case "[object Date]":
return new Date(target)
case "[object RegExp]":
return cloneReg(target)
case "[object Function]":
return cloneFunction(target)
}
}
function cloneSymbol(targe) {
const a = String(targe);
const b = a.substring(7, a.length - 1);
return Symbol(b);
}
function cloneReg(target) {
const reFlags = /\w*$/;
const result = new target.constructor(target.source, reFlags.exec(target));
result.lastIndex = target.lastIndex;
return result;
}
function cloneFunction(targe) {
const bodyReg = /(?<={)(.|\n)+(?=})/m;
const paramReg = /(?<=\().+(?=\)\s+{)/;
const targeString = targe.toString();
if (targe.prototype) {
const param = paramReg.exec(targeString);
const body = bodyReg.exec(targeString);
if (body) {
if (param) {
const paramArr = param[0].split(',');
return new Function(...paramArr, body[0]);
} else {
return new Function(body[0]);
}
} else {
return null;
}
} else {
return eval(targeString);
}
}
function handleWhile(array, callback) {
let index = -1;
const length = array.length;
while (++index < length) {
callback(array[index], index);
}
}
function clone(target, map) {
if (isObject(target)) {
let result = null;
if (getType(target) === "[object Array]") {
result = []
} else if (getType(target) === "[object Object]") {
result = {}
} else if (getType(target) === "[object Map]") {
result = new Map();
} else if (getType(target) === "[object Set]") {
result = new Set();
}
if (map.has(target)) {
return map.get(target);
}
map.set(target, result);
if (getType(target) === "[object Map]") {
target.forEach((value, key) => {
result.set(key, clone(value, map));
});
return result;
} else if (getType(target) === "[object Set]") {
target.forEach(value => {
result.add(clone(value, map));
});
return result;
} else if (getType(target) === "[object Object]" || getType(target) === "[object Array]") {
const keys = getType(target) === "[object Array]" ? undefined : Object.keys(target);
function callback(value, key) {
if (keys) {
key = value
}
result[key] = clone(target[key], map)
}
handleWhile(keys || target, callback)
} else {
result = handleOherData(target)
}
return result;
} else {
if (getType(target) === "[object Symbol]") {
return cloneSymbol(target)
} else {
return target;
}
}
}
let map = new WeakMap;
const result = clone(target, map);
map = null;
return result
}
loadsh:_.cloneDeep() jQuery中extend( )
let obj = {
childs: ['Jack', 'Tom'],
age: 45
}
let newObj = $.extend(true, {}, obj)
newObj.childs[0] = 'Jone'
console.log(newObj.childs[0])
console.log(obj.childs[0])
8.总结:
|