认识作用域

  • 作用域

作用域(scope)规定了变量能够被访问的“范围”,离开了这个“范围”变量便不能被访问

作用域分为:局部作用域;全局作用域

  1. 局部作用域分为函数作用域和块作用域
  1. 函数作用域:

在函数内部声明的变量只能在函数内部被访问,外部无法直接访问。

  1. 块级作用域:

在 JavaScript 中使用 { } 包裹的代码称为代码块,代码块内部声明的变量外部将【有可能】无法被访问。

  1. 全局作用域:<script> 标签 和 .js 文件 的【最外层】就是全局作用域,在此声明的变量在函数内部也可以被访问。

全局作用域中声明的变量,任何其它作用域都可以访问

  1. Var关键字,也可以用于声明变量

弊端:用var声明的变量都被放到window身上了,就是window的属性;

平时尽量不要使用var来声明变量,而应该使用let或const

尽量减少全局变量的定义,避免不必要的冲突和污染

  1. 如果函数中使用变量,但没有进行声明

我们指局部变量是说在局部定义的变量,如果该变量不是在局部定义的, 就不是当前的局部变量

  1. 作用域链

嵌套关系的作用域串联起来形成了作用域链

作用:作用域链本质上是底层的变量查找机制(就近原则)

在函数被执行时,会优先查找当前函数作用域中查找变量

如果当前作用域查找不到则会逐级向上查找父级作用域直到全局作用域

  1. 垃圾回收机制

JS中内存的分配和回收都是自动完成的,内存在不使用的时候会被垃圾回收器自动回收

内存的生命周期

JS环境中分配的内存, 一般有如下生命周期:

内存分配:当我们声明变量、函数、对象的时候,系统会自动为他们分配内存

内存使用:即读写内存,也就是使用变量、函数等

内存回收:使用完毕,由垃圾回收器自动回收不再使用的内存

说明:

全局变量一般不会回收(关闭页面回收)

一般情况下局部变量的值, 不用了, 会被自动回收掉

内存泄漏:程序中分配的内存由于某种原因程序未释放或无法释放叫做内存泄漏

垃圾回收机制-原理

引用计数法,是最初的一种垃圾回收机制,原理是统计所有对象的引用技术,只要没有人引用对象了(零引用),就会被回收掉

什么是引用?

o是变量{}创建的一个对象

对象存储在堆内存空间中,会被分配一个地址值,将地址值赋给o变量,此时我们可以叫o引用着该对象

总结:引用计数法就是数堆内存中对象被引用了多少次,如果只有0次就会被回收

致命缺点:循环引用

由于o1和o2互相引用这对方,哪怕没有变量引用他俩了,在内存中依然不会销毁,因为引用计数是1,所以引用计数法极易导致内存泄露

在2012年之后所有现代浏览器都取消这种算法了。取而代之的是标记清除法

标记清除法

假定全局作为根开始,一层一层往局部去标记所有对象,打完标记后,如果有些对象没有标记,就会被清楚

垃圾回收机制的三种优化

网址:

垃圾回收

  1. 分代收集(Generational collection)—— 对象被分成两组:“新的”和“旧的”。在典型的代码中,许多对象的生命周期都很短:它们出现、完成它们的工作并很快死去,因此在这种情况下跟踪新对象并将其从内存中清除是有意义的。那些长期存活的对象会变得“老旧”,并且被检查的频次也会降低。
  2. 增量收集(Incremental collection)—— 如果有许多对象,并且我们试图一次遍历并标记整个对象集,则可能需要一些时间,并在执行过程中带来明显的延迟。因此,引擎将现有的整个对象集拆分为多个部分,然后将这些部分逐一清除。这样就会有很多小型的垃圾收集,而不是一个大型的。这需要它们之间有额外的标记来追踪变化,但是这样会带来许多微小的延迟而不是一个大的延迟。
  3.  闲时收集(Idle-time collection)—— 垃圾收集器只会在 CPU 空闲时尝试运行,以减少可能对代码执行的影响。

  1. 闭包

概念:一个函数对周围状态的引用捆绑在一起,闭包让开发者可以从内部函数访问外部函数的作用域

简单理解:闭包 =  内层函数 + 外层函数的变量

闭包是指函数嵌套时,内层函数访问外层函数的局部变量

总结:

  1. 一旦发生闭包, 意味着外层函数的局部变量不会随着函数的结束而释放, 会长期存在一个叫 closure (闭包)的空间中。
  2. 闭包会导致内存泄露(但这种内存泄露是必要的,我们我无法阻止的,只能说尽量少用闭包,但必须用的时候还是得用),本该被释放的变量,无法被及时释放,会存在闭包空间中

闭包作用:实现数据的私有化(让外面的人无法修改内部的变量),避免全局污染,外层函数也可以访问里层函数变量

比如,我们要做个统计函数调用次数,函数调用一次,就++

全局变量:所有人都可以随意访问,这种数据就叫公共数据,及其容易篡改。导致出现一些严重的bug

    // 总结:

    // 闭包是什么:

    // 闭包就是函数的嵌套, 内层函数访问了外层函数的局部变量

    // 闭包有什么用:

    // 实现变量的私有化, 让外面的人无法修改内部的变量

    // 闭包会产生什么现象或问题:

    // 1. 内存泄漏

    // 2. 本该被释放的变量, 无法及时释放, 会存在闭包空间中

  1. 变量提升

Var关键字会进行声明提升,没有块级作用域

变量提升是 JavaScript 中比较“奇怪”的现象,它允许在变量声明之前即被访问(仅存在于var声明变量)

说明:

  1. 变量提升出现在当前作用域的最前面
  2.  提升时,只提升变量声明,不提升变量赋值
  3. let/const 声明的变量不存在变量提升
  4. 实际开发中推荐先声明再访问变量

变量提升是什么流程?

先把var 变量提升到当前作用域于最前面

只提升变量声明, 不提升变量赋值

然后依次执行代码

  1. 函数提升

分为2种

  • 函数声明提升

      提高函数使用的灵活性

  • 函数表达式的声明提升

      函数表达式则与函数提升不同

      只会提升声明, 不会提升赋值, 和之前的变量声明提升一样

arguments现在已经被淘汰,原因有2个

  1. 因为柯柏年参数(也就是是剩余参数)的出现
  2. 性能问题

arguments就是一个伪数组。仅存在于function中,他的作用是装载着所有的实参,因为arguments是动态伪数组,数据变化带来的性能损耗较大,每次都会同步更新所有参数,如果参数过多则会出现问题。在开启严格模式后就会彻底禁用

Arguments,现在开发中基本不用arguments了,可以使用可变参数完全代替arguments的功能

Arguments.calllee代表函数本身,一般用于匿名函数自调用,后来由于ES6的出现,不让用arguments了,所以callee自然也无法使用了,官方建议给函数起名字

8.函数参数

  1. 剩余参数(重点)

剩余参数:允许我们将一个不定数量的参数表示为一个数组

简单理解:用于获取多余的实参,并形成一个真数组

使用场景:

也可以解决形参和实参个数不匹配的问题

  1. 展开运算符

展开运算符(…),将一个数组/对象进行展开

展开运算符主要的作用是?

可以把数组展开,可以利用求数组最大值以及合并数组等操作

展开运算符和剩余参数有什么区别?

展开运算符主要是 数组展开(拆散)

剩余参数 在函数内部使用,把多个元素收集起来生成一个真数组(凝聚)+

    // 展开运算符

    // 不会修改原数组, 只是把数组外壳去了, 里面的内容取出来放在原地

    let arr = [1, 5, 8, 9]

    console.log(arr)

    console.log(arr[0], arr[1], arr[2], arr[3])

    console.log(...arr)

    // 求数组最大值 / 求最小值

    console.log(Math.max(1, 5, 0, 20))

    console.log(Math.max(...arr))

console.log(Math.max(1, 5, 8, 9))

    // 合并数组

    let arr1 = [1, 2, 3]

    let arr2 = [4, 5, 6]

    // let arr3 = [...arr1, ...arr2]

// console.log(arr3)

    let arr3 = []

    arr3.push(...arr1, ...arr2)

    console.log(arr3)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值