ES6笔记 2.块级作用域与嵌套、let、暂时性死区

本文详细介绍了JavaScript中的预解析过程,特别是let和块级作用域的引入,对比了var和let在变量声明、重复声明、作用域、提升、暂时性死区以及函数声明方面的差异,强调了KISS原则在设计中的重要性。
摘要由CSDN通过智能技术生成

预解析的基本回顾

  1. 全局作用域:

    全局作用域下的预解析步骤:GO 对象(函数执行前一刻产生)

  • 寻找变量声明
  • 寻找函数声明
  • 执行
  1. 函数作用域:

    函数作用域下的预解析步骤:AO 对象(函数执行前一刻产生)

  • 寻找变量声明与形式参数
  • 实际参数给形式参数赋值
  • 寻找函数声明
  • 函数执行

let 与块级作用域的产生

ES5 中存在 var 变量声明提升问题,随之带来重复声明变量覆盖问题,ES5 通常通过立即执行函数,产生独立的作用域解决这个问题;针对这种问题 ES6 中推出 let、块级作用域语法,并且遵循 kiss 原则(keep it simple,stupid)。

KISS 原则是指在设计当中应当注重简约的原则。总结工程专业人员在设计过程中的经验,大多数系统的设计应保持简洁和单纯,而不掺入非必要的复杂性,这样的系统运作成效会取得最优;因此简单性应该是设计中的关键目标,尽量回避免不必要的复杂性。同时这原则亦有应用在商业书信、设计电脑软件、动画、工程上。

let 语法产生了块级作用域,let 的本质上就是为了 js 增加一个块级作用域; let 所在的地方,就是块级作用域在的地方。( let 所在的块,会有块级作用域 , let 在全局,全局就是块 , let 在函数,函数就是块 , let 在 for 的不同位置,也会有不同的块 )块级作用域 if(){},for(var i = 0; i < 10; i++){},{}

let 不能在同一个作用域下重复声明

  • 在全局作用域或者函数作用域中,利用 var 声明变量,重复声明变量的话,后面声明的变量将覆盖之前声明的变量。
var a = 1;
var a = 2;
console.log(a); // 2

function fn() {
  var a = 1;
  var a = 2;
  console.log(a); // 2
}
fn();
  • 如果是用 let 进行变量声明的话,程序会抛出异常,SyntaxError: Identifier ‘a’ has already been declared
let a = 1;
let a = 2;
console.log(a); // SyntaxError: Identifier 'a' has already been declared

function fn() {
  let a = 1;
  let a = 2;
  console.log(a); // SyntaxError: Identifier 'a' has already been declared
}
fn();
  • 如果是 var 声明变量与 let 声明变量同时存在同一个作用域下,程序也会抛出异常 SyntaxError: Identifier ‘a’ has already been declared,var 首先声明变量 a,但是又通过 let 进行声明变量 a,而在同一个作用域下,let 是不允许重复声明同一个变量的
var a = 1;
let a = 2;
console.log(a); // SyntaxError: Identifier 'a' has already been declared

function fn() {
  var a = 1;
  let a = 2;
  console.log(a); // SyntaxError: Identifier 'a' has already been declared
}
  • 如果在函数内部,let 声明形式参数,此时程序也会抛出异常;因为形式参数 a 在函数 fn 内部相当于一个临时变量,在函数预解析的时候,已经定义过形式参数 a,当前 let 是不允许在同一个作用域下声明同一个变量
function fn(a) {
	let a = 2;
	console.log(a); // SyntaxError: Identifier 'a' has already been declared
}
fn();

--->

function fn(a) {
	var a = undefined;
	let a = 2;
	console.log(a); // SyntaxError: Identifier 'a' has already been declared
}
fn();
  • 如果不在同一个作用域下,就不会产生重复声明变量的问题
function test(a) {
  {
    let a = 10;
  }
  console.log(a); // undefined 因为作用域的问题,打印的是形式参数a的值
}
test();

function test(a) {
  {
    let a = 10;
    console.log(a); // 10 打印的是let声明变量a的值
  }
}
test();

let 不会声明提升,它会产生一个暂时性死区

// 块级作用域内
{
  // 暂时性死区 a
  console.log(a); // ReferenceError
  console.log(b); // undefined

  let a = 1; // 此时变量 a 没有提升
  console.log(a); // 脱离暂时性死区

  var b = 2; // 变量 b 提升
}
function test() {
  var foo = 33;
  if (foo) {
    let foo = foo + 55; // 预编译时在这一对花括号时声明变量 foo 在使用赋值时出现暂时性死区
  }
}
test();

在函数参数默认值赋值的时候,形式参数不存在变量提升的问题,相当于形式参数是 let 声明

对变量 y 来说,let x = y 代码的执行是在变量 y 的暂时性死区范围内部,所以你在变量 y 暂时性死区内部访问 y,所以抛出 ReferenceError 错误

function test(x = y, y = 2) {
	console.log(x, y); // ReferenceError: Cannot access 'y' before initialization
}
test();

--> 可看作以下代码
function test() {
	// TDZ start beginning of scope
	let x = y; // end of TDZ
	let y = 2; // end of TDZ
	console.log(x, y);
}

--> 修正为以下顺序

function test(y = 2, x = y) {
	console.log(x, y); // 2, 2
}

利用 typeof 尝试 let 暂时性死区的问题,抛出异常 ReferenceError: Cannot access ‘b’ before initialization

console.log(typeof a); // undefined

// 此时let声明的b变量,被let锁在当前行,并不能变量提升,而且被typeof运算符判断时会直接抛出异常
console.log(typeof b);
let b = 2; // ReferenceError: Cannot access 'b' before initialization

let 只能在当前的块级作用域下生效

// 示例中,let声明的变量a只存在于当前的块级作用域中,并不会像var声明的变量一样进行变量提升的现象,所以在块级作用域之外访问变量a是访问不到的。
{
  let a = 2;
}
console.log(a); // ReferenceError: a is not defined

function fn() {
  let a = 2;
}
console.log(a); // ReferenceError: a is not defined

if (1) {
  let a = 2;
}
console.log(a); // ReferenceError: a is not defined

程序运行不到的地方,不会出现错误

for (; 1; ) {
  let a = 1;
}
console.log(a); // 不执行,因为上述代码是死循环,程序执行不到这行代码。

for 语句与 let 形成块级作用域,实际上 for(let i = 0; i < 10; i++){}也是一个块级作用域,所以在全局作用下访问变量 i 访问不到

for (let i = 0; i < 10; i++) {}
console.log(i); // ReferenceError: i is not defined

for 循环,通过 var 声明的 i 变量可以看作是全局作用域下的一个变量,通过 for 循环向数组中存入匿名函数 function,但是此时全局作用域下的 i 成为 10,但是接下来的 for 循环又将变量 i 赋值为 0,导致每次匿名函数执行的时候,输出 0 - 9

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

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

在 for 循环中变量 i 是被 let 声明,所以每一次循环的时候,因为 let 的原因产生块级作用域,而匿名函数 function 此时作为一个闭包函数被存入数组中,存入的不仅仅是匿名函数,还存入当前匿名函数所处的环境(包含每次循环 i 的值),所以在第二次 for 循环时,执行匿名函数时,匿名函数都能够拿到当时的 i 值 0-9

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

for (var k = 0; k < 10; k++) {
  arr[k]();
}

判断 for 循环中,()和 {} 是否是同一个作用域,下面例子()与 {} 看似是在同一个作用域下

for (var i = 0; i < 10; i++) {
  i = "a";
  console.log(i); // 'a'
}

for (let i = 0; i < 10; i++) {
  i = "a";
  console.log(i); // 'a'
}

for (let i = 0; i < 10; i++) {
  var i = "a";
  console.log(i); // SyntaxError: Identifier 'i' has already been declared
}

由于 let 产生的块级作用域原因,导致 for 循环的()与 {} 不是同一个作用域

for (let i = 0; i < 10; i++) {
  let i = "a";
  console.log(i); // 10个a
}

以上类似于立即执行函数的块级作用域

for (let i = 0; i < 10; i++) {
  var i = "a";
  console.log(i); // SyntaxError: Identifier 'i' has already been declared
}

--> 可看作以下代码

while (1) {
  let i = 0;
  {
    var i = "a";
    console.log(i); // Uncaught SyntaxError: Identifier 'i' has already been declared
  }
  i++;
}

块级作用域中函数声明的方式

ES5 规定在函数只能够在顶层作用域和函数作用域中生成,不建议在块级作用域当中用函数声明的方式来声明函数,而用函数表达式

ES5:
function test(){} 合法
function test(){  合法
	function test1(){}
}

ES6:
{
	function fn(){} // 浏览器能够解析,但是不推荐
}

if(1) {
	function test(){} // 浏览器能够解析,但是不推荐
}

try {
	function fn(){}  // 浏览器能够解析,但是不推荐
}catch(e) {
	function test(){}
}

----> 如果需要在块级作用域中声明函数,利用函数表达式替换

try {
	var test1 = function(){}
}catch(e) {
	var test2 = function(){}
}

块级作用域返回值问题

块级作用域是没有返回值的,目前 do{}的语法可以让块级作用域有返回值,但是只是草案

函数的块级的作用域并不是命名函数的立即调用

一个是作用域,一个是函数立即执行,你能够通过块级作用域模拟函数立即执行,但完全不是等效的

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值