一.作用域再分类:局部作用域,全局作用域,作用域链,js回收机制,闭包,变量提升
(一)局部作用域:函数作用域,块作用域
1.函数作用域:
(1)在函数内部声明的变量只能在函数内部被访问
(2)函数参数也是函数内部的局部变量
(3)函数执行完毕,函数内部变量实际被清空了
2.块作用域:
(1)js中使用 { } 包裹的称为代码块,块内声明的变量外部可能无法被访问
(2)let,const(声明的是常量)声明的变量产生块作用域,var不会产生块作用域
(3)不同代码块之间变量无法互相访问
(二)全局作用域:
在<script>标签和js文件最外层就是全局作用域,在此声明的变量在函数内部也可以被访问
(三)作用域链(底层的变量查找机制):
(1)函数执行,优先在当前函数作用域中查找变量
(2)当前作用域查找不到则会依次逐级查找父级作用域直到全局作用域
(四)js回收机制:
(1)内存生命周期:内存分配--->内存使用--->内存回收
(2)说明:全局变量不会回收,局部变量不用了就会回收
(3)内存泄漏:分配的内存由于某种原因程序未释放或无法释放
(五)闭包:
(1)闭包=内层函数+外层函数的变量
闭包基本格式:
function outer() {
const a = 1
function f() {
console.log(a)
}
return fn
}
//outer() === fn === function fn() { }
//consts fun = function fn() { }
const fun = uter()
fun() //调用函数,这就实现了外层函数使用内部函数变量
例如:内层函数f()引用了外层函数outer的变量a,这就形成了闭包。并且内层函数和外层函数都要调用才能显示出来,才能闭包。最终在控制台可以看见打印出10。
(2)闭包作用:封闭数据,提供操作,外部也可以访问函数内部变量
(3)闭包应用:实现数据私有
比如,做个统计函数调用次数,函数调用一次,就++
let i = 0
function fn() {
i++
console.log('函数被调用了${i}次')
}
//控制台每调用一次,次数就加1
//但是i作为全局变量很容易被修改,所以可以改为闭包形式
function count() {
let i = 0
function fn() {
i++
console.log(i)
}
return fn
}
const fun = count()
一直会用到fn,一直会用到外层函数变量,fn调用之后一直被作用,不会被销毁,所以称为内存泄漏。
(六)变量提升
(1)允许在变量声明之前即被访问(仅存在于var声明变量),把所有var声明的变量提升到当前作用域的前面,但是只提升声明,不提升赋值
console.log(num +'件') //因为不提升赋值,所以num是undefined,打印出来也就是undefined 件
var num=10
console.log(num)//这里打印出来就是10了
function fn() {
console.log(num)
var num = 10
}
fn()//此时打印出来是undefined