共计 2120 个字符,预计需要花费 6 分钟才能阅读完成。
作用域
简略来说,作用域是指程序中定义变量的区域,它决定了以后执行代码对变量的拜访权限
在 ES5 中,个别只有两种作用域类型:
全局作用域:全局作用域作为程序的最外层作用域,始终存在
函数作用域:函数作用域只有在函数被定义时才会被创立,蕴含在父级函数作用域或全局作用域中
说完概念,咱们来看上面这段代码:
var a = 100
function test(){
var b = a * 2
var a = 200
var c = a/2
console.log(b)
console.log(c)
}
test() // 这里会打印出什么?
解析:
1. 首先这段代码造成了全局作用域与函数作用域
2. 全局作用域有一个变量 a 赋值为 100
3. 在 test 函数作用域中定义了局部变量 b,a,c
4. 这里又存在变量晋升,在函数作用域内先进行变量晋升 var b; var a; var c;
5. 再对 b 进行赋值,这时候 a 还没有被赋值,所以 a 的值为 undefined,再将 a *2,所以 b 为 NaN
6. 再给 a 赋值为 200,c 赋值为 a / 2 等于 100
所以最终会打印出 NaN,100
在 ES6 中,新增了一种块级作用域
简略来说,花括号 {…} 内的区域就是块级作用域,但 Javascript 并不是原生反对块级作用域的,须要借助 ES6 提出的 let、const 来创立块级作用域
// ES5
if(true) {
var name = ‘ 南玖 ’
}
console.log(name) // 南玖
// ES6
if(true) {
let age = 18
}
console.log(age) // 这里会报错
作用域链
当可执行代码外部拜访变量时,会先查找以后作用域下有无该变量,有则立刻返回,没有的话则会去父级作用域中查找 … 始终找到全局作用域。咱们把这种作用域的嵌套机制称为作用域链
词法作用域
词法作用域是作用域的一种工作模型,词法作用域是 JavaScript 中应用的一种作用域类型,词法作用域也能够被叫做动态作用域。
所谓的词法作用域就是在你写代码时将变量和作用域写在哪里来决定的,也就是词法作用域是动态的作用域,在你写代码时就决定了。函数作用域取决于它申明的地位,与理论调用的地位无关
MDN 对闭包的定义:
一个函数和对其四周(词法环境)的援用捆绑在一起(或者说函数被援用突围),这样一个组合就是闭包(closure)
也就是说,闭包让你能够在一个内层函数中拜访到其外层函数的作用域。在 JavaScript 中,每当创立一个函数,闭包就会在函数创立的同时被创立进去。
咱们能够得出:
闭包 = 函数 + 外层作用域
咱们先来看段代码:
var name = ‘ 前端南玖 ’
function say() {
console.log(name)
}
say()
解析:say 函数能够拜访到外层作用域的变量 a,那么这样不就是造成了一个闭包吗?
在《Javascript 权威指南》书中有这样一句话:严格来讲,所以 JavaScript 函数都是闭包
但这只是实践上的闭包,与咱们平时应用的不太一样。下面这个例子只是一个简略的闭包。
ECMAScript 对闭包的定义:
从实践上来讲:所有函数都是闭包。因为它们在创立的时候就曾经下层上下文的数据保存起来了。
从实际上来讲:闭包应该满足两个条件:1. 在代码中援用了外层作用域的变量;2. 即便创立它的上下文曾经销毁,它依然存在;
咱们再看一段《JavaScript 权威指南》上的代码:
let scope = ‘global scope’
function checkscope(){
let scope = ‘local scope’
function f(){
return scope
}
return f
}
let s = checkscope()
s() // 这里返回什么?
很多同学可能感觉是 global scope, 但真的是这样吗,咱们一起来看下它的执行过程:
1. 首先执行全局代码,创立全局执行上下文,定义全局变量 scope 并赋值
2. 申明 checkscope 函数,并创立该函数的执行上下文,创立局部变量 scope 并赋值
3. 申明 f 函数,创立该函数的执行上下文
4. 执行 checkscope 函数,该函数又返回了一个 f 函数赋值给了变量 s
5. 执行 s 函数,相当于执行了 f 函数。这里返回的 scope 是 local scope。至于为什么是 local scope,咱们下面讲到了词法作用的根本规定:JavaScript 函数是应用定义它们的作用域来执行的。在定义 f 函数的作用域中,变量 scope 的值为 local scope
闭包的利用
闭包的利用,绝大多是都是在保护外部变量的场景下应用
闭包的缺点
因为闭包的存在可能会造成变量常驻内存,使用不当会造成内存透露
内存透露可能会导致应用程序卡顿或解体
高频闭包面试题
var arr = []
for(var i=0;i<3;i++){
arr[i] = function(){console.log(i)
}
}
arr[0]() // 3
arr[1]() // 3
arr[2]() // 3
// 这里在执行的时候 i 曾经变成了 3
// 应用闭包解决
var arr = []
for(var i=0;i<3;i++){
arr[i] = (function(i){return function(){console.log(i)
}
})(i)
}
arr[0]() // 0
arr[1]() // 1
arr[2]() // 2