JavaScript变量对象、执行环境和作用域链

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jlin991/article/details/60957928

首先不管是变量对象、执行环境或作用域链都是内部对象你无法直接用js访问。

JS两种变量类型的访问和内存问题

基本数据类型是按值访问的

引用类型的值是保存在内存中的对象。JS不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。 操作对象的时候实质是操作对象的引用而不是实际的对象。
严谨地说:

var a={v:2,c:3};
var b=a  //这种情况操作的是引用

a.x=23; //这种情况操作的是对象,实际也是找到这个对象并给这个对象的属性赋值
//这个属性是一个基本数据类型,那么赋值是按值访问的

动态的属性

对于引用类型,可以添加属性和方法,也可以删除改变属性和方法。
但是基本类型不能,尽管不会报错:

var name="xx";
name.age=27;
console.log(name.age); //undefiend

复制变量值

从一个变量向另一个变量复制基本类型值时,会在变量对象上创建一个新值,然后把该子复制到为新变量分配的位置上 。
这里写图片描述

从一个变量向另一个变量复制引用类型的值时,同样会将存储在变量对象中的值复制一份放到新变量分配的空间中。 不同的是,这个值的副本实际是一个指针!
这个指针指向存储在堆中的一个对象。
复制操作结束后,两个变量实际上将引用同一个对象。因此改变其中一个变量就会影响另一个变量!

这里写图片描述
这个图描述了 保存在变量对象中的变量和保存在堆中的对象之间的关系

详解介绍变量对象

JavaScript中的执行环境包括全局执行环境和函数执行环境这两种,每进入到一个执行环境都会创建一个变量对象这个对象中记录了在当前执行环境中可以访问到的变量,它们以变量对象的属性形式存在。也就是说这个变量对象成为“作用域”这个抽象概念的实体

变量对象
浏览器的解析器在处理数据时会在后台使用它,无法通过代码访问。

全局环境中:
1) 先是函数声明
2)变量声明其值为undefined,一直执行到这条语句的时候才被赋予具体值
函数环境中: (进入函数环境时,变量对象进行以下初始化)
1)arguments对象,对象中的值被赋予具体的参数值
2)函数的形参,变量对象的一个属性,其属性名就是形参的名字,其值对应实参的值,不传递的就是undefined
3)函数声明:也是变量对象的一个属性,属性名和值都是函数对象创建出来的,值为指向某个函数对象的引用
4) 变量声明:变量对象的一个属性,属性名为变量名

总结一句话:在进入上下文的时候(比如进入到一个全局环境或者是调用某个函数),变量对象除了arguments,函数的声明,以及参数被赋予了具体的属性值,其它的变量属性默认的都是undefined。

执行环境(上下文)和变量对象

执行环境定义了变量或函数有权访问的其他数据。每个执行环境都有一个与它关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。

全局执行环境
web浏览器中,全局执行环境被认为是window对象,因此所有全局变量和函数都是作为window的属性存在。

函数执行环境
每个函数都有自己的执行环境。 当执行流进入一个函数时,函数的环境会被推入一个环境栈中。 而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。

执行环境的销毁
某个执行环境中的所有代码执行完毕后,该环境被销毁。里面的变量和函数定义也被销毁!
对于全局执行环境来说就是程序退出,如关闭网页或浏览器。

创建作用域链

作用域链 — [[Scope]]引用,这是一个函数的内部属性。
它本质是一个指针列表,存放了它能够访问的各个执行环境的变量对象的引用!

(当代码在一个环境中执行时,就会创建变量对象的一个作用域链scope chain。 )

作用域的用途: 保证对执行环境有权访问的所有变量和函数的有序访问。
作用域链的前端始终是当前执行的代码所在的变量对象。 如果这个环境是函数,则将其活动对象作为变量对象
活动对象在最开始时只包含一个变量,即argument对象。作用域链中的下一个变量对象来自包含环境,而再下一个变量对象来自下一个包含环境。 以此类推。。。

作用域链与标识符搜索

标识符的搜索,也是沿着作用域链一级一级的搜索,搜索过程始终从作用域链的前端开始,逐级向后回溯。

作用域链:
这里写图片描述

内部执行环境可以通过作用域链访问外部执行环境中的变量或函数,反之无效。 这些环境之间是线性,有次序的。

改变作用域(临时延长作用域链)

函数每次执行时对应的执行黄环境都是独一无二的! 多次调用同一个函数会创建多个执行环境!当函数执行完毕后,执行环境会被销毁~~~ 每一个运行期执行环境都和一个作用域链关联。
而with 和 catch语句 ,就可以在运行期改变函数的作用域链。
它们会在作用域链的前端添加一个变量对象。 对with语句来说,会将指定的对象添加到作用域链中。 catch则是创建一个新的变量对象。
执行结束后就会被移除,这个变量对象是临时增加的。

猜你喜欢

转载自blog.csdn.net/jlin991/article/details/60957928