作用域链和闭包

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张图片
变量的访问规则
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();

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

var f=(function(){
	var num=123;
	return function(){
		return null;
		}
	})();
//f引用函数,函数引用变量
//因此,在不使用该数据时,最好写上f=null

你可能感兴趣的:(javascript)