在chrome的开发者工具中,通过断点调试,我们能够非常方便的一步一步的观察JavaScript的执行过程,直观感知函数调用栈,作用域链,变量对象,闭包,this等关键信息的变化。因此,断点调试对于快速定位代码错误,快速了解代码的执行过程有着非常重要的作用,这也是我们前端开发者必不可少的一个高级技能。
函数在被调用执行时,会创建一个当前函数的执行上下文。在该执行上下文的创建阶段,变量对象、作用域链、闭包、this指向会分别被确定。JavaScript程序中一般有多个函数,JavaScript引擎使用函数调用栈来管理这些函数的调用顺序,函数调用栈的调用顺序与栈数据结构一致。
代码段1
var fn; function funcOut(){ var a = 2; function funcIn(){ console.log(a); } fn = funcIn; } function funcTest(){ fn(); } funcOut(); funcTest();
在funcOut()处设置断点,刷新页面;
点击step into,注意观察下方call stack与scope的变化,以及函数执行位置的变化。
我们可以看到,在funcOut内部声明的funcIn函数在调用时访问了它的变量a,因此funcOut成为了闭包。
代码段2
var fn; var n = 20; function funcOut(){ var a = 2; function funcIn(a){ console.log(a); } fn = funcIn; } function funcTest(){ fn(n); } funcOut(); funcTest();
闭包没了,作用域链中没有包含funcOut了。
代码段3
function funcOut() { var a = 2; return function funcIn() { var b = 20; return function fn() { console.log(a); } } } var funcIn = funcOut(); var fn = funcIn(); fn();
fn只访问了funcOut中的a变量,因此它的闭包只有funcOut。
代码段4
function funcOut() { var a = 2; return function funcIn() { var b = 20; return function fn() { console.log(a,b); } } } var funcIn = funcOut(); var fn = funcIn(); fn();//2 20
这个时候,闭包变成了两个。分别是funcIn,funcOut。
代码段5
//闭包在模块中的应用 (function() { var a = 10; var b = 20; var myObj = { c: 20, sum1: function(x) { return a + x; }, sum2: function() { return a + b + this.c; }, sum3: function(k, j) { return k + j; } } window.myObj = myObj; })(); myObj.sum1(100); myObj.sum2(); myObj.sum3(); var funcTest = myObj.sum3; funcTest();
sum1执行时,闭包为外层的自执行函数,this指向myObj。
sum2执行时,闭包为外层的自执行函数,this指向myObj。
sum3执行时,闭包为外层的自执行函数,this指向myObj。
funcTest执行时,闭包为外层的自执行函数,this指向Window。
这里的this指向显示为Object或者Window,大写开头,他们表示的是实例的构造函数,实际上this是指向的具体实例。
代码段6
var a = 10; var obj = { a: 20 } function fn() { console.log(this.a); } fn.call(obj);
代码段7
function funcOut() { var a = 10; function funcIn1() { return a; } function funcIn2() { return 10; } funcIn2(); } funcOut();
这个例子,和其他例子不太一样。虽然funcIn2并没有访问到funcOut的变量,但是funcOut执行时仍然变成了闭包。而当我将funcIn1的声明去掉时,闭包便不会出现了。我暂时也不知道应该如何解释这种情况。只能大概知道与funcIn1有关,可能浏览器在实现时就认为只要存在访问上层作用域的可能性,就会被当成一个闭包吧。