重点:
一、单线程
js引擎是单线程,模拟多线程(短时间内轮流执行多个任务的片段)
步骤:
1.切分任务
2.将任务随机排列,组成队列
3.按顺序将任务片段送进js进程
4.js线程执行任务片段
二、数据类型
- 基本数据类型的特点:直接存储在栈(stack)中的数据
- 引用数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里
1.原始值是不可改变的,原因如下:
var a = 3;
var b = a;
a = 1;
console.log(a); // 1
console.log(b); // 3
var a = 3;
var b = a;
a = 1;
2.引用值在堆栈中的存放
引用数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里
var arr1 = [1,2,3,4,5];
var arr2 = arr1;
arr1.push(5);
console.log(arr1); // [1,2,3,4,5,5]
console.log(arr2); // [1,2,3,4,5,5]
arr1 = [1,2];
console.log(arr1); // [1,2]
console.log(arr2); // [1,2,3,4,5,5]
var arr1 = [1,2,3,4,5];
var arr2 = arr1;
当arr1.push(5);时,arr2会跟着arr1一起变化
arr1 = [1,2]
arr1重新赋值,arr2不会跟着改变
三、赋值
赋值:只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
当其中一个值改变时,另一个值也跟着改变。
var obj1 = {
a: 1,
b: 2,
c: [3,4,5],
d: function() { console.log(000); }
}
var obj2 = obj1;
obj2.a = 6;
console.log(obj1); //{a: 6, b: 2, c: Array(3), d: ƒ}
console.log(obj2); //{a: 6, b: 2, c: Array(3), d: ƒ}
四、浅拷贝
浅拷贝:创建一个新对象。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。
var obj1 = {
a: 1,
b: 2,
c: [3,4,5],
d: function() { console.log(000); }
}
function shallowCopy(obj1) {
var resultObj = {};
for (var prop in obj1) {
if (obj1.hasOwnProperty(prop)) {
resultObj[prop] = obj1[prop];
}
}
return resultObj;
}
var obj2 = shallowCopy(obj1);
obj2.a = 6;
obj2.c[0] = 7;
console.log(obj1); //{a: 1, b: 2, c: [7,4,5], d: ƒ}
console.log(obj2); //{a: 6, b: 2, c: [7,4,5], d: ƒ}
浅拷贝方法:
1.如上的属性复制方法
2.Object.aaign():
var obj1 = {
a: 1,
b: 2,
c: [3,4,5],
d: function() { console.log(000); }
}
var obj2 = Object.assign({}, obj1);
obj2.a = 6;
obj2.c[0] = 7; // 浅拷贝
console.log(obj1); // {a: 1, b: 2, c: [7,4,5], d: ƒ}
console.log(obj2); // {a: 6, b: 2, c: [7,4,5], d: ƒ}
obj2.c = [8,9,0]; //
console.log(obj1); // {a: 1, b: 2, c: [7,4,5], d: ƒ}
console.log(obj2); // {a: 6, b: 2, c: [8,9,0], d: ƒ}
3.如果是数组,可使用Array.prototype.concat()和Array.prototype.slice(),这两个方法都不修改原数组
Array.prototype.concat():
var arr1 = [1,[2,3,4],5];
var arr2 = arr1.concat();
arr2[0] = 6;
arr2[1][0] = 7;
console.log(arr1); //[1,[7,3,4],5]
console.log(arr2); //[6,[7,3,4],5]
Array.prototype.slice():
var arr1 = [1,[2,3,4],5];
var arr2 = arr1.slice();
arr2[0] = 6;
arr2[1][0] = 7;
console.log(arr1); //[1,[7,3,4],5]
console.log(arr2); //[6,[7,3,4],5]
五、深拷贝
1.JSON.parse(JSON.stringify()):用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。
可以实现数组或对象深拷贝,但不能处理函数
var obj1 = {
a: 1,
b: 2,
c: [3,4,5],
d: function() { console.log(000); }
}
var obj2 = JSON.parse(JSON.stringify(obj1));
console.lpg(obj2); // {a: 1, b: 2, c:[3,4,5]} //d中的函数直接被略去
2.手写递归方法:递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝
//定义检测数据类型的功能函数
function checkedType(target) {
return Object.prototype.toString.call(target).slice(8, -1)
}
//实现深度克隆---对象/数组
function clone(target) {
//判断拷贝的数据类型
//初始化变量result 成为最终克隆的数据
let result, targetType = checkedType(target)
if (targetType === 'Object') {
result = {}
} else if (targetType === 'Array') {
result = []
} else {
return target
}
//遍历目标数据
for (let i in target) {
//获取遍历数据结构的每一项值。
let value = target[i]
//判断目标结构里的每一值是否存在对象/数组
if (checkedType(value) === 'Object' ||
checkedType(value) === 'Array') { //对象/数组里嵌套了对象/数组
//继续遍历获取到value值
result[i] = clone(value)
} else { //获取到value值是基本的数据类型或者是函数。
result[i] = value;
}
}
return result
}