作用域
简单来说,作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。
函数的作用域:函数内的区域,就是这个函数的作用域,变量和函数在这个区域都可以访问操作。最外层函数外的区域叫全局作用域,函数内的区域叫局部作用域。
注:在函数内部声明变量的时候,要使用var进行声明。如果不用的话,你实际上声明了一个全局变量!
变量的作用域:变量所在的区域,就是这个变量的作用域,变量在这个区域内可以被访问操作。在全局作用域上定义的变量叫全局变量,在函数内定义的变量叫局部变量。
[[scope]]:每个JavaScript函数都是一个对象,对象中的有些属性我们可以访问,但有些不可以,这些属性仅供JavaScript引擎存取,[[scope]]就是其中一个。
[[scope]]就是我们所说的作用域,其中存储了执行上下文的集合。
执行上下文:当函数执行时,会创建一个成为执行上下文的内部对象。一个执行上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,它所产生的执行上下文被销毁。
作用域链:[[scope]]中存储的执行上下文对象的集合呈链式连接,我们把这种链式连接叫做作用域链。
通俗地讲,当声明一个函数时,局部作用域一级一级向上包起来,就是作用域链。
1.当执行函数时,总是先从函数内部找寻局部变量
2.如果内部找不到(函数的局部作用域没有),则会向创建函数的作用域(声明函数的作用域)寻找,依次向上
例子:
function a() {
console.log(a) //undefined
function b() {
var b = 234;
console.log(a); //123
}
var a = 123;
console.log(a); //123
b();
}
var glob = 100;
a();
a函数被定义时,发生如下过程
a函数被执行时,发生如下过程
此时在a函数里面访问一个变量,系统会去a的scope里面找这个变量,它里面放的是个链,系统会先去作用域链的顶端去找,然后一次向下去找。(查找变量:从作用域链的顶端依次向下查找)
b函数被创建时,发生如下过程
当函数执行完后,它会把自己产生的执行上下文销毁,回归到自己定义的状态,等待下次被执行。
提到作用域就不得不提到闭包,简单来讲,闭包外部函数能够读取内部函数的变量。
优点:闭包可以形成独立的空间,永久的保存局部变量。
缺点:保存中间值的状态缺点是容易造成内存泄漏,因为闭包中的局部变量永远不会被回收。
简单例子:
function test(){
var arr =[];
for(var i = 0; i< 10; i++){
arr[i] = function (){
document.write(i+" ");
}
}
return arr;
}
var myArr = test();
for( var j = 0; j<10; j++){
myArr[j]();
}
结果:
闭包的作用:
1.实现公有变量
2.可以做缓存(存储结构)
3.可以实现封装,属性私有化
4.模块化开发,防止污染全局变量
1.例子:不依赖于外部变量并且能执行的函数累加器
function add() {
var num = 0;
function a() {
console.log("执行次数:" + ++num)
}
return a;
}
var myAdd =add();
myAdd();
myAdd();
myAdd();
2.缓存效果
function test() {
var food = "apple";
var obj = {
eatFood: function () {
if (food != "") {
console.log("I am eating" + food);
food = "";
} else {
console.log("There is nothing!");
}
},
pushFood: function (myFood) {
food = myFood;
}
}
return obj;
}
var person = test();
person.eatFood();
person.eatFood();
person.pushFood('banana');
person.eatFood();