不一般的块级作用域

块级作用域


1.什么是作用域

由于代码执行会形成代码执行的空间,这个执行空间指的就是我们的作用域。 表达式,函数执行的环境就会产生作用域,也就是变量,函数能作用到的范围,我在这个范围内,起作用,他就是我的作用域。 通过之前的学习,了解过作用域,作用域链。 由于代码执行,在一“块“内执行的代码,会产生作用域,也就是代表这段代码执行的空间在哪里。 作用域存在的目的就是存放当前环境下,当前作用域下面的变量,函数等等。在ES6之前我们仅仅存在着全局作用域,和函数作用域


全局作用域:window环境下执行的代码。

var a = 10 function person() {} // window 作用域 中存在 a变量 以及 person这个函数
函数作用域: 由于函数执行,会产生作用域,这块作用域内存放着当前函数内部执行的代码中的变量,函数。
function person() { var name = 'dxb' function getName() { console.log(name) } } person() //在这里由于函数person执行,产生一块作用域里面包括name, getName 但是当person函数定义的时候就不会存里面内容,尽管这个函数体是这样的。

接下来看一个例子

function getScope() { var content = 'content' return function () { console.log(content) } } var content = getScope()()

//在这里 getScope 执行会产生一个作用域,最后又返回了一个函数 

//当被返回的函数被执行的时候访问了一个叫 content 的变量。

// 但是被返回的函数在执行的时候并没有 content , 咋办?

// 它爸爸有啊,这里也就是父级作用域的 content拿过来输出一下。

// 又发现它父级作用域执行完了,并没有释放,对吧,这种现象也称之为闭包。 

所以作用域呈现链式,在函数执行的时候回反复的创建作用域,但是每次创建的作用域都会至于作用域链的顶端,为了方便访问当前作用域内的作用变脸以及函数,所以置于作用域链顶端。没找到,会依次向下去找,知道作用域链访问到头,浏览器环境下的window还没有找到想要的变量,那就报错喽, xxx is not defined

2.块级作用域绑定

在过去 javascript的变量声明机制大家都已经接触过了,有什么呢,变量声明提升,函数声明整体提升。而且有一些同学是从C语言学起的,对这样声明方式,用起来特别不舒服。ECMAScript6新的语法可以更好的控制作用域。块级作用域的出现使得一系列的问题被解决。

回顾var声明提升的机制,先看一段代码

if(false) { var name = 'wxb' } else { console.log("name 的值为" + name) } /* 结果是什么呢? name 的值为 undefined 没有报错, 没报错的前提是什么 a被定义 所以在这里的实质就是 */ var name if(false) { var name = 'wxb' } else { console.log("name 的值为" + name) } // 在预编译阶段 变量进行的提升 // 接着在看一个例子 var name = ‘dxb’ // ......(此处省略10000行代码) 经过反复的思考觉得姓王也不错呢,而且将来可以发展为隔壁老王 var name = 'wxb' // 就把姓改了 姓王了 console.log(name) 结果 name = 'wxb' // 看到结果 邓哥特别高兴 

从上面可以看出,通过var声明变量有诸多不严谨的地方。
1、存在作用域问题。

2、允许重复定义,污染同一作用域下的变量。 为了解决这个问题,引出块级作用域,使得作用域的变量可以更好的把控 

块级作用域

特点: 块级作用域声明的变量只会在当前作用域及其以下的作用域可以访问的到
存在于: {} 中,也被称为块中。


let 和 const 声明
let 声明变量的方式与 var 相同, 不同的是 通过 let 声明的变量具有识别块级作用域的能力, 同时不允许反复声明, 以及暂时性死区的特点
1. 具有识别块级作用域的能力

eg : { let a = 10 var b = 10 } console.log(a, b) // a is not defined // 10

2. 不允许反复声明

eg: // 确实,在同一个世界下每个人都是不一样的,而且目前没有基因一模一样的人 let p1 = '0x1234' // .... (此处省略10000行代码) 、、 let p1 = '0x1234' // 报错 p1 has already been declared 3.暂存性死区 如果在当前作用域下,一定要先定义后使用 TDZ(temporal dead zone)

javascript搜索引擎在扫描代码的时候发现变量声明

1. 如果var 声明的 放到当前作用域顶部,变量声明提升

2. 如果是let、const声明 会先放到TDZ中,当代码执行的时候,遇到这个变量就报错,如果遇到声明就把他从TDZ中拿出来。
eg: typeof msg let msg //
const 声明变量 也具有 let 声明变量的特点,被称为 常量
// 接着在看下一个例子 // 邓哥儿子为啥姓王啊,是有原因的 // 刚生下来确实姓邓,但是邓哥性格大家也都明白啊,稳久必浪,觉得现在政策宽松,随便改性 var name = ‘dxb’ // ......(此处省略10000行代码) 经过反复的思考觉得姓王也不错呢,而且将来可以发展为隔壁老王 name = 'wxb' // 就把姓改了 姓王了 console.log(name) 结果 name = 'wxb' // 看到结果 邓哥特别高兴 可惜好景不长,国家下来政策,名字不能随便乱改 // 听说国家改政策了, 毕竟还是邓哥自己的孩子(亲不亲生的就无从考证了,野史能写 1PB = 1024TB = 1024 * 1024GB 量级的) const name = 'wxb' // 现在的名是 wxb 想改回邓小宝 // .... (此处省略10000行代码) // 又托关系,又安排的,好不容易啊到了改名的地方 name = 'dxb' // 就想改个姓, 不行不让改了 // 看似一个笑话,其实真实程度高达百分90%。 对于const 声明的变量,我们成为常量 常量是不可以被改变的,但不是绝对的。 好比楼盘,同学们可能已经有房子的,或者正在找房子的。哈尔滨的房价20000。。。。 为什么说是和楼盘去比。 当开发商批下来一块地皮的时候, 只要技术够,钱够,你可以盖很多层,但是,地皮位置不能变,不能说群力地段比哈西好,就换到群力去,不可以。 所以说她是可变的,维度可变,不可变,位置不变,其实对应的就是我们的对象 const obj = {} //这个时候地址批下来了,就在这 obj.name = 'wxb' // 我在这块地皮内随便搞 obj = {} // 觉得地段不行,想换。不好意思,不可以。

// Assignment to constant variable

经过上面的学习,介绍的块级作用域,介绍了两个生命变量的方式 let const,以及他们的特点,具有识别块级作用域的能力,不可以在同一作用域内反复声明。 那么接下来,咱们通过几个小例子加深一下对于知识的理解与掌握

练习
eg: var a = {} console.log(window.a == a) //true let b = {} console.log(widow.b == b) // false console.log(window.b)

// undefined 说明 通过 var 声明的变量会在 window 的对象上定义一个变量 a 通过 let const 声明的变量不会在 window 的上定义对象

eg: for 循环中的 let 和 const 首先俩看一个简单的例子 for(let i=0; i<10; i ++) { let i }

// 会报错么 let i for (let i=0; i< 10; i++) { }

// 会报错么 回想我们当初学闭包时的例子

var arr = [] for(var i=0; i<10; i++) { arr[i] = function () { console.log(i) } } arr[6]() // 10 console.log(i)

// 10 通过立即执行函数来解决。

我们之前在 for 循环使用 let 发现 每次循环中的通过let声明的变量都可以执行不报错 所以我们说每次循环的块级作用域是不一样的 之前通过闭包来解决的问题,通过let也可以解决 var arr = [] for(let i=0; i< 100; i++) { arr[i] = function () { console.log(i) } } arr[6] = 6

可能有同学不明白,怎么就可以了呢。 每个let 定义的变量都不一样,都在自己所在的块级作用域内, 当函数执行的时候还要去拿i 所以每个作用域内的i不能被释放,当函数执行的时候也就还能访问。 那对于for in循环呢 同学们可以自己想一想。

最后给大家总结一下,块级作用域的最佳实践。随着 let 声明变量的方式逐渐被支持。这个let 更是大家想要的。对于需要被保护的变量通过 const 进行声明。声明的变量不会提升,仅仅在声明的代码块中使用,如此一来,javascript的声明变量的方式和其他语言更相似了,同时也大幅降低产生错误的几率,虽说性能没有之前好累,给我带来了巨大的便利性。

原文地址:https://www.cnblogs.com/pandawind/p/9798436.html