JavaScript红宝书02-变量、作用域和内存(Variables, Scope and Memory)

36 阅读3分钟

原始类型和引用类型

JavaScript中是不允许直接修改内存中的数据,只能操作这个对象的引用

注意:JavaScript中字符串类型与其他语音不同,JavaScript的字符串类型是基本数据类型,不是引用类型。

深复制和浅复制

基本数据类型的六种是把值复制到栈的新的内存空间中,深复制

引用数据类型,修改指针的指向,堆中不会复制一份新的变量,浅复制

基本实现

上下文和作用域

一段上下文在执行完所有的代码之后,这个上下文就会被销毁。

全局上下文是最外层的上下文,在浏览器中全局上下文窗口对象(window)

全局创建的方法和变量,都是window对象的属性和方法。

使用let和const在最上层进行定义,不会算在全局的上下文里,但是可以被解析到作用域链中。

注意:全局上下文,在整个应用退出之前都不会销毁

方法的上下文

方法有自己的上下文,和属性不一样,方法是在上下文栈中,不管是否执行到该方法,先都压入栈中,执行完一个方法,从栈中弹出一个方法。

上下文链结构图

一个内层的上下文可以通过外层上下文链访问所有东西,但外层上下文并不能通过一个内层的上下文访问所有东西。

方法作用域内使用var定义变量

在方法作用域内,使用var定义变量,会自动添加到可用的最直接的上下文。在方法中,最直接的上下文之一是with语句。如果变量被初始化没有被声明则会自动添加到全局上下文中。

举例:

这么写就会报错

function addSum(num1, num2) {
      var sum = num1 + num2
      return sum
}
let result = addSum(1,2)
console.log(sum)

这样写就不会报错

function addSum1(num1, num2) {
      sum = num1 + num2
      return sum
}
let result1 = addSum1(1,2)
console.log(sum)

垃圾回收

JavaScript是垃圾回收机制语言,意味着执行环境需要管理代码执行期间的内存空间(不需要开发者手动管理)。

一般情况下生命周期内方法内部的局部变量,在离开作用域通常就认为不再使用了,但也有不平常的情况,就需要两种技术对特殊情况的处理,标记-清除和引用计数。

标记-清除

一个变量进入了上下文,会被标记在上下文中,这块内存将不会被释放。

变量离开上下文,会被标记在上下文外。

当垃圾回收器运行,会清除内存中标记在上下文中的变量,和被变量引用的在上下文中的变量,清除标记值并且回收对应的内存空间。

引用计数

和iOS一样,定义时引用计数为0,该变量多一个引用加1,少一个减1,为0时释放(不过iOS的引用计数是对于对象来说,这本书里说的是变量,不知道是我英语水平问题,还是这边就这样)

使用let和const提升性能

let和const是块级作用域,var可能会出现定义提升的问题,作用域不稳定,let和const可以尽快被进行垃圾回收,提升性能

隐藏类和删除操作

V8引擎会隐藏类,V8引擎会把两个相同类的实例共享一个隐藏类,这样可以共享构造函数和原型,提高性能