将来跳槽用

闭包、堆栈、深浅克隆

2021-02-21  本文已影响0人  无穷369

一、闭包

一句话概括专有名词

闭包函数:声明在一个函数中的函数叫做闭包函数。

闭包:内部函数总是可以访问其所在的外部函数中声明的参数或变量。

闭包的几个特点

例子

function external(){
    var i = 0;
    function inside(){
        i++;
        console.log(i);
    }
    return inside;
}
var run = external();
run();
run();
run();
var run2 = external();
run2();
run2();
run2();

执行结果:1 2 3 1 2 3

闭包的应用场景

function Person(value){
    var name = value;
    this.getName = function(){
        return name;
    }
    this.setName = function(value){
        name = value;
    }
}
var person = new Person('张三');
console.log(person.getName()); // 张三
person.setName('李四');
console.log(person.getName()); // 李四

以上代码的构造函数中定义了两个特权方法 getName() setName() 这两个方法可以通过对象访问,而且都有权访问私有变量 name 但是在 Person 外部是无法访问到 name

二、堆栈

栈内存主要用于存储基本类型的变量,包括Boolean、Number、String、undefined、null以及对象变量的指针
堆内存主要用于存储对象(引用类型值 Object Function)

全局对象(GO)

var globalObject = {
  Math: {},
  String: {},
  document: {}
  ...
  window: this
}

执行上下文栈(ECStack)
执行上下文(EC)
. 值存储区(变量对象VO)
. 活动对象(AO)
Scope:作用域,创建函数的时候赋值
Scope Chain:作用域链

image.png

全局执行上下文

  1. 在执行全局代码前将window确定为全局执行上下文
  2. 对全局数据进行预处理
    var定义的全局变量赋值为undefined,添加为window的属性
    function声明的全局函数赋值fun,添加为window的方法
    this赋值window
  3. 开始执行全局代码

函数执行上下文

  1. 在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象
  2. 对局部数据进行预处理
    形参变量赋值实参,添加为执行上下文的属性
    arguments赋值实参列表,添加为执行上下文的属性
    var定义的局部变量赋值undefined,添加为执行上下文的属性
    function声明的函数赋值fun,添加为执行上下文的方法
    this赋值调用函数的对象
  3. 开始执行函数体代码

1、var 和function声明创建在全局对象中,而let const class声明的变量创建在全局scope中
2、先到全局scope中找变量,查找不到再到全局对象中查找

三、深浅克隆

浅克隆只是克隆了内存地址,实际操作的还是同一块内存空间,所以在克隆后改变值会影响到被克隆原有的值。

案例

let a = {b: 1}
let c = a
c.b = 3
console.log(a) // {b: 3}
执行过程

那如何才能使变量c新开辟一块儿空间不和a公用呢,这个时候就要用深克隆的方式了

let a = {b: 1}
let c = {...a}
c.b = 3
console.log(a) // {b: 1}
console.log(c) // {b: 3}
执行过程

但要注意,上面这只是简单的一层对象的深克隆,如果我写成多层对象,深克隆就失效了。

let a = {b: {c: 1}}
let d = {...a}
d.b.c = 3
console.log(a) // {b: {c: 3}}

那像这种该如何深克隆呢,也有办法,先把对象转换成字符串,然后再转换成对象。

let a = {b: {c: 1}}
let d = JSON.parse(JSON.stringify(a))
d.b.c = 3
console.log(a) // {b: {c: 1}}
console.log(d) // {b: {c: 3}}

但是这里要注意,JSON.stringify是无法将function,Data等类型转换成字符串的,如果对象中包含了这样的类型值,JSON.stringify会过滤掉这些属性。要想实现对含有特殊类型值的对象实现深拷贝,就得使用递归。

function deepClone(obj){
  // 过滤特殊情况
  if (obj === null) return null;
  if (typeof obj !== 'object') return obj;
  if (obj instanceof RegExp) return new RegExp(obj);
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof Function) return new Function(obj);
  // 不直接创建空对象的目的是克隆的结果和之前保持相同的所属类
  let newObj = new obj.constructor;
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = deepClone(obj[key]);
    }
  }
  return newObj;
}
let a = {b: {c: 1},d: function(){}}
let e = deepClone(a)
e.b.c = 3
console.log(a) // {b: {c: 1},d: f()}
console.log(e) // {b: {c: 3},d: f()}
上一篇 下一篇

猜你喜欢

热点阅读