摘自《高程3》版本 朋友推荐《高性能JS》这部分讲的比较细致
- JavaScript 是
变量松散类型
,不存在定义某个变量必须要保存何种数据类型规则,变量的值及其数据类型可以在脚本的生命周期内改变。
在将一个值赋值给变量时,解析器必须确定这个值是基本类型值还是引用类型值。
基本类型值
- Undefined
- Null
- Boolean
- Number
- String
引用类型值
- 引用类型值是保存在内存中的对象,与其他语言不同,JS不允许直接访问内存中的位置,也就是不能直接操作对象的内存空间。
- 在操作对象时,实际上是在操作对象的引用而不是实际的对象,为此,引用类型的值是按引用访问的。
- 定义基本类型值和引用类型值的方式是类似的: 创建一个变量并为该变量赋值。
- 对于引用类型的值,我们可以为其添加属性和方法,也可以改变和删除其属性和方法。
除了保存的方式不同外,再从一个变量向另一个变量赋值基本类型值和引用类型值时,也不同。
基本类型
- 如果从一个变量向另一个变量复制基本类型的值,会在变量对象上创建一个新值,然后把该值复制到心变量分配的位置上。
引用类型
- 当从一个变量向另一个变量复制引用类型的值时,同样也会将存储在变量对象中的值复制一份放到为心变量分配的空间中。
- 不同的是,这个值的副本实际上是一个指针,而这个指针指向存储在
堆
中的一个对象。
- 所有函数的参数都是按值传递的,但是会根据值的类型——
基本类型值
、引用类型值
产生两种复制方式。 - 在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部。
- 在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量(即命名参数,或者用ECMAScript的概念来说,就是arguments对象中的一个元素)。
- 假如将对象obj作为参数传递给函数,当在函数内部重写obj时,这个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即被销毁。
- 在向参数传递基本类型的值时,被传递的值会复制给一个局部变量(即命名参数,或者用ECMAScrip的概念来说,就是arguments对象中的一个元素)。
- 在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量。
- 基本类型使用
typeof
- 引用类型使用
instanceof
- 执行环境(有时也称
环境
)。 - 执行环境定义了变量和函数有权访问的其他数据,决定了他们各自的行为。
- 每个执行环境都有一个与之关联的变量对象(
varibale object
) - 环境中定义的所有变量和函数都保存在这个对象中。
- 我们编写的代码无法访问这个对象,但是解析器在处理数据时会在后台使用它。
全局执行环境
- 全局执行环境是最外围的一个执行环境。根据
ECMAScript
实现所在的宿主环境不用,表示执行环境的对象也不一样。 - 在
Web
浏览器中,全局执行环境被认为是window对象
,因此所有全局变量和函数都是作为window对象
的属性和方法创建的。 - 某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁。
- 全局执行华景知道引用程序退出: 例如关闭网页或浏览器时才会被销毁。
作用域链
- 当代码在一个环境中执行时,会创建变量对象的一个
作用域链
。 作用域链
的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。- 作用域链的前端,始终都是当前执行的代码所在环境的变量对象。
- 如果这个环境是函数,则将其
活动对象
作为变量对象。 - 活动对象在最开始时,只包含一个变量,即
arguments
对象(这个对象在全局环境中是不存在的) - 作用域链中的下一个变量对象来自包含(外部)环境,而在下一个变量对象则来自下一个包含环境。这样,一直延续到全局环境。
- 全局执行环境的变量对象始终都是作用域链中的最后一个对象。
标识解析
- 沿着作用域链一级一级地搜索标识符的过程。
- 搜索过程始终从作用域链的前端开始,然后逐级地向后回溯,直至找到标识符为止。
- 如果找不到标识符,通常会发生错误。
- 执行环境的类型总共有两种——全局和局部(函数)。
- 有些语句可以在作用域链的前端临时增加一个变量对象,该变量对象会在代码执行后被移除。
try-catch
的catch
块、with
catch和with
- 这两个语句都谁在作用域链的前端添加一个变量对象。
- 对
with
语句来说,会将指定对象添加到作用域链中。 - 对
catch
语句来说,会创建一个新的变量对象,其中包含的是被抛出的错误对象的声明。 - 在<=IE8版本的JS实现中,存在一个与标准不一致的地方,在
catch
语句中捕获的错误对象会被添加到执行环境的变量对象,而不是catch
语句的变量对象中
- 花括号在JS中并不是一个块级作用域(es6是了)。
声明变量
- 使用
var
申明的变量会自动被添加到最接近的环境中。 - 如果初始化变量时,没有使用
var
声明,该变量会自动被添加到全局环境。 - 不声明而直接初始化变量是一个常见的错误做法,在严格模式下,初始化未经声明的变量会导致错误。
查询标识符
- 当在某个环境中为了读取或写入而引用一个标识符时,必须通过搜索来确定该标识符实际代表什么。
- 搜索过程从作用域链的前端开始,向上逐级查询与给定名字匹配的标识符。
- 如果再局部环境中找到了该标识符,搜索过程停止,变量就绪。
- 如果在局部环境中没有找到该变量名,则继续沿作用域链向上搜索。
- 搜索过程将一直追溯到全局环境的变量对象。
- 如果在全局环境中也没有找到这个标识符,这意味着该变量尚未声明。
标记清除 引用计数 性能问题 管理内存
- 一旦数据不再有用,最好将其值设置为null来释放其引用——解除引用。
- 局部变量会在他们离开执行环境时自动被解除引用。