资讯专栏INFORMATION COLUMN

ES6学习之 -- let和const命令

marser / 956人阅读

摘要:命令用来声明变量,它的用法类似,但是命令声明的变量只在所在的代码块中有效。不允许重复声明不允许在同一作用域声明两个相同的变量。对于内部的数据结构的变化是无法控制的。

let命令
用来声明变量,它的用法类似var,但是let命令声明的变量只在所在的代码块中有效。

{
    var a = 1;
    let b = 2;
}

console.log(a); // 1
console.log(b); // b is not defined b未定义

这就说明let定义的变量只在对应的代码块中有效。
同样的下面是个for循环

for(let i = 0; i < 5; i++){
    // ...
}
console.log(i);// i is not defined i未定义

i只在循环体内有效。
阮一峰老师的文章中有一个例子我们看一下并且分析一下

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

老师给我们的分析是这样子的:

上面代码中,变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为 JavaScript 引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。
如果还不理解的话我们可以再看一个例子:
var a = [];
for (let i = 0; i < 10; i++) {
  let val = i;
  a[i] = function () {
    console.log(val);
  };
}
a[6](); // 6

这时候你就会理解原因了,就相当于for循环中的执行体,每次的执行都位于一个多带带的代码块中。这个val是我们显示定义的一个副本,当我们执行a[6]的时候,他会找到a[6]保存的函数的执行环境下去找这个val,数组a中的每个元素都位于一个多带带的代码块中互不影响。那么我们可以得出一个结论:js引擎会为我们for循环中每次循环的代码块保存一个副本。
Nicholas C. Zakas《深入理解ES6》中也有相关解释。
不存在变量提升

console.log(a);// undefined
console.log(b);// b is not defined
var a = 1;
let b = 2;

暂时性死区
只要块级作用域中存在let命令,那么let声明的变量就会绑定这个作用域不受外部影响。

var temp = "hello";
if(true){
    console.log(temp);// temp is not defined
    let temp;
}
原因就是let绑定了块级作用域并且let定义的变量不会提升,就是这个地盘跟我同名的都得死。
隐蔽的死区
function test(x = y, y = 2) {
    return [x, y];
}
test();// 报错

原因是:当执行test()的时候会先将y的值赋给x作为初始值,但此时y不存在,所以报错。

function test(x = 2, y = x) {
    return [x, y];
}
test();// [2, 2]

这样就没问题了。

总之,暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

不允许重复声明
let不允许在同一作用域声明两个相同的变量。

let a;
var a;//报错  a已经被声明了
function fun(params) {
    let params;
}
func();//报错  params已经被声明了
function test(params) {
    {//内部代码块
        let params;
    }
}
test();//正常执行  执行函数内部的代码块被其中的那个变量占用了而已

块级作用域
先看一下es5,es5只有全局作用域和函数作用域。

var name = "Jason";
function test() {
    console.log(name);
    if(false) {
        var name = "Nico";
    }
}
==>相当于
var name = "Jason";
function test() {
    var name;//变量提升
    console.log(name);
    if(false) {
        name = "Nico";
    }
}
所以执行test()会打印undefined

还有就是for循环的时候i的定义被提前

for(var i = 0; i < 3; i++) {
    console.log(i);
}
console.log(i);
依次打印0 1 2 3

原因是i定义被提前,如下:

var i;
for(i = 0; i < 3; i++) {
    console.log(i);
}
console.log(i);

es6出现了块级作用域

function test() {
    let n = 0;
    if(true) {
        let n = 1;
    }
    console.log(n);
}
test();// 0

外层的块级作用域不受内层的控制。

{
    {
        let a = 1;
    }
    console.log(a);//报错 a未被定义
}

外层作用域无法访问内层作用域定义的变量

{
    let a = 0;
    {
        let a = 1;
    }
}

内层作用域可以命名外层已经命名的变量。
值得提醒的是函数在块级作用域中的声明

function test() {
    console.log("outside");
}
(function() {
    if(false) {
        function test() {
            console.log("inside");
        }
    }
    console.log(test());
})();

ES5会打印inside字符串,ES6却会报test is not a function的错。
是不是很诧异,为什么ES6没有打印outside呢?

原因是:ES6中允许块级作用域中声明函数,但是函数声明会类似于var提升到全局作用域或者函数作用域头部,同时函数声明会提升到块级作用域头部,所以上面的代码就相当于
function test() {
    console.log("outside");
}
(function() {
    var test = undefined;
    if(false) {
        function test() {
            console.log("inside");
        }
    }
    console.log(test());
})();
所以才会报test is not a function的错误。

所以尽量避免块级作用域中声明函数,如果有必要的话可以使用函数表达式。

function test() {
    console.log("outside");
}
(function() {
    if(false) {
        let test = function() {
            console.log("inside");
        }
    }
    console.log(test());// outside
})();

const命令
用于定义常量,一旦定义必须立刻初始化不然报错,定义后无法改变值,改变也会报错。

const USER_NAME;//报错
const USER_ID = "410100";
USER_ID = 2;//报错

const的作用域与let命令相同:只在声明所在的块级作用域内有效
const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
const声明的常量,也与let一样不可重复声明。
const其实保证的是变量存储的内存地址不得改动,对于简单的数据类型(数值,布尔,字符串),值就存在内存地址指向的位置,就等同于常量。但是对于数组、对象保存的就是一个指针,只能保证这个指针不被改变。对于内部的数据结构的变化是无法控制的。

const ARR = [];
ARR.push(1);// 可以执行
ARR.length = 0;// 可以执行
ARR = [];//报错
const OBJ = {};
OBJ.name = "JASON";// 可以执行
OBJ = {};//报错

ES6 声明变量的六种方法:var function let const import class

顶层对象:浏览器中指window Node中指global
ES5的时候全局变量的赋值与顶层变量的赋值是同一件事。
ES6改变了这一点除了varfunction还保持原来的方式,新的声明变量的方法不再与顶层变量挂钩。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/90573.html

相关文章

  • es6习之letconst命令

    摘要:和命令命令是在它所在的代码块有效,它属于块级作用域,新增。只有全局作用域和函数作用域。 let和const命令 let命令是在它所在的代码块有效,它属于块级作用域,es6新增。es5只有全局作用域和函数作用域。let命令存在暂时性死区(TDZ),即在申明前使用就会报错,不存在变量提升 console.log(a); // 报错 let a = 111; ==let不允许在相同作用域中,...

    DrizzleX 评论0 收藏0
  • ES6习之 -- Set数据结构

    摘要:类似于数组,但是中不存在重复元素。可以接受一个数组或者其他具有接口的数据结构作为参数从上面的代码可以看出有去重的功能。去重还有另一个方法将数据结构的数据转换成数组。清除实例的指定成员。返回一个布尔值,表示某个值是否在实例之中。 Set Set类似于数组,但是Set中不存在重复元素。Set可以接受一个数组(或者其他具有itarable接口的数据结构)作为参数 const set = ne...

    wawor4827 评论0 收藏0
  • ES6习之 -- 解构(使数据访问更便捷)

    摘要:数组的解构赋值规定允许按照一定模式,从数组和对象中提取值对变量进行赋值,我们称之为解构。的规则是,只要有可能导致解构的歧义,就不得使用圆括号。 数组的解构赋值 ES6规定:允许按照一定模式,从数组和对象中提取值对变量进行赋值,我们称之为解构。以前赋值只能直接指定值 let a = 1; let b = 2; let c = 3; ES6允许以下这种做法 let [a, b, c] = ...

    mrcode 评论0 收藏0
  • NodeAPI习之Buffer

    摘要:与字符编码通过指定的编码进制,可以在与普通的字符串之间转换。中文中文通常用于实例数组的排序。有点像方法合并截断为的长度,缺少的部分会用补充,是一个返回,是一个支持的字符编码返回,创建并返回一个形式的迭代器,如果与具有完全相同的字节就返回 Buffer 可以在TCP流或者文件系统操作等场景中处理二进制数据流。 Buffer实例类似于整数数组,但是Buffer大小固定、且在V8堆外分配物理...

    Integ 评论0 收藏0
  • node 核心模块习之 Buffer

    摘要:核心模块学习之何为在引入之前,没有能读取和操作二进制数据流的机制,作为引入,以便能和网络流文件流等进行交互。返回值写入的实际大小,没有足够的空间保存,只会写入一部分。返回值实际存入的字节数。参考文章一进阶核心模块常用使用总结 node 核心模块学习之Buffer 何为 Buffer 在ES6引入 TypeArray 之前,JS没有能读取和操作二进制数据流的机制,Buffer 作为 No...

    soasme 评论0 收藏0

发表评论

0条评论

marser

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<