一、闭包
1、定义:有权访问另一个函数作用域中的变量的函数
缺点:闭包比其他函数占用更多内存,不要过量使用
2、闭包有哪些
(1)通过作用域链在全局环境中查找变量x,f1就是闭包
var x=1
function f1(){
alert(x)
}
f1()
(2)嵌套在f1中的f2函数就是闭包
---即访问上层函数的作用域的内层函数就是闭包
function f1(){
var x=1
function f1(){
alert(x)
}
f2()
}
(3)f2在f1函数的作用域中声明,在全局作用域中被调用,f2就是闭包
---即指在函数声明时的作用域意外的地方被调用的函数
需要通过将该函数作为返回值或参数传递,叫闭包
function f1(){
var x=1
function f2(){
alert(x)
}
return f2
}
f1()()
function f1(){
var x=1
function f2(){
alert(x)
}
f3(f2)
}
function f3(n){
n()
}
f1()
3、闭包特性
(1)自闭特性---闭包内部声明的变量,外部无法访问,除非闭包主动向外界提供访问接口
(2)包裹特性---
[1]普通函数调用完毕,系统会自动注销函数,释放资源
[2]闭包结构,当外部函数被调用之后闭包结构依然被保存在系统中,从而实现包裹数据的目得
function f1(x){
var x=a
var y= function f2(){
return x
}
return y
}
var c=f1(1)
4、闭包应用
(1)闭包能够跟踪动态环境中数据的实时变化
function f1(){
var a=1
var b=function f2(){
return a
}
a++
return b
}
f1()()
(2)闭包不会因为外部环境的注销而消失
当f1执行完毕,并没有被销毁,因为闭包引用了变量a而继续存在
function f1(){
var a=1
b=function(){alert(a)}
c=function(){alert(++a)}
e=function(){alert(a)}
d=function(x){alert(a=x)}
b()//1
c()//2
e()//2
d(5)//5
}
f1()
5、闭包底层原理
作用域链:1、当某个函数被调用时,会创建一个执行环境和相应的作用域链,
同时初始化函数的活动对象
2、在作用域链中,该函数本身处于作用域链第一层,该函数的外部函
数作用域处于第二位,外部的外部处于第三位,以此类推,直到作
用域的终点为全局环境
3、作用域的查找由下向上,由低到高,逐级查找
function f1(a,b){
if(a<b){
return -1
}else{
return 1
}
}
var r=f1(2,3)
function f1(arg1){
return function(a,b){
var v1=a[arg1]
var v2=b[arg1]
if(v1<v2){
return -1
}else{
return 1
}
}
}
f2=f1("age")
f2({"age":23},{"age":34})
6、闭包重点
function f1(){
var a=[]
for(var i=0;i<3,i++){
a[i]=function(){return i}
}
return a
}
var b=f1()
alert(b)
二、js代码运行机制
1、js是描述性的语言,不需要编译成中间语言,由浏览器动态解析与执行
2、js是按<script>代码块分割,进行编译和执行
代码块之间互相独立,但是变量和方法共享
3、浏览器对每个代码块进行独立的扫描,在对全局的代码块进行'顺序'执行
在一个块中,函数可以在调用之后再进行定义
在两个块中,定义函数所在的块必须在函数所调用的块之前
4、预编译期与执行期
同名的声明式函数,后面会覆盖前面,只预编译声明式函数
预编译步骤:
1、读入第一行代码块
2、做语法词法分析,有错错误则报错并跳到第五步
3、对var变量和声明式函数进行预编译处理(变量提升)
4、执行代码
5、如由下一个代码块则读入,重复第二步
<script>
alert(a)//报错
alert('代码块一')
var b=1
</script>
<script>
alert("代码块二")
alert(b)//undefined
</script>