深入理解javascript作用域系列第四篇——块作用域
前面的话
尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用其他类型的作用域单元甚至可以实现维护起来更加优秀、简洁的代码,比如块作用域。随着ES6的推广,块作用域也将用得越来越广泛。本文是深入理解javascript作用域系列第四篇——块作用域
let
for (var i= 0; i<10; i++) {
console.log(i);
}
上面这段是很熟悉的循环代码,通常是因为只想在for循环内部的上下文中使用变量i,但实际上i可以在全局作用域中访问,污染了整个作用域
for (var i= 0; i<10; i++) {
console.log(i);
}
console.log(i);//
ES6改变了现状,引入了新的let关键字,提供了除var以外的另一种变量声明方式。let关键字可以将变量绑定到所在的任意作用域中(通常是{...}内部),实现块作用域
{
let i = 1;
};
console.log(i);//ReferenceError: i is not defined
块级作用域实际上可以替代立即执行匿名函数(IIFE)
(function(){
var i = 1;
})();
console.log(i);//ReferenceError: i is not defined
如果将文章最开始那段for循环的代码中变量i用let声明,将会避免作用域污染问题
for (let i= 0; i<10; i++) {
console.log(i);
}
console.log(i);////ReferenceError: i is not defined
for循环头部的let不仅将i绑定到了for循环的块中,事实上它将其重新绑定到了循环的每一个迭代中,确保使用上一个循环迭代结束时的值重新进行赋值
//与上一段代码等价
{
let j;
for (j=0; j<10; j++) {
let i = j; //每个迭代重新绑定
console.log( i );
}
}
循环
下面代码中,由于闭包只能取得包含函数中的任何变量的最后一个值,所以控制台输出5,而不是0
var a = [];
for(var i = 0; i < 5; i++){
a[i] = function(){
return i;
}
}
console.log(a[0]());//
当然,可以通过函数传参,来保存每次循环的值
var a = [];
for(var i = 0; i < 5; i++){
a[i] = (function(j){
return function(){
return j;
}
})(i);
}
console.log(a[0]());//
而使用let则更方便,由于let循环有一个重新赋值的过程,相当于保存了每一次循环时的值
var a = [];
for(let i = 0; i < 5; i++){
a[i] = function(){
return i;
}
}
console.log(a[0]());//
重复声明
let不允许在相同作用域内,重复声明同一个变量
{
let a = 10;
var a = 1;//SyntaxError: Unexpected identifier
}
{
let a = 10;
let a = 1;//SyntaxError: Unexpected identifier
}
提升
使用let进行的声明不会在块作用域中进行提升
{
console.log(i);//ReferenceError: i is not defined
let i = 1;
};
const
除了let以外,ES6还引入了const,同样可以用来创建块作用域变量,但其值是固定的(常量)。之后任何试图修改值的操作都会引起错误
if (true) {
var a = 2;
const b = 3;
a = 3;
b = 4;// TypeError: Assignment to constant variable
}
console.log( a ); //
console.log( b ); // ReferenceError: b is not defined
const声明的常量,也与let一样不可重复声明
const message = "Goodbye!";
const message = "Goodbye!";//SyntaxError: Identifier 'message' has already been declared
try
try-catch语句的一个常见用途是创建块级作用域,其中声明的变量仅仅在catch内部有效
{
let a = 2;
console.log(a); //
}
console.log(a); //ReferenceError: a is not defined
在ES6之前的环境中,可以使用try-catch语句达到上面代码的类似效果
try{
throw 2;
}catch(a){
console.log( a ); //
}
console.log( a ); //ReferenceError: a is not defined
//或者
try{
throw undefined;
}catch(a){
a = 2;
console.log( a ); //
}
console.log( a ); //ReferenceError: a is not defined
深入理解javascript作用域系列第四篇——块作用域的更多相关文章
- 深入理解javascript函数系列第四篇——ES6函数扩展
× 目录 [1]参数默认值 [2]rest参数 [3]扩展运算符[4]箭头函数 前面的话 ES6标准关于函数扩展部分,主要涉及以下四个方面:参数默认值.rest参数.扩展运算符和箭头函数 参数默认值 ...
- 深入理解javascript作用域系列第四篇
前面的话 尽管函数作用域是最常见的作用域单元,也是现行大多数javascript最普遍的设计方法,但其他类型的作用域单元也是存在的,并且通过使用其他类型的作用域单元甚至可以实现维护起来更加优秀.简洁的 ...
- 深入理解javascript函数系列第三篇——属性和方法
× 目录 [1]属性 [2]方法 前面的话 函数是javascript中的特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本 ...
- 深入理解javascript函数系列第三篇
前面的话 函数是javascript中特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样.甚至可以用Function()构造函数来创建新的函数对象.本文是深入理解javascript函数 ...
- javascript面向对象系列第四篇——选项卡的实现
前面的话 面向对象的应用并非只是读几本书那么容易,需要有大量的工程实践做基础才能真正理解并学会使用它.本文将用面向对象的技术来制作一个简单的选项卡 图示说明 由图示结果看到,这是一个非常简单的选项卡. ...
- javascript面向对象系列第四篇——OOP中的常见概念
前面的话 面向对象描述了一种代码的组织结构形式——一种在软件中对真实世界中问题领域的建模方法.本文将从理论层面,介绍javascript面向对象程序程序(OOP)中一些常见的概念 对象 所谓对象,本质 ...
- 深入理解javascript对象系列第三篇——神秘的属性描述符
× 目录 [1]类型 [2]方法 [3]详述[4]状态 前面的话 对于操作系统中的文件,我们可以驾轻就熟将其设置为只读.隐藏.系统文件或普通文件.于对象来说,属性描述符提供类似的功能,用来描述对象的值 ...
- javascript运动系列第四篇——抖动
× 目录 [1]原理介绍 [2]代码实现 [3]实例应用 前面的话 在运动系列中,前面分别介绍了匀速运动.变速运动和曲线运动.下面介绍一种特殊的运动形式——抖动 原理介绍 抖动其实是往复运动的一种特殊 ...
- javascript动画系列第四篇——拖拽改变元素大小
× 目录 [1]原理简介 [2]范围圈定 [3]大小改变[4]代码优化 前面的话 拖拽可以让元素移动,也可以改变元素大小.本文将详细介绍拖拽改变元素大小的效果实现 原理简介 拖拽让元素移动,是改变定位 ...
随机推荐
- iOS进阶_FMDB的简单使用
先引入FMDB第三方,点击查看方法 一.创建表 1.创建sql语句 NSString *createSql = @"create table if not exists t_stude ...
- 河南省第四届ACM程序设计大赛
A: 序号互换 #include <cstdio> #include <cstdlib> #include <cstring> #include <algor ...
- IDEA 创建Maven Web项目(图文版)
前言:IDEA作为一款广泛使用的开发工具,无论是后台人员,还是前段工作者,都能在它上面发现它的魅力. IDEA提供了诸多项目模板,今天就以创建Maven Web项目作为示例,和大家一起分享: 第一步: ...
- java的 new 关键字
java的new关键字想必大家都知道这是实例化一个对象.没错,也是为新对象分配内存空间. 比如new MyDate(22,7,1964)这样一个案例,他的完成需要四部: 一.为新对象分配内存空间,将M ...
- UIView动画
UIView动画 一.commitAnimations方式使用UIView动画 1.commitAnimations方式使用UIView动画 [UIView beginAnimations:@&quo ...
- MySQL DELETE语句和TRUNCATE TABLE语句的区别
MySQL DELETE语句和TRUNCATE TABLE语句的区别 2010-10-08 16:05 佚名 互联网 字号:T | T 在MySQL数据库中,DELETE语句和TRUNCATE TAB ...
- springmvc和struts2的差别
springmvc和struts2的区别相关内容 1.spring mvc的入口是servlet,而struts2是filter filter功能:用户可以改变一个request和修改一个resp ...
- .NET Framework 基础知识总结
C#: 1. public:同一个程序集的任何代码或引用该程序集的其他程序集都可以访问该类型或成员 internal:同一个程序集的任何代码都可以访问该类型或成员 private :只有在结构或类中的 ...
- 解剖SQLSERVER 第五篇 OrcaMDF里读取Bits类型数据(译)
解剖SQLSERVER 第五篇 OrcaMDF里读取Bits类型数据(译) http://improve.dk/reading-bits-in-orcamdf/ Bits类型的存储跟SQLSERVE ...
- 《Linux内核设计与实现》读书笔记 - 目录 (完结)
读完这本书回过头才发现, 第一篇笔记居然是 2012年8月发的, 将近一年半的时间才看完这本书(汗!!!). 为了方便以后查看, 做个<Linux内核设计与实现>读书笔记 的目录: < ...