添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

作用域是指程序源代码中定义变量的区域。作用域规定了如何查找变量,也就是确定当前执行代码对变量的访问权限。

JavaScript 采用词法作用域(lexical scoping),也就是静态作用域。也就是说 函数的作用域在函数定义的时候确定的 。动态作用域相对于 this 来说的

全局作用域

函数外部声明的变量,作用域为全局的,所有函数均可访问

函数作用域

在js函数内部声明的变量,仅在函数内部起到局部作用

块级作用域

es6中新增的let以及const,let和const声明的对象作用域就是块级作用域,仅在声明对象所在的代码块中作用

在作用域中嵌套作用域,形成作用域链

不在当前作用域定义的变量

函数能访问自己作用域,不在自己所在作用域调用,就形成闭包

var a = 10
function foo(){
	console.log(a) // 函数作用域在定义是确定的,所以foo定义在全局,a指向全局的a
function bar(){
	var a = 1
	foo()
bar() // 10

以上foo调用其实就是一个闭包,不太明显,看下面

function foo(){
	var count = 0
    return function(){
    	console.log(count)
var b = foo()
b() // 0

b函数能够记住并访问foo函数变量count,这就是闭包,其实是作用域的一种特殊形式;

自执行函数IIFE

自执行函数表达式,其实是匿名函数自调用;优点是:封装变量;减少对全局变量污染;相当于一个独立的作用域;因为自己调用自己,它本身并不是闭包;但是它可以作为一闭包作用域,提供给定义在内部的函数消费

(function(){
	// todo...
    var  a = 100
    setTimeout(function(){
    	// 延迟函数形成闭包
        console.log(a)
    },0)

探讨for循环

for(var i = 0; i < 5; i++){
	setTimeout(function(){
    	console.log(i)

上面for循环会打印五个5;并不是预期中的0,1,2,3,4;为什么会这样?

仔细想一下;setTimeout是异步执行;当for循环结束后开始执行延迟函数回调;这个时候开始查找i;由于i其实是定义在全局作用域的共享变量;所以最终查找的是同一个i,也就是5;

所以我们需要一个独立的作用域,且每次迭代都要一个不重复的闭包作用域来存储不同的i;这样我们访问的i就是不同的;

使用自执行函数试一下

for(var i = 0; i < 5; i++){
	(function(j){
      setTimeout(function(){
          console.log(j)
    })(i)

此时使用自执行函数可以在每次迭代都生成一个新的作用域;相当于把每次迭代的i都存到j中;异步回调执行访问的j都是所在自调用函数作用域内部的j;所以实现对i的存储;

使用let

for(let i = 0; i < 5; i++){
    setTimeout(function(){
        console.log(i)

let也可是实现对i的存储;ES6中for循环的let有个特殊的行为;使用let声明的i,不会只声明一次,每次迭代都会声明,而且会自动记住上次迭代后的i值来重新初始化,每次i不重复;也就是每次迭代都会形成一个块级作用域来供延迟函数访问,这样块作用域与闭包完美结合;let简直为for循环量身定制的;终于可以愉快地写代码了

另外for括号中let声明的i与{}中不属于同一个块;也就是说{}作为子作用域,也可以声明i;父子作用域互不影响

for(let i = 0; i < 5; i++){
	let i = 10
    setTimeout(function(){
        console.log(i) // 都为10

同样的也可以在{}中直接存储i

for(var i = 0; i < 5; i++){
	let j = i // 闭包的块作用域
    setTimeout(function(){
        console.log(j)
    isfff
        An unknown developer
       
私信