函数内变量取值的底层原理分析

【原创】本文阐述某些情况下内存泄漏的根本原因,深入分析函数变量取值底层原理;

示例****start

//【JS预解析】 经典题
function fn(i) {
    var i;
    alert(i);
};
fn(10); // 10

解释:函数fn内的行参,相当于var i = i;紧随其后又声明了变量i,但未赋值;根据var声明提升原理,在重复声明后才会完成复制操作(此代码不在函数内部依然表现如此);
示例****1

function  fn(j){

    j = 2323

};

var h = 23;

fn(h);//h依旧是23

解释:函数内的行参,相当于var j = j;所以函数内部重赋值h不受影响

示例****2


var data = [];

for (var k = 0; k < 3; k++) {

      data[k] = function () {

          alert(k);

    };

}

//输出结果

data[0](); // 3

data[1](); // 3

data[2](); // 3

解释:函数内的内的变量是在函数创建的时候保存了函数的作用域链,而不是变量。所以在调用的时候,就会顺着作用域链找到k的值,此时的k已经为3了!

示例****3


var data = [];

for (var k = 0; k < 3; k++) {

  data[k] = (function _helper(k) {

    return function () {

      alert(k);

    };

  })(k); //传入"k"值

}

//现在结果是正确的了

data[0](); // 0

data[1](); // 1

data[2](); // 2

解释:data[k]为自执行函数_helper执行之后的函数,自执行函数_helper接收参数k,相当于var k = k; 执行了三次,就相当于每次var k = k;创建了三个局部变量k,那么这个k会不会被释放呢?
答案是不会!因为自执行函数_helper的返回函数 使用到了局部变量k,会以[[scope]]的方式引用,只要data[k]不会被释放(注意:data[k]中的k下标和自执行函数_helper执行之后的函数,使用到的k局部变量不是同一个),那么_helper执行之后的函数,通过[[scope]]的方式引用的局部变量k将永远存在于内存之中;
函数内的内的变量是在函数创建的时候保存了函数的作用域链,而不是变量。所以在调用的时候,就会顺着作用域链找到k的值,此时的k找到的是被data引用所以无法释放的三块内存中,分别为0/1/2 这就是柯里函数的意义所在

示例****4


var x = 10;

function foo() {

  alert(x);

}

(function () {

  var x = 20;

  foo(); // 10, but not 20

})();

解释:我们再次看到,在标识符解析过程中,使用函数创建时定义的词法作用域--变量解析为10,而不是20。此外,这个例子也清晰的表明,一个函数(这个例子中为从函数“foo”返回的匿名函数)的[[scope]]持续存在,即使是在函数创建的作用域已经完成之后。

换句通俗易懂的说法:函数内的变量在函数激活(调用)的时候,会顺着 作用域链 向父级递归查找,这个 作用域链 在函数创建的时候,是以函数的一个属性[[scope]]保存的;

闭包内变量会保存在内存中,且不会被释放,就是因为被未释放的函数引用。

资料参考自汤姆大叔的博客

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容