诡异的 javascript 变量

诡异例子:

在绥阳等地区,都构建了全面的区域性战略布局,加强发展的系统性、市场前瞻性、产品创新能力,以专注、极致的服务理念,为客户提供网站设计制作、成都做网站 网站设计制作定制网站开发,公司网站建设,企业网站建设,成都品牌网站建设,成都全网营销推广,成都外贸网站建设公司,绥阳网站建设费用合理。

function DelayExe() {

var a = 10;

setTimeout( function Print() { console.log(a);}, 1000 );

}

以C++的观点来看:一旦函数DelayExe()执行完毕,变量 a 就不复存在,函数 Print() 根本引用不到变量a,必然抛出异常。

但是,在 js 中,在 DelayExe() 执行完毕 1000ms 后执行 Print() 函数,Print() 函数居然能正确引用 a。是不是很诡异?

概念和原理:

举个例子:

一个64位整型变量,在 C++ 程序中,只占8字节。

一个64位整型变量,在 js 中,占有以下空间:

M1:8字节,表达数值

M2:引用计数器,若是 5,表示有 5 个函数引用该变量。

每当一个函数引用该变量时,js 引擎就递增变量的引用计数器

每当一个函数用完该变量后,js 引擎就递减变量的引用计数器。若变量的引用计数器递减为 0,说明已没有函数用到该变量,该变量才会被删除。

由此可见:

C1:js 中的变量,不仅包含数值,还包含引用计数器。

C2:变量是否存在,取决于其引用计数器的值。

C3:js 引擎根据引用计数器的值决定是否删除变量,是否从内存中清除变量。

实际用例:

function DelayExe() {

var a = 10;

setTimeout( function Print() { console.log(a);}, 1000 );

}

以C++的观点来看:

变量 a 是函数DelayExe() 的局部变量,函数 DelayExe() 执行完毕,变量 a 就被删除,不再占用存储空间。

但是,js 的情况截然不同:

S1:执行函数 DelayExe()

S2:执行到语句 setTimeout() 时,做如下处理:

S2.1:在内存中分配一块空间,存储函数 Print(),

S2.2:由于函数 Print() 引用了变量 a,递增变量 a 的引用计数器

S2.3:安排函数 Print() 在 1000ms 后被放入任务队列调度执行

S3:函数 DelayExe() 执行完毕。由于此时变量 a 的引用计数器 > 0,所以 js 引擎不将其不删除,变量 a 依然存在。

S4:1000ms 后执行函数 Print(),执行完毕后,函数 Print() 不再引用变量 a,js 引擎递减变量 a 的引用计数器。此时,变量 a 的引用计数器递减为 0,不再被任何函数引用,于是 js 引擎才将其从内存中删除。

结论:

C1:js 变量的存在性,与变量的定义位置无关。

C2:js 变量是否存在,是否占用存储空间,取决于有没有被函数引用。

C2.1:若没有被任何函数引用,变量就被删除。

C2.2:若至少被一个函数引用,变量就存在。

C3:若一个变量被一个函数引用,但这个函数一直未被调用执行,那么这个变量就一直存在。


标题名称:诡异的 javascript 变量
链接地址:http://myzitong.com/article/dsojhhp.html