函数在定义时,存在一个位置,这个位置叫当前函数的定义作用域;
函数在执行时,存在一个位置,这个位置叫当前函数的执行作用域。
function box(){
function fn(){
}
fn();// fn的执行作用域,是box的局部作用域
}
box();// box的定义作用域,是全局作用域
// box的执行作用域,是全局作用域
// fn(); 执行不了
执行作用域可以跨作用域,局部可以执行全局;函数是一种特殊的对象,意味着,函数类型属于引用数据类型。
function box(){
function fn(){
}
return fn;
}
var f = box();
f();
在box中返回了一个函数,返回值被f变量保存,因为函数也是对象,简单赋值属于浅拷贝,那么其实当前的f就是box中返回的那个函数的一个引用,如果将f作为函数执行了,相当于执行了box返回的那个函数的引用,其实就是执行了box里面的函数,当前变量f,其实就是box内部的fn,的执行作用域,就变成了全局。
函数的定义作用域,是固定的,写在哪就是哪。
函数的执行作用域,是可变的,在哪执行就是哪。
函数在执行时,可以拿到当前函数所在定义作用域中的所有数据。
function box(){
var a = 10;
function fn(){
a++;
console.log(a);
}
return fn;
}
var f = box();
f();// 11
f();// 12
闭包:利用函数的嵌套,实现将第一层函数中的局部变量,可以在第一层函数外部修改的过程,叫闭包。
闭包的形成环境:
- 函数的嵌套
- 内部函数使用外部函数中的变量
- 将内部函数返回,在外部函数的外部,接收返回值,执行(相当于执行了内部函数)
闭包的特点:
- 解决掉所有的全局变量,节省内存空间
- 可以在函数外部,修改函数内部的变量
- 相对于局部变量来说,浪费了内存
闭包的应用场景:
<body>
<div id="box"></div>
<ul class="list">
<li>link1</li>
<li>link2</li>
<li>link3</li>
<li>link4</li>
<li>link5</li>
</ul>
</body>
// 1.循环中的事件,事件处理函数中使用了循环的每次的计数器
var ali = document.querySelectorAll(".list li");
for(var i=0;i<ali.length;i++){
// (function(index){
// ali[index].onclick = function(){
// console.log(index);
// }
// })(i);
ali[i].onclick = (function(index){
return function(){
console.log(index);
}
})(i);
}
// 2.给某些系统默认的回调函数,传参
// (给计时器的回调函数,传参)
function fn(a){
return function(){
console.log(a);
};
}
setTimeout(fn("world"), 1000);
// 3.处理掉全局变量,只要开启新文件,新功能,最好上手就是一个匿名函数,简易闭包
var f = (function(){
var a = "hello";
function fn(){
console.log(a + "world");
}
return fn;
})();
f();
// 如果当前功能只是一个封装,不只是在当前使用,将来在其他位置也会使用,或者给别人使用