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 ...
随机推荐
- 异步简析之BlockingCollection实现生产消费模式
目前市面上有诸多的产品实现队列功能,比如Redis.MemCache等... 其实c#中也有一个基础的集合类专门用来实现生产/消费模式 (生产模式还是建议使用Redis等产品) 下面是官方的一些资料和 ...
- unity Tab键实现切换输入框功能
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; ...
- 20165235 实现pwd功能
20165235 实现pwd功能 要求 学习pwd命令 2.研究pwd实现需要的系统调用(man -k; grep),写出伪代码 3.实现mypwd 测试mypwd 实现过程 pwd是将当前的文件目录 ...
- 音频相关基本概念,音频处理及编解码基本框架和原理以及音、重采样、3A等音频处理(了解概念为主)
视频笔记:音频专业级分析软件(Cooledit) 音质定义以语音带宽来区分,采样率越高,带宽越大,则保真度越高,音质越好.窄带(8khz采样),宽带(16khz采样),CD音质(44.1khz采样) ...
- tensorflow 使用 5 mnist 数据集, softmax 函数
用于分类 softmax 函数 手写数据识别:
- Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to ;XX.XX.XX.XX:6379] with root cause
java.net.ConnectException: Connection refused: no further information at sun.nio.ch.SocketChannelImp ...
- leetcode-求众数
题目:求众数 给定一个大小为 n 的数组,找到其中的众数.众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素. 你可以假设数组是非空的,并且给定的数组总是存在众数. 示例 1: 输入: [3,2,3 ...
- Vue(二十七)当前GitHub上排名前十的热门Vue项目(转载)
原文地址:https://my.oschina.net/liuyuantao/blog/1510726 1. ElemeFE/element tag:vue javascript components ...
- Linux 搭建Nginx+uWSGI+Django环境
安装环境 sudo apt-get install nginx sudo apt install python3 sudo apt install python3-pip 使用 sudo pip3 i ...
- oracle 创建的表为什么在table里没有,但是可以查出来
有两种的可能: 1这个表在其他用户下创建的,当前用户没有权限访问,此表不在属于当前用户 2查询时写的表名,并不是真正意义的表名,可能指向其他用户,或者就不是这个表