es6浅学-let和const
来源:互联网 发布:方便面 数据报告 编辑:程序博客网 时间:2024/04/30 21:04
let
let基本总结:
- let指令只在块内有效
- 不存在变量提升(就是说使用只能在声明之后否则报错)
- 暂时性死区(let变量和外面的同变量没有任何的关系)
let temp=1;{ temp="abc"//报错 let temp=2;}
- 不允许重复声明(1.let不允许在相同作用域内,重复声明同一个变量。2.不能在函数内部重新声明参数。)
- do 表达式(返回块级作用域的最后一行的表达式的值)
let x = do { let t = f(); t * t + 1;};上面代码中,变量x会得到整个块级作用域的返回值(t * t + 1)
1.在let命令所在的代码块内有效
{ let a = 10; var b = 1;}a // ReferenceError: a is not defined.b // 1
for循环的计数器,就很合适使用let命令。
for (let i = 0; i < 10; i++) { // ...}console.log(i);// ReferenceError: i is not defined
下面的代码如果使用var,最后输出的是10。
var a = [];for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); };}a[6](); // 10
如果使用let,声明的变量仅在块级作用域内有效,最后输出的是 6。
var a = [];for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); };}a[6](); // 6
另外,for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。
for (let i = 0; i < 3; i++) { let i = 'abc'; console.log(i);}// abc// abc// abc
2.不存在变量提升
var命令会发生”变量提升“现象,即变量可以在声明之前使用,值为undefined。这种现象多多少少是有些奇怪的,按照一般的逻辑,变量应该在声明语句之后才可以使用。
为了纠正这种现象,let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。
// var 的情况console.log(foo); // 输出undefinedvar foo = 2;// let 的情况console.log(bar); // 报错ReferenceErrorlet bar = 2;
3.暂时性死区
只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。
var tmp = 123;if (true) { tmp = 'abc'; // ReferenceError let tmp;}
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ)。
if (true) { // TDZ开始 tmp = 'abc'; // ReferenceError console.log(tmp); // ReferenceError let tmp; // TDZ结束 console.log(tmp); // undefined tmp = 123; console.log(tmp); // 123}
typeof x; // ReferenceErrorlet x;
上面代码中,变量x使用let命令声明,所以在声明之前,都属于x的“死区”,只要用到该变量就会报错。因此,typeof运行时就会抛出一个ReferenceError。
作为比较,如果一个变量根本没有被声明,使用typeof反而不会报错。
typeof undeclared_variable // "undefined"
上面代码中,undeclared_variable是一个不存在的变量名,结果返回“undefined”。所以,在没有let之前,typeof运算符是百分之百安全的,永远不会报错。现在这一点不成立了。这样的设计是为了让大家养成良好的编程习惯,变量一定要在声明之后使用,否则就报错。
有些“死区”比较隐蔽,不太容易发现。
function bar(x = y, y = 2) { return [x, y];}bar(); // 报错
上面代码中,调用bar函数之所以报错(某些实现可能不报错),是因为参数x默认值等于另一个参数y,而此时y还没有声明,属于”死区“。如果y的默认值是x,就不会报错,因为此时x已经声明了。
function bar(x = 2, y = x) { return [x, y];}bar(); // [2, 2]
另外,下面的代码也会报错,与var的行为不同
// 不报错var x = x;// 报错let x = x;// ReferenceError: x is not defined
上面代码报错,也是因为暂时性死区。使用let声明变量时,只要变量在还没有声明完成前使用,就会报错。上面这行就属于这个情况,在变量x的声明语句还没有执行完成前,就去取x的值,导致报错”x 未定义“。
ES6 规定暂时性死区和let、const语句不出现变量提升,主要是为了减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为。这样的错误在 ES5 是很常见的,现在有了这种规定,避免此类错误就很容易了。
总之,暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
4.不允许重复声明
let不允许在相同作用域内,重复声明同一个变量。
// 报错function func() { let a = 10; var a = 1;}// 报错function func() { let a = 10; let a = 1;}
因此,不能在函数内部重新声明参数。
6.块级作用域
为什么需要块级作用域?
ES5 只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景。
var tmp = new Date();function f() { console.log(tmp); if (false) { var tmp = 'hello world'; }}f(); // undefined
第二种场景,用来计数的循环变量泄露为全局变量。
var s = ‘hello’;
for (var i = 0; i < s.length; i++) {
console.log(s[i]);
}
console.log(i); // 5
上面代码中,变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。
ES6 的块级作用域
let实际上为 JavaScript 新增了块级作用域。
function f1() { let n = 5; if (true) { let n = 10; } console.log(n); // 5}
上面的函数有两个代码块,都声明了变量n,运行后输出 5。这表示外层代码块不受内层代码块的影响。如果两次都使用var定义变量n,最后输出的值才是 10。
ES6 允许块级作用域的任意嵌套。
{{{{{let insane = 'Hello World'}}}}};
上面代码使用了一个五层的块级作用域。外层作用域无法读取内层作用域的变量。
上面代码使用了一个五层的块级作用域。外层作用域无法读取内层作用域的变量。
{{{{ {let insane = 'Hello World'} console.log(insane); // 报错}}}};
内层作用域可以定义外层作用域的同名变量。
{{{{ let insane = 'Hello World'; {let insane = 'Hello World'}}}}};
块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了。
// IIFE 写法
(function () {
var tmp = …;
…
}());
// 块级作用域写法
{
let tmp = …;
…
}
7.块级作用域与函数声明
函数能不能在块级作用域之中声明?这是一个相当令人混淆的问题。
ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。
// 情况一
if (true) {
function f() {}
}
// 情况二
try {
function f() {}
} catch(e) {
// …
}
上面两种函数声明,根据 ES5 的规定都是非法的。
但是,浏览器没有遵守这个规定,为了兼容以前的旧代码,还是支持在块级作用域之中声明函数,因此上面两种情况实际都能运行,不会报错。
ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。
function f() { console.log('I am outside!'); }(function () { if (false) { // 重复声明一次函数f function f() { console.log('I am inside!'); } } f();}());
const
1.const声明一个只读的常量。一旦声明,常量的值就不能改变。
const PI = 3.1415;PI // 3.1415PI = 3;// TypeError: Assignment to constant variable.
2.声明常量的时候必须赋值
const foo;// SyntaxError: Missing initializer in const declaration
3.const 和let同样是块级作用域
if (true) { const MAX = 5;}MAX // Uncaught ReferenceError: MAX is not defined
4.const同样存在暂时性死区,只能在声明的位置后面使
if (true) { console.log(MAX); // ReferenceError const MAX = 5;}
6.const和let一样在相同的作用域不能重复声明
var message = "Hello!";let age = 25;// 以下两行都会报错const message = "Goodbye!";const age = 30;
7.const的本质其实并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。
- 对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。
- 于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
const foo = {};// 为 foo 添加一个属性,可以成功foo.prop = 123;foo.prop // 123// 将 foo 指向另一个对象,就会报错foo = {}; // TypeError: "foo" is read-only
const a = [];a.push('Hello'); // 可执行a.length = 0; // 可执行a = ['Dave']; // 报错
ES6 声明变量的六种方法
1.let
2.const
3.class
4.import
- es6浅学-let和const
- 【ES6】let和const
- es6 let和const
- ES6-let和const
- es6 let和const
- 【ES6系列】let和const
- ES6学习-let和const
- ES6 中的 let 和 const
- es6中的const和let
- es6 let 和 const 命令
- ES6的let和const
- ES6 let和const命令
- 深入浅出ES6(十四):let和const
- ES6学习--let和const命令
- 《ES6入门》let和const总结
- ES6学习笔记之《let 和 const》
- ES6之一(let和const)
- ES6(一) let和const命令
- 微信支付的支付目录配置的坑
- 喝果汁、玩AR,AR圈里总有一种让人又爱又恨的走心体验
- 手把手教你怎么撩妹,五分钟读懂!提取于《谈话的力量》
- 2017.12.21
- JSP学习心得之一:JSP开发环境下载与配置
- es6浅学-let和const
- 数据结构课程设计——学生成绩管理系统
- Android 异步回调中操作UI线程,UI同步、卡死阻塞等性能问题
- mybatis中的动态sql
- 弘智教育-效果图10-建模最后一节课
- 【七月Python入门】 第五课面文件访问与函数式编程入门
- 打造浪漫的Android表白程序
- pandas—Dataframe操作(选取 插入 删除)
- 存储器层次结构1