Skip to content

Latest commit

 

History

History
174 lines (101 loc) · 5.86 KB

第4章-变量、作用域和内存问题.md

File metadata and controls

174 lines (101 loc) · 5.86 KB

变量、作用域和内存问题

学习目标

  1. 理解基本类型和引用类型的值
  2. 理解执行环境
  3. 理解垃圾收集

JavaScript松散类型的本质,决定了它只是在特定时间用于保存特定的值的一个名字而已。由于不存在定义某个变量必须保存何种数据类型值的规则,变量的值,�及其数据类型可以在脚本的声明周期内改变。

4.1 基本类型和引用类型的值

js中包括两种不同数据类型的值

  1. 几本类型值 (undefined null string number boolean)
  2. 引用类型值 (对象)

4.1.1 动态属性

这节说了一个问题,只能给引用类型的值动态地添加属性,不能给基本类型的值添加。

4.1.2 复制变量值

两种数据类型,除了保存方式不一样之外,在从一个变量向另一个变量复制基本类型值和引用类型值时,也存在不同。

  1. 如果从一个变量向另一个变量复制基本类型的值,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上。
var num1 = 5
var num2 = num1

看下图

看下图

  1. 当用一个�变量向另一个变量�复制�引用类型的值的时候,同样也会将存储在变量对象中的值�复制一份放到新变量分配的空间中,不同的是,这个值的副本实际上是一个指针,而这个指针�指向存储在堆中的一个对象,复制操作结束之后,两个变量实际上将引用�同一个对象。所以只要改变其中一个变量就会�影响到另一个变量。
var obj1 = new object()
var obj2 = obj1
ibj1.name = 'qianlongo'
alert(obj.name) // qianlongo

基本原理看下图

4.1.3 传递参数

ECMAScript中�所有函数的参数都是按值传递的,也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。

理解上面这句话,大概就可以理解js中的传参机制了,还有可以可以把函数的参数想象成局部变量。

4.1.4 检测类型

要检测一个变量是不是基本数据类型的?typeof是得力的工具,更具体一些旧事typeof可以确定一个变量是string、number、boolean、还是undefined,但是null会返回object。

4.2 执行环境及作用域

4.2.1 延长作用域

  1. try catch
  2. with

没有块级作用域

在类似C语言中,由花括号封闭的代码块都有自己的作用域,因而支持根据条件来定义变量。

if (true) {
  var color = 'blue'
}

alert(color) // blue

如果在�类似c语言中,if执行之后变量color会被销毁,但是在js中会被添加到当前的执行环境中。

声明函数

使用var声明的变量会自动添加到最接近的环境中,在函数内部,最接近的环境就是函数局部环境,在with语句中,最接近的环境是函数环境,如果初始化的时候没有制定var声明,该变量就会被添加到全局环境中。

查询标志符

说白了就是js在查找变量的过程是逐级向上的。

var color = 'blue'

function getColor () {
  return color
}

alert(getColor()) // blue

4.3 垃圾收集

JavaScript有自动的垃圾回收机制,执行环境会自动管理代码执行过程中使用的内容。

垃圾回收机制的基本原理

找出那些�不再继续使用的变量,然后释放其占用的内存。�为此,垃圾收集器会按照固定的时间间隔周期性地执行这一操作

垃圾回收机制一般有两种,标记清除 引用计数

4.3.1标记清除

基本原理

当变量进入环境(�例如: 声明一个变量),就将这个变量标记为"进入环境",当变量离开环境时将其标志为"离开环境"

4.3.2 引用计数

基本原理

引用计数的含义是跟踪记录每个值被引用的次数

  1. 当声明了一个变量并将一个引用类型的值赋给该变量时,则这个值的引用次数就是1,如果同一个值又被赋给另一个变量,则该引用次数又加一.
  2. 相反如果包含这个值引用的变量又取得了�另外一个值,则这个值的引用次数减一。
  3. 当这个值的引用次数变成0的时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。

引用计数带来的问题

function problem () {
  var objectA = new object()
  var objectB = new object()
  
  objectA.somOtherObject = objectB
  objectB.somOtherObject = objectA
}

这个例子中两个对象通过各自的属性相互引用,导致这两个对象的引用次数都是2,且永远不可能为0。在菜用标记清除的策略中,函数执行完成之后,两个对象都离开的作用域,所以循环引用不是问题。

ie中的麻烦

ie中的BOM和DOM对象不是JavaScript对象,而是使用�c++以COM(Component Object Model 组件对象模型)对象形成的。�但是COM对象的垃圾收集机制是引用计数,所以即使ie的JavaScript引擎室使用标记清楚策略来实现的,但是因为存在上面的问题,依然会有循环引用带来的问题。

var element = document.getElementById('some_element')
var myObject = new Object()
myObject.element = element
element.someObject = myObject

为了避免以上问题,应该手动断原声js对象与DOM元素之间的连接

myObject.element = null
element.someObject = null

性能问题

主要说垃圾回收机制周期处理时间

管理内存

将不用的变量手动设置为null,解除引用关系。