美文网首页将来跳槽用
闭包、堆栈、深浅克隆

闭包、堆栈、深浅克隆

作者: 无穷369 | 来源:发表于2021-02-21 21:59 被阅读0次

一、闭包

一句话概括专有名词

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

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

闭包的几个特点

  • 函数嵌套函数
  • 内部函数可以引用外部函数的参数和变量
  • 外部函数的变量会常驻内存中不销毁

例子

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()}

相关文章

  • 闭包、堆栈、深浅克隆

    一、闭包 一句话概括专有名词 闭包函数:声明在一个函数中的函数叫做闭包函数。 闭包:内部函数总是可以访问其所在的外...

  • 闭包

    什么是闭包? 闭包就是函数的局部变量的集合,只是这些局部变量在函数返回后会继续存在。闭包就是函数的‘堆栈’在函数返...

  • js背诵计划

    谈谈你对闭包的理解,以及在项目中的应用! 回答技巧 1.阐述闭包是什么?(引申:堆栈、EC、AO、VO、SCOPE...

  • 前端面试题【Day01】

    本篇绪论1,闭包2,深浅拷贝3,防抖、节流 1,闭包 闭包的定义很简单:函数 A 返回了一个函数 B,并且函数 B...

  • JavaScript闭包

    闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。 闭包就是就是函数的“堆栈”在函数返回后并不释...

  • 面试 | JS 闭包经典使用场景和含闭包必刷题

    思维导图 闭包 了解闭包前先来了解一下上级作用域和堆栈内存释放问题。 上级作用域的概念 函数的上级作用域在哪里创建...

  • 前端线路图

    1 堆栈内存以及闭包作用域 1 js中的基本数据类型以及其区别 (8种) 2 js堆栈内存的运行机制 3 变量提升...

  • 深浅克隆(拷贝)

    在前端项目开发中,很多情况下都是在操作数据,如果碰到复杂的数据,操作起来就比较困难了。 例如:vue中数据是双向绑...

  • 闭包其实很简单

    什么是闭包 闭包是函数式编程基石,在形式上就是一个函数内部定义另一个函数,函数的堆栈在在函数返回后并不释放,我们也...

  • 闭包

    定义 子函数可以访问到其他函数作用域中的数据,称之为闭包 堆栈内存 1、ECStack: Execution Co...

网友评论

    本文标题:闭包、堆栈、深浅克隆

    本文链接:https://www.haomeiwen.com/subject/hnuzxltx.html