作用域链和闭包

1.作用域: 什么是?
域表示范围,即是作用范围(包括局部作用域和全局作用域)
作用域规则?
1.函数内允访问函数外的数据,反之不行
2.整个代码结构中只有函数可以限定作用域
3.作用规则首先使用提升规则分析
4.如果当前作用规则中可以找到,就不会到外面找
2.关于变量提升 即解析器会把函数声明和变量声明提升到前面。这里注意一下函数声明和表达式的区别,若是函数表达式,则提升的不是函数体,而是声明的函数名。

foo(); //foo is not a function,会把var foo提升到前面,但是函数体没有提升 foo1(); //1,会把函数提到前面 console.log(a); //undefined,变量提升会将var a提升到前面,但是还没有赋值 var foo=function(){ console.log(1); }; //函数表达式 function foo1(){ console.log(1); }; //函数表达式 var a=10;

3.关于作用域链 什么是?
只有函数可以产生作用域,主要是代码,至少有一个作用域,即全局作用域。凡是代码中有函数,那么函数就构成另一个作用域,如果函数还有函数,那么再在这个作用域中有产生一个作用域,那么将是这些所有列出来,可以有一个有函数内想函数外的链式结构。
作用域链的绘制
1.将全局看作一条链,即顶级链,记为0级
2.看全局作用域中有什么成员,就绘制到0级链上(看声明)
3.再找函数,只有函数可以限制作用域,因此只有函数菜可以引出一条新链,按照1、2…顺序依次绘制
var num=12; function f1(){ var num=123; function f2(){ console.log(num); } }

上面代码的作用域链如下:
作用域链和闭包
文章图片

变量的访问规则
1.若要使用变量,首先再本作用域链上找,如果有则直接使用
2.若没有,则往上一级找,若有直接使用,若还是没有,再往上找,直到全级链还是没有,就报错。另外:需注意,同一级的链无法访问。
4.关于闭包 什么是?
函数和其词法环境一起构成闭包,即可使函数再当前作用域作用域范围之外执行。
***作用***可读取函数内部的变量,可以使变量的值长期保存再内存中,生命周期较长,可用来实现js模块。
//使用闭包实现模块化 function myCounter() { var num = 0; function optionNum(val) { num += val; } var obj={ addNum: function(){ optionNum(1); }, subNum:function(){ optionNum(-1); }, value:function(){ return num; } } return obj; } var counter=myCounter(); counter.addNum(); console.log(counter.value()); } //函数的防抖也应用到了闭包 //运用单例模式模仿在一个页面中只能有一个登录框的效果,其中也用到了闭包 class LoginForm{ constructor(){ this.state='hiden' } show(){ if(this.state==='hiden'){ console.log('对话框显示'); this.state="show"; }else{ alert("对话框已经显示,无法同时显示两个") } } hide(){ if(this.state==='show'){ console.log('对话框隐藏'); this.state='hiden'; }else{ alert('对话框已经隐藏,无法再次隐藏'); } } } LoginForm.getLoginForm=(function(){ let instance; return function(){ if(!instance){ instance=new LoginForm(); } return instance; } })(); let login1=LoginForm.getLoginForm(); login1.show(); let login2=LoginForm.getLoginForm(); login2.show();

【作用域链和闭包】闭包的一个错误使用
作用域链和闭包
文章图片

以上代码来源:添加链接描述
闭包性能问题:
函数执行需要内存,那么函数中定义的变量,会在函数执行结束后自动回收。凡是闭包结构被引出的数据,如果还有变量引用这些数据,则这些数据就不会被回收(如:当一个变量为一个dom节点获取或者宿主对象,它的一个属性(onclick…)引用一个内部函数,而内部函数又在引用外部对象。会造成互相引用,引起内存泄露。)因此,在使用闭包的时候,若不使用某些数据,一定要赋值null
var f=(function(){ var num=123; return function(){ return null; } })(); //f引用函数,函数引用变量 //因此,在不使用该数据时,最好写上f=null

    推荐阅读