作用域
理解:
- 就是一块"地盘",,一个代码所在的区域
- 它是静态的(相对于上下文对象),在编写代码时就确定了
分类:
- 全局作用域
- 函数作用域
- ES5没有块作用域(ES6有了)
作用
- 隔离变量,不同作用域下同名变量不会有冲突
举例
if(true){
var c = 3;
}
console.log(c); //3
上面之所以可以打印出c的原因是因为ES5没有块作用域,但是如果在Java语言当中,c的值是取不到的。
如何判断作用域的个数
- 我们看到,上面代码中,我定义了两个function,分别有各自的作用域,加上全局作用域之后共有三个作用域。由此,我们得到:
- 作用域N = F(n) + 1; ------------函数的个数加一
作用域的作用
var a = 10;
function fn1() {
var b = 20;
function fn2() {
var c = 4;
console.log(a); //10
console.log(b); //20
console.log(c); //4
console.log(d); //d is not defined
}
}
- 我们发现 abc是可以正常打印的,而d是未定义。
- 提及作用域链的概念:作用域链就是由多个上下级关系的作用域组成的链
- 作用:
- 查找变量时是沿着作用域链查找的,并且遵循就近原则(就近原则:假如fn1中含有变量a,且值为100,则打印出a的值是100),查找过程的终止,是查找到了作用域链的顶层,即全局作用域。
作用域与执行上下文的区别
区别1
- 除全局作用域之外,每个函数都会创建自己的作用域,作用域在函数定义时就已经创建了,而不是在函数调用时。
- 全局执行上下文环境是在全局作用域确定之后,JS代码马上执行之前创建
- 函数执行上下文是在调用函数时,函数体代码执行前创建。
区别2
- 作用域是静态的,只要函数定义好了就一直存在,且不在变化。
- 执行上下文是动态的,调用函数时创建,函数掉用结束时上下文环境就会被释放。
联系
- 上下文环境(对象)属于所在的作用域
- 全局上下文环境===》全局作用域
- 函数上下文环境===》对应的函数作用域
闭包
- ES5的两大神兽之一哈,(网上解析很多,这里作为自己的笔记)下面深入了解下,什么是闭包。
- 看如下示例
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f;
}
var foo = checkscope();
foo();
- 将上面代码在谷歌中调试,return f 语句进行断点,查看参数。
- 由上图可知,形成了闭包对象,包含参数scope。
闭包的产生
1、当一个嵌套的内部(子)函数调用了嵌套的外部函数(父)的变量时,就会产生闭包。
2、闭包:嵌套的内部函数。包含被引入变量(函数)的对象,可以理解为对象
- 上图中的scope参数是全局变量,由此重新理解下闭包的定义:
在《JavaScript权威指南》中就讲到:从技术的角度讲,所有的JavaScript函数都是闭包。 - 示例2
function showDelay(msg, time) {
setTimeout(function () {
alert(msg);
},time);
}
showDelay('aaa',1000);
- 上面闭包对象只有一个变量msg,因为只有msg变量被引用。、
- 示例3
function fn1() {
var a = 2;
function fn2() {
a++;
console.log(a);
}
return fn2;
}
var f = fn1();
f(); //3
f(); //4
- 上面示例演示了将函数作为另一个函数的返回值,之所以可以打印出3,4,是因为a作为闭包函数对象的参数一直存在,并没有消失。(其根本原因是var f = fn1();被 f 引用着)
- 看到这里不由发出三个疑问:
- 函数执行完后,函数内部声明的局部变量是否还存在? 答:一般情况下不会存在,只有出现闭包对象时才可能存在。
- 那么示例3中怎样使闭包对象消失呢?答案是:f = null;
- 在函数外部能直接访问函数内部的局部变量嘛? 答:不能
闭包的作用
- 与作用域链相反,闭包是一种由外向内访问变量的技术。
闭包的生命周期
- 产生:在嵌套内部函数定义执行完成时就产生了(不是在调用时)
- 死亡:在嵌套的外部函数变成垃圾对象时消失
闭包的缺点
- 当被其他变量引用时,闭包不会消失,所以如果大量使用闭包时,可能会造成内存溢出或者内存泄漏。