执行上下文(Execution Context): 函数执行前进行的准备工作(也称执行上下文环境)
js 的执行环境:
全局环境
函数环境
eval函数环境 (已不推荐使用)
执行栈(函数调用栈)后进先出
栈底的永远是全局环境的执行上下文
栈顶的是当前正在执行函数的执行上下文
注意:全局环境只有一个,对应的全局执行上下文也只有一个,只有当页面被关闭之后它才会从执行栈中被推出,否则一直存在于栈底
上下文的生命周期:
创建阶段:
函数被调用时,进入函数环境,为其创建一个执行上下文,此时进入创建阶段
执行阶段:
执行函数中代码时,此时执行上下文进入执行阶段
创建阶段的操作:
- 创建变量对象
函数环境会初始化创建Arguments对象(并赋值)
函数声明(并赋值) 变量声明,
函数表达式声明(未赋值)
- 确定this指向(this由调用者确定)
- 确定作用域(词法环境决定,哪里声明定义,就在哪里确定)
执行阶段的操作:
-
变量对象赋值
-
变量赋值
函数表达式赋值
调用函数
- 顺序执行其它代码
函数声明优先级 :
函数声明优先 > 变量>函数表达式
javascript:对变量的存储位置:栈内存,堆内存,池(一般也会归类为栈中)。
栈内存:(后进后出)
- 基本类型:String,Number,Boolean,Null,Undefined,symbol直接存放
- 对象变量的指针(Function,Array,Object)
堆内存:一种经过排序的树形数据结构
Function,Array,Object
注意:
闭包中的基本数据类型变量不保存在栈内存中,而是保存在堆内存中。
栈内存中变量一般在它的当前执行环境结束就会被销毁被垃圾回收制回收, 而堆内存中的变量则不会,因为不确定其他的地方是不是还有一些对它的引用。 堆内存中的变量只有在所有对它的引用都结束的时候才会被回收。
var a = new String('123')
var b = String('123')
var c = '123'
console.log(a==b, a===b, b==c, b===c, a==c, a===c)
>>> true false true true true false
深浅拷贝
上面栈堆了解后,可以了解深浅拷贝就容易了。
浅拷贝:
只是复制基本类型的数据或者指向某个对象的指针,而不是复制对象本身,源对象和目标对象共享同一块内存;若对目标对象进行修改,存在源对象被篡改的可能。
function shadowClone (sourceObj = {}) {
let targetObj = Array.isArray(sourceObj) ? [] : {};
let copy;
for (var key in sourceObj) {
copy = sourceObj[key];
targetObj[key] = copy;
}
return targetObj;
}
代码来源
深拷贝:
实现方法就是递归调用“浅拷贝”。深拷贝会创造一个一模一样的对象,其内容地址是自助分配的,拷贝结束之后,内存中的值是完全相同的,但是内存地址是不一样的,目标对象跟源对象不共享内存,修改任何一方的值,不会对另外一方造成影响。
function deepClone (sourceObj = {}) {
let targetObj = Array.isArray(sourceObj) ? [] : {};
let copy;
for (var key in sourceObj) {
copy = sourceObj[key];
if (typeof(copy) === 'object') {
if (copy instanceof Object) {
targetObj[key] = deepClone(copy);
} else {
targetObj[key] = copy;
}
} else if (typeof(copy) === 'function') {
targetObj[key] = eval(copy.toString());
} else {
targetObj[key] = copy;
}
}
return targetObj;
}
合并:
function clone (deep = true, sourceObj = {}) {
let targetObj = Array.isArray(sourceObj) ? [] : {};
let copy;
for (var key in sourceObj) {
copy = sourceObj[key];
if (deep && typeof(copy) === 'object') {
if (copy instanceof Object) {
targetObj[key] = clone(deep, copy);
} else {
targetObj[key] = copy;
}
} else if (deep && typeof(copy) === 'function') {
targetObj[key] = eval(copy.toString());
} else {
targetObj[key] = copy;
}
}
return targetObj;
}
深拷贝的几种实现方法:
1.若拷贝数组是纯数据(不含对象),可以通过concat() 和 slice() 来实现深拷贝。(第一层)
2. Object.assign()、Object.create() 都是一层(根级)深拷贝,之下的级别为浅拷贝。
3. 若拷贝对象只有一层,可以通过对象的解构来实现深拷贝。
4. 用 JSON.stringify() 把对象转成字符串,再用 JSON.parse() 把字符串转成新的对象,可以实现对象的深复制。
参考修改:
https://segmentfault.com/a/1190000017469386
https://zhuanlan.zhihu.com/p/79840222
https://www.cnblogs.com/heioray/p/9487093.html