ES6-2 块级作用域与嵌套、let、暂行性死区

注意,写在开头

function test(x = 1) {var x  // 不报错console.log(x)
}
function test1(x = 1) {let x = 10 // 报错console.log(x)
}

let的变量名不可以和参数中的名称相同。而var并不限制,说白了就是希望你规范使用变量名。
形参原则上数组函数内部的临时变量,但是形参其实在内存中有独立的空间存储。

阮一峰ES6 - let

思考,在编写代码时,有es5、es6的语法,究竟是否有块级作用域?
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。

1. var关键字可以重复声明

var num1 = 1;
var num1 = 100;
console.log(num1) // 100

2. let块级作用域

2.1 同一作用域下不能重复声明(无论是let/var/const声明)

let num1 = 1;
var num1 = 100; // 报错 重复定义
var a = 10;
let a = 10; // 报错
function test(a){let a = 10; // 预编译时,形参a已定义,重复声明报错
}
let a = 1;
function a() { } // 报错
let a = 1;
{function a() { } // 不报错
}
// 函数提升是在当前(块级)作用域下提升
// 转译后
"use strict";var a = 1;
{var _a = function _a() {}; // 不报错}
function test(a) {{let a = 10;}console.log(a) // undefined
}
test()

2.2 let不会提升,会产生一个暂时性死区,在变量声明前访问会报错

var a = a;
console.log(a) // undefined
let x = x; // 报错
// 在变量x的声明语句还没有执行完成前,就去取x的值,导致报错”x 未定义“。
// 这里不要把赋值语句拆分为声明和赋值2步理解
  • 以下3种情况
var x = 1;
{// 此处=右的x取的是块级作用域内的// 暂时性死区let x = x;console.log(x) // 报错// Uncaught ReferenceError: Cannot access 'x' before initialization
}

// 转译ES5
"use strict";var x = 1;
{var _x = _x;console.log(_x); // undefined
}

这里注意: 因为es5不存在暂时死区。let x = x 的问题在于,右侧x是取值并赋值的操作,而这个时候在es6里,x并没有完成初始化,所以取值x的时候就会失败。
而var是不存在这种问题的。因为es6严格规定了初始化流程就是变量声明必须初始化且不允许取值。也就是说声明语句不可以有对该变量的引用。

转译并不能百分百还原。对应let转var这里就出现了以上的情况。
有些浏览器不支持块级作用域(大括号)。
转译结果和babel的版本也有关系,有可能转译后去除了大括号或转成IIFE或其他形式。

var x = 1;
{let x;x = x;console.log(x) // undefined
}

"use strict";var x = 1;
{var _x;_x = _x;console.log(_x); // undefined
}
// 这个本身就是ES5不需要转
var x = 1;
{x = x;console.log(x) // 1
}
let a ;
a = a
console.log(a) // undefined
if (true) {// TDZ开始tmp = 'abc'; // ReferenceErrorconsole.log(tmp); // ReferenceErrorlet tmp; // TDZ结束console.log(tmp); // undefinedtmp = 123;console.log(tmp); // 123
}
function bar(x = y, y = 2) {return [x, y];
}bar(); // 报错 
// 参数x默认值等于另一个参数y,而此时y还没有声明,属于“死区”。如果y的默认值是x,就不会报错,因为此时x已经声明了。

2.3 typeof不再是一个百分之百安全的操作

typeof x; // ReferenceError
let x;

注意

for (var i = 0; i < 10; i++) {arr[i] = function () {console.log(i)}
}
for (var i = 0; i < 10; i++) {arr[i]() // 打印0-9  
}
// 第二个for循环里,var i重新赋值了,恰好是i

在这里插入图片描述

var arr = [];
for (var i = 0; i < 10; i++) {arr[i] = function () {console.log(i)}
}
// 上个for循环var i是全局的,退出循环后为10
for (var index = 0; index < 10; index++) {arr[index]() // 10个10
}

==================================================

let是在块中声明的变量,每当声明一个function都会传入当前for的块中单独的i进去。也就是说let是块变量,在自己的块,或者子块中使用。而不是只在函数或全局作用域中使用。立即执行函数是为了将每次的i作为函数作用域中的局部变量传入与外界的i隔离。

在这里插入图片描述

// 用let声明,由于存在父子级作用域,相当于也形成了闭包
var arr = [];
for (let i = 0; i < 10; i++) {arr[i] = function () {console.log(i)}
}
// 即使index用let打印的也是0-9
for (var index = 0; index < 10; index++) {arr[index]() // 0-9
}
// 转译之后
"use strict";var arr = [];var _loop = function _loop(i) {arr[i] = function () {console.log(i);};
};for (var i = 0; i < 10; i++) {_loop(i); // 这里立即执行了
}for (var index = 0; index < 10; index++) {arr[index](); // 0-9
}

2.4 for循环作用域

  • for循环的特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域
for (var i = 0; i < 10; i++) {let i = 'a' console.log(i) // 10个a // 循环的index i是声明在全局的
}
console.log(i) // 10
for (let i = 0; i < 10; i++) {// for循环内的块级作用域// for花括号内的块级作用域并不相同let i = 'a'console.log(i) // 10个a
}
for (let i = 0; i < 10; i++) {var i = 'a' // 报错 // 因为for循环内,这里var声明的i会提升到全局// 而for循环条件又用let声明一次i,重复声明了console.log(i) 
}
if (1) {let a = 1;console.log(a) // 1{let a = 10;console.log(a) // 10}
}

以前遇到的有IIFE里不用关键字声明的吗

let a = 1;
(function(){a = 10; console.log(a) // 10
})()
console.log(a) // 10
let a = 1;
(function(){let a = 10;console.log(a) // 10
})()
console.log(a) // 1
var a;
(function () {a = 10;console.log(a) // 10
})();
(function () {a = 100;console.log(a) // 100
})();
console.log(a) // 100
(function () {var a = 10;console.log(a) // 10
})();
(function () {var a = 100;console.log(a) // 100
})();
console.log(a) // 报错 
// Uncaught ReferenceError: a is not defined

思考:在index.html文件的script标签里编码,既有es5的语法,又有es6的语法,在浏览器中打开时,浏览器会将所有代码转译成es6吗
不会转译,浏览器不同的版本对es的支持不一样。(现代浏览器基本都支持ES6)
现在普遍兼容es6的语法。但对特殊的语法需要babel转译, 包括对象的拓展,类的修饰等等,这些是需要babel转译的。

块级作用域等于匿名函数的立即调用吗?并不,块级作用域没有返回值。二者本质不同。

思考总结,在块级作用域{}内,用let/const声明的和父作用域同名的变量x,在转译ES6的时候,会被编译成另一变量_x

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/251041.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

常用的操作系统知识

为什么要有操作系统 现代计算机系统是由一个或者多个处理器&#xff0c;主存&#xff0c;磁盘&#xff0c;打印机&#xff0c;键盘&#xff0c;鼠标显示器&#xff0c;网络接口以及各种其他输入&#xff0c;输出设备组成的复杂系统&#xff0c;每位程序员不可能掌握所有系统实现…

vue --- 使用中央事件总线(bus)实现跨组件通信

使用Bus实现跨组件传输须注意以下3点: 1.需要创建一个空的Vue实例(bus),来作为中间站 2.使用bus.emit来发送事件3.使用bus.emit来发送事件 3.使用bus.emit来发送事件3.使用bus.on来监听事件(在钩子created中监听) 代码如下: <!DOCTYPE html> <html> <head>…

Execution Order of Event Functions, unity 3d 事件函数的执行顺序

vs_Community.exe --layout "F:\linson\vs2017 comm\offline" --lang zh-CN 学习unity3d&#xff0c;感觉事件顺序很重要。就翻译一下官方文档吧。 Execution Order of Event Functions 事件函数的执行顺序 In Unity scripting, there are a number of event functio…

ES6-3 let进阶、const、全部变量与顶层对象

一 const 1. 定义常量 1.1 引入模块时 const test require(http)1.2 定义时必须赋值(初始化)且不可修改 const a; // Uncaught SyntaxError: Missing initializer in const declaration若赋值为原始值&#xff0c;不可修改若赋值为引用值&#xff0c;对于的地址不可修改&a…

前后端如何通信

目录 前后端如何通信URL . URI . URN第一部分&#xff1a;传输协议第二部分&#xff1a;域名第三部分&#xff1a;端口号第四部分&#xff1a;请求资源文件的路径名称第五部分&#xff1a;问号传参第六部分&#xff1a;HASH值前后端如何通信 前段&#xff1a;客户端 后端&#…

vue --- 获取子组件数据的一个应急方案$refs

使用$refs需要注意以下2点: 1.html方法使用子组件时,需使用ref “xxx” 声明. 2.在父组件中使用,this.refs.xxx.msg 获取数据 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> </head> <body><div id"app"…

Mysql 根据出生日期计算年龄

最近因为业务要求需要根据出生日期计算年龄&#xff0c;在网上查了好多的方法&#xff0c;在这里总结一下。 网上的计算方法好多都提到了格里高利历法&#xff0c;特意去查了下资料&#xff0c;普及点知识。 格里高利历是公历的标准名称&#xff0c;是一种源自于西方社会的历法…

ES6-4/5 解构赋值、函数默认值、数组解构、对象解构

ES-4 解构赋值、函数默认值、数组解构、对象解构 ES-5 隐式转换、函数参数解构、解构本质、()用法 一 解构赋值 1 虚值 含义&#xff1a;在Boolean转换结果为假的值falsy 2 函数默认值 ES6 内部使用严格相等运算符&#xff08;&#xff09;&#xff0c;判断一个位置是否有值…

springboot之session、cookie

1- 获取session的方案 session: https://blog.csdn.net/yiifaa/article/details/77542208 2- session什么时候创建&#xff1f; 一个常见的误解是以为session在有客户端访问时就被创建&#xff0c;然而事实是直到某server端程序调用HttpServletRequest.getSession(true)这样…

echarts --- 多折线图按段显示颜色规则订制

描述: 图中有4个序列,序列1和序列2在同一个x轴下,显示不同的颜色.(如,在-40到-30,序列一是红色,而序列2是黑色) 关键: VisualMap中的seriesIndex属性(根据不同的系列,制定不同的颜色规则). 下面是代码,可以直接复制到 echart实例 中进行调试 var symbolSize 20; var data [[…

Git-分布式版本控制系统

一、版本控制 版本控制系统是记录若干文件内容变化&#xff0c;以便将来查阅修订特定版本或还原部分文件的系统 分为&#xff1a;集中式版本控制系统&#xff08;svn&#xff09;简称cvcs 都有一个单一集中管理服务器&#xff0c;保存所有文件修订版本&#xff0c;开发人员通…

ES6-6 - this指向、箭头函数基本形式、rest运算符

一 chrome断点调试 观察函数调用栈 // 25min var x 1; function foo(x, y function () { x 2; console.log(2) }) {var x 3;y();console.log(x) } foo() console.log(x) // 2 3 1var x 1; function foo(x, y function () { x 2; console.log(x) }) {x 3;y();console.…

【二分答案】Problem C:木材加工

Problem C:木材加工 Time Limit:1000MS Memory Limit:65536K Total Submit:48 Accepted:20 Description 【问题描述】 木材厂有一些原木&#xff0c;现在想把这些木头切割成一些长度相同的小段木头&#xff08;木头有可能有剩余&#xff09;&#xff0c;需要得到的小段的数目是…

vue --- vue.js实战基础篇课后练习

练习1:在输入框聚焦时,增加对键盘上下键按键的支持,相当于加1和减1 练习2:增加一个控制步伐的prop-step,比如设置为10,点击加号按钮,一次增加10 思路: // 考虑到子模板的复用性,即在父模板中复用如下: <input-number v-model"value" :max"10" :min&qu…

js打字效果

//文字依次出来效果 $.fn.autotype function() {var $text $(this);// console.log(this, this);var str $text.html(); //返回被选 元素的内容var index 0;var x $text.html();//$text.html()和$(this).html()有区别var timer setInterval(function() {//substr(index, …

ES6-7 - 箭头函数的实质、箭头函数的使用场景

箭头函数返回对象 // 这种情况要要用(),否则会将对象的{}解释为块 const fn (a, b) > ({a:1, b:2})箭头函数的特点 this指向由外层函数的作用域来决定&#xff0c;它本身没有this&#xff0c;不能通过call、apply、bind改变不能作为构造函数使用不可以使用arguments对象&…

mybatis比hibernate处理速度快的原因

mybatis:是面向结果集的。当要展示的页面需要几个字段时&#xff0c;springmvc会提供这几个字段并将其拼接成结果集&#xff0c;在转化为相应的对象。 hibernate&#xff1a;是面向对象的。要展示的页面需要某些字段时&#xff0c;会将所有字段都查出来&#xff0c;在转化为相应…

zabbix 从入门到精通

https://www.cnblogs.com/clsn/p/7885990.html 转载于:https://www.cnblogs.com/learningJAVA/p/8376589.html

javasript --- 一个日期规范(x秒前,x分前...)

Time函数(通俗易懂,自己根据实际需求修改吧- -) // time.js var Time {// 获取当前时间戳getUnix: function () {var date new Date();return date.getTime();},// 获取今天0点0分0秒的时间戳getTodayUnix: function () {var date new Date();date.setHours(0);date.setMin…

ES6-8 - 函数名/对象拓展、描述符、getter/setter

函数名 有两种特殊情况&#xff1a;bind方法创造的函数&#xff0c;name属性返回bound加上原函数的名字&#xff1b;Function构造函数创造的函数&#xff0c;name属性返回anonymous。 bind函数名 // 以bound开头 function foo() { } const fnName foo.bind().name console.lo…