javascript ES6 新特性之 let
let的作用是声明变量,和var差不多。
let是ES6提出的,在了解let之前,最好先熟悉var的原理。
JavaScript有一个机制叫“预解析”,也可以叫“提升(Hoisting)机制”。很多刚接触JavaScript的人都会被这个机制弄混。比如:
// var 的情况
console.log(a); // 输出undefined
var a = 2;
在预编译阶段,JavaScript引擎会将上面的a函数修改成下面的写法:
var a; //声明且初始化为undefined
console.log(a);
a=2;
我们把上面的 var 变成 let ;
// let 的情况
console.log(a); // 报错ReferenceError
let a = 2;
//相当于在第一行先声明bar但没有初始化,直到赋值时才初始化
由此我们得出:
变量提升现象:浏览器在运行代码之前会进行预解析,首先解析函数声明,定义变量,解析完之后再对函数、变量进行运行、赋值等。
-不论var声明的变量处于当前作用域的第几行,都会提升到作用域的头部。
-var 声明的变量会被提升到作用域的顶部并初始化为undefined,而let声明的变量在作用域的顶部未被初始化
在ES6中对块级作用域做了进一步强化,从而使变量在生命周期内能被更好的控制。
块级声明用于声明在指定块的作用域之外无法访问的变量。
“块级作用域”也可以称为“词法作用域”。
- 块级作用域存在于
- 函数内部
块中(字符 { 和 } 之间的区域)
比如 if 和 for 在ES6中也被定义成一个块级。
let声明的用法与var相同,用let代替var来声明变量,就可以把变量的作用域限制在当前代码块中。
而且let声明不会被提升(在预解析的过程中,不会把声明变量放在所有代码的之前),因此开发者通常会将let声明语句放在封闭代码块的顶部,以便整个代码块都可以访问。
var a = 123;
if (true) {
a = 456; // ReferenceError
let a;
}
console.log(a); //输出值为123,全局 a 与局部 a 不影响
上面这小段代码,先声明全局变量 a = 123; 按照我们以往的思维,如果if 判断语句中没有 let a;则最后会输出 456;但是if 判断语句作为块作用域,内部在未声明变量的时候直接给 a 赋值为 456;因此会报错。
由此可见,用let来声明变量比var更严紧。
let的另一个特性是禁止在同一个作用域下重复声明。
var a = 10;
let a = 20;
// 抛出语法错误
// Uncaught SyntaxError: Identifier 'a' has already been declared
// 很直接的告诉开发者变量a已经被定义过了。
不管之前用var还是let声明,只要后面再重复声明同一个变量,都会报错。
let a = 10;
var a = 20;
// 也会报错
上面是的报错是因为在同一个作用域下,用let重复声明。
熟悉JavaScript的开发者都知道,var是可以重复声明的,而后面声明的操作会覆盖前面的声明。
如果不在同一个作用域下,是可以用let来重复声明相同名的变量。
let a = 30;
if (true) {
let a = 40;
console.log(a);
// 输出40
}
console.log(a); // 输出30
同时 let 还有一个功能是防止变量泄露,
用var声明
for (var i=0; i<10; i++) {}
console.log(i);
// 输出 10
用let声明
for (let i=0; i<10; i++) {}
console.log(i);
// 抛出错误:Uncaught ReferenceError: i is not defined
最后我们总结出:let
- 在同一个作用域下,不可以被重复声明
- 可以重新赋值
- 可以防止变量泄露
接下来我们看一个 var 和 let 的实战练习:
我们先看一个正常的for循环,普通函数里面有一个for循环,for循环结束后最终返回结果数组
function foo(){
var arr = [];
for(var i=0;i<5;i++){
arr[i] = i;
}
return arr;
}
console.log(foo())
//输出结果为 [0,1,2,3,4]
有时我们需要在for循环里面添加一个匿名函数来实现更多功能,看下面代码
//循环里面包含闭包函数
function foo(){
var arr = [];
for(var i=0;i<5;i++){
arr[i] = function(){
return i;
}
}
return arr;
}
console.log(foo()); //执行5次匿名函数本身 --> [ [Function], [Function], [Function], [Function], [Function] ]
console.log(foo()[1]); //执行第2个匿名函数本身 --> [Function]
console.log(foo().length); //最终返回的是一个数组,数组的长度为5 --> 5
console.log(foo()[0]()); //数组中的第一个数返回的是5 --> 5
上面这段代码就形成了一个闭包:
闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包的常见的方式,就是在一个函数内部创建另一个函数,通过另一个函数访问这个函数的局部变量。
在for循环里面的匿名函数执行 return i 语句的时候,由于匿名函数里面没有i这个变量,所以这个i他要从父级函数中寻找i,而父级函数中的i在for循环中,当找到这个i的时候,是for循环完毕的i,也就是5,所以这个 foo 得到的是一个数组[5,5,5,5,5]。
那我们怎么才能输出 [1,2,3,4,5],在上述中我们说了在闭包内部函数调用 i 时没有找到转而向上层父级去找,那我们在调用内部函数时将值传给内部函数不就可以不需要去父级找了,在 JavaScript 函数中有有匿名函数的自我执行,即 在函数体外面加一对圆括号,形成一个表达式,在圆括号后面再加一个圆括号,里面可传入参数。
(function(){
console.log(123);
})();
//输出 123
var a = 123;
(function(b){
console.log(b);
})(a);
//输出 123
根据上面的执行结果我们可以将目标函数改造如下:
function foo(){
var arr = [];
for(var i=0;i<5;i++){
arr[i] = (function(num){
return num;
})(i);
}
return arr;
}
console.log(foo()); // [ 0, 1, 2, 3, 4 ]
console.log(foo()[1]); // 1
console.log(foo().length); // 5
console.log(foo()[0]); // 0
这样在每次调用 foo 的时候内部的匿名函数都会自我执行,并且将 i 传入匿名函数进行返回。
我们现在来看下面的代码:
function foo(){
var arr = [];
for(var i=0;i<5;i++){
arr[i] = function(){
return i;
}
}
return arr;
}
console.log(foo()[0]()); // 5
function foo(){
var arr = [];
for(let i=0;i<5;i++){
arr[i] = function(){
return i;
}
}
return arr;
}
console.log(foo()[0]()); // 0
在上面的代码中,我们分别用 var 和 let 来声明 i 的值,获得的结果却是不一样的,当为 var 时我们在上面的时候已经解释过了,但是为什么当 var 换为 let 之后会变呢,只是由于使用 let 声明块级变量,这样每次循环时就会在自己的作用域内找 i 的变量,而不是去全局找 i 的变量。
我们再来看一道面试时会经常问到的题目:
for(var i = 0; i < 5; i++){
setTimeout(function(){
console.log(i);
},1000);
} // 5,5,5,5,5
for(let i = 0; i < 5; i++){
setTimeout(function(){
console.log(i);
},1000);
} // 0,1,2,3,4
在setTimeout的时候,匿名函数function(){console.log(i);}会被声明创建,当匿名函数执行的时候,会查找当前运行环境的 i 的值。
var声明的 i ,运行环境的 i 的值为5,但是let声明的 i,运行环境中 i 的值是每一个循环创建匿名函数时候的 i。
所以得到了0-4的值。
let替换var,可以很好的解决闭包的问题。
javascript ES6 新特性之 let的更多相关文章
- javascript ES6 新特性之 扩展运算符 三个点 ...
对于 ES6 新特性中的 ... 可以简单的理解为下面一句话就可以了: 对象中的扩展运算符(...)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中. 作用类似于 Object.assign() ...
- JavaScript ES6 新特性详解
JavaScript ES6 带来了新的语法和新的强大功能,使您的代码更现代,更易读 const , let and var 的区别: const , let 是 ES6 中用于声明变量的新关键字. ...
- JavaScript ES6新特性介绍
介绍 ES6:ECMScript6 首先,一个常见的问题是,ECMAScript 和 JavaScript 到底是什么关系? ECMAScript是一个国际通过的标准化脚本语言: JavaScript ...
- javascript ES6 新特性之 Promise,ES7 async / await
es6 一经推出,Promise 就一直被大家所关注.那么,为什么 Promise 会被大家这样关注呢?答案很简单,Promise 优化了回调函数的用法,让原本需要纵向一层一层嵌套的回调函数实现了横向 ...
- javascript ES6 新特性之 class
在之前的文章中我们讲过原型,原型链和原型链继承的文章,在 ES6 中为我们提供了更为方便的 class,我们先来看一下下面的例子: function Person(name) { //构造函数里面的方 ...
- javascript ES6 新特性之 解构
解构的作用是可以快速取得数组或对象当中的元素或属性,而无需使用arr[x]或者obj[key]等传统方式进行赋值 var arr = [1, 2, 3]; //传统方式 var a = arr[0], ...
- ES6新特性概览
本文基于lukehoban/es6features ,同时参考了大量博客资料,具体见文末引用. ES6(ECMAScript 6)是即将到来的新版本JavaScript语言的标准,代号harmony( ...
- Atitit js版本es5 es6新特性
Atitit js版本es5 es6新特性 Es5( es5 其实就是adobe action script的标准化)1 es6新特性1 Es5( es5 其实就是adobe action scrip ...
- ES6新特性:Proxy代理器
ES6新特性:Proxy: 要使用的话, 直接在浏览器中执行即可, node和babel目前还没有Proxy的polyfill;,要使用的话,直接在浏览器中运行就好了, 浏览器的兼容性为:chrome ...
随机推荐
- 1、Linux文件结构介绍
文件目录介绍 bin 可执行的命令 boot 启动相关的程序:boot→grub→grub.conf timeout修改启动时间 dev 设备.硬件相关信息 etc 程序.系统配置文件 home 用户 ...
- UOJ#370. 【UR #17】滑稽树上滑稽果 动态规划
原文链接www.cnblogs.com/zhouzhendong/p/UOJ370.html 题解 首先易知答案肯定是一条链,因为挂在链的最下面肯定比挂在其他节点上赚. 问题被转化成了从一个集合中不断 ...
- 20165319 Exp6 信息收集与漏洞扫描
实验过程 whois 在虚拟机Kali的终端输入命令:whois gitee.com,查询码云的域名注册信息. dig或nslookup域名查询 在kali终端输入dig 网址或nslookup 网址 ...
- Bicoloring 二分图+染色
https://vjudge.net/contest/281085?tdsourcetag=s_pcqq_aiomsg#problem/B #include<stdio.h> #inclu ...
- datatable 笔记 服务器端查询
var vTable = ""; $("#vip_data").dataTable({ "scrollY": 400, //竖向高度 滚动 ...
- 我对PMO的理解(持续更新)
PMO的价值 为项目管理提供方法上的指导,对项目的实施过程提供监督.评价. PMO应该从哪方面着手建立管理体系 如何量化工作 如何考评工作 如何激励员工 如何进行人工.成本核算 如何进行进度跟踪与控制 ...
- django用户认证系统——拓展 User 模型
Django 用户认证系统提供了一个内置的 User 对象,用于记录用户的用户名,密码等个人信息.对于 Django 内置的 User 模型, 仅包含以下一些主要的属性: username,即用户名 ...
- HTML入门11
在网页中添加矢量图形, 使用矢量图形在很多情况下,效果较好,拥有较小的文件尺寸,高度缩放,下面具体讲解如何在网页中添加矢量图形 位图和矢量图 位图文件包含了每个像素的位置和色彩信息,流行的位图格式包括 ...
- python学习相关知识点
1.ndarray中,添加行或列:https://blog.csdn.net/lishuandao/article/details/52444288 2.numpy中ndarray数组拼接方法介绍:h ...
- 自然语言处理(四)统计机器翻译SMT
1.统计机器翻译三要素 1.翻译模型 2.语言模型 3.排序模型 2.翻译流程 1.双语数据预处理 2.词对齐 3.构造短语翻译表 4.对短语翻译表进行概率估计 5.解码,beam search 6. ...