ES6语法:let和const

1.let

(1)let用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效;var是全局变量,let是局部变量;

例如:

分别用let和var声明了两个变量;然后在代码块之外调用这两个变量,结果let声明的变量报错,var声明的变量返回了正确的值;这表明,let声明的变量只在它所在的代码块有效。

{
  let a = 10;
  var b = 1;
}
console.log(b); // 1
console.log(a); // 报错a没有定义:ReferenceError: a is not defined.

(2)for循环的计数器,就很合适使用let命令;

例如:

使用var,最后输出的是10:

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

使用var,最后输出的是6:

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

(3)不存在变量提升;

例如:

var可能会变量提升:

console.log(d) //undefined
var d = 2

let不会变量提升 必须先声明后使用:

console.log(e) //报错:Uncaught ReferenceError: e is not defined
let e = 3

(4)暂时性死区;

var命令会发生“变量提升”现象,即变量可以在声明之前使用,值为undefined。为了纠正这种现象,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
}

总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的;

(5)块级作用域;

let实际上为JavaScript新增了块级作用域,在{ }被包围的范围外,不受内层的let变量影响(但会受var的“变量提升”影响);

例如:

function text1(){
  let n = 5; //或var n = 5;
  if (true) {
    let n = 10;
  }
  console.log(n); // 5
}
 
function text2(){
  var n = 5;
  if (true) {
    var n = 10;
  }
  console.log(n); // 10
}
 
function text3(){
  let n = 5;
  if (true) {
    var n = 10; //报错,已经声明了n
  }
}

(6)不允许重复声明;

let不允许在相同作用域内,重复声明同一个变量,不能在函数内部相同模块范围重新声明参数;

例如:

let a = 10;// 即使声明是var a = 10;后面一样报错
let a = 1;// 报错
 
function func(arg) {
  let arg; // 调用时因同范围重名报错
}
 
function func(arg) {
  {
    let arg; // 不报错,因为对上一个arg来看在子模块中
  }
}

2.const命令

(1)const声明一个只读的常量;一旦声明,常量的值就不能改变;通常变量名全部大写;

例如:

const PI = 3.1415;
PI // 3.1415

PI = 3;
// TypeError: Assignment to constant variable.

上面代码表明改变常量的值会报错;

(2)一般用于全局变量;且声明时必须立即初始化,不能留到以后赋值;

例如:

const foo;
// SyntaxError: Missing initializer in const declaration

上面代码表示,对于const来说,只声明不赋值,就会报错;

(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;
}

上面代码在常量MAX声明之前就调用,结果报错;

(5)const声明的常量,也与let一样不可重复声明;

例如:

var message = "Hello!";
let age = 25;

// 以下两行都会报错
const message = "Goodbye!";
const age = 30;

3.变量的解构赋值:

ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring);

(1)数组的解构赋值;

a.“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值;

例如:

let [a, b, c] = [1, 2, 3];

b.使用嵌套数组进行解构:

例如:

let a = 1;
let b = 2;
let c = 3;
// 等价于
let [a, b, c] = [1, 2, 3];  // 这种写法属于“模式匹配”
 
let [ , third] = ["foo", "bar", "baz"];
third // "bar"
 
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
 
let [x, y, ...z] = ['a'];
x // "a"
y // 变量解构不成功,赋值为undefined
z // 数组解构不成功,赋值为[]

c.不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功;

例如:

let [x, y] = [1, 2, 3];
x // 1
y // 2

let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4

d.如果等号的右边不是数组(或者严格地说,不是可遍历的结构),将会报错;

例如:

// 报错
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};

e.Set 结构,也可以使用数组的解构赋值;

例如:

let [x, y, z] = new Set(['a', 'b', 'c']);
x // "a"

只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值;

(2)对象的解构赋值;

a.对象也可以解构;

例如:

let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"

b.对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值;

例如:

let { bar, foo } = { foo: 'aaa', bar: 'bbb' };
foo // "aaa"
bar // "bbb"

let { baz } = { foo: 'aaa', bar: 'bbb' };
baz // undefined

c.对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量;

例如:

// 例一
let { log, sin, cos } = Math;

// 例二
const { log } = console;
log('hello') // hello

d.如果变量名与属性名不一致,必须写成下面这样;

let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"

let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'

e.对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者;

例如:

let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
foo // error: foo is not defined

上面代码中,foo是匹配的模式,baz才是变量。真正被赋值的是变量baz,而不是模式foo;

f.与数组一样,解构也可以用于嵌套结构的对象;

例如:

let obj = {
  p: [
    'Hello',
    { y: 'World' }
  ]
};

let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"

注意,这时p是模式,不是变量,因此不会被赋值。如果p也要作为变量赋值,可以写成下面这样;

let obj = {
  p: [
    'Hello',
    { y: 'World' }
  ]
};

let { p, p: [x, { y }] } = obj;
x // "Hello"
y // "World"
p // ["Hello", {y: "World"}]

g.对象的解构也可以指定默认值;

var {x = 3} = {};
x // 3

var {x, y = 5} = {x: 1};
x // 1
y // 5

var {x: y = 3} = {};
y // 3

var {x: y = 3} = {x: 5};
y // 5

var { message: msg = 'Something went wrong' } = {};
msg // "Something went wrong"

(3)字符串的解构赋值;

a.字符串被转换成了一个类似数组的对象;

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

(4)数值和布尔值的解构赋值;

a.解构赋值时,如果等号右边是数值和布尔值,则会先转为对象;

例如:

let {toString: s} = 123;
s === Number.prototype.toString // true

let {toString: s} = true;
s === Boolean.prototype.toString // true

上面代码中,数值和布尔值的包装对象都有toString属性,因此变量s都能取到值;

(5)函数参数的解构赋值;

a.函数的参数也可以使用解构赋值;

例如:

function add([x, y]){
  return x + y;
}

add([1, 2]); // 3

注:本文用于整理知识点和笔记,参考内容来自作者阮一峰《ECMAScript 6 入门》附:https://es6.ruanyifeng.com/#docs/destructuring

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值