ES6学习一(变量声明和结构赋值)

1. 变量声明

es6总共有6种方式声明变量,分别是varfunctionletconstimportclassvarfunction命令与es5没有区别,今天主要记录 letconst命令(importclass命令还没仔细了解,之后再做补充)。


1.1 let命令

作用:声明一个变量,但所声明的变量旨在let命令所在的块级作用域内有效,没有变量提升。

// 只声明
let a
// 声明时赋值
let b = 1
// 声明后赋值
let c
c=2

console.log(a); // undefined
console.log(b); // 1
console.log(c); // 2

1.2 const命令

作用:声明一个常量,和let命令类似。

声明时赋值初始化

同let命令相比,常量一旦声明,它的值就不能变了,所以在声明时就要给这个常量赋值初始化。

// 只声明
const a // SyntaxError: Missing initializer in const declaration
console.log(a); // 不执行

对象、数组等引用类型的数据

因为这些数据的地址保存的是指向实际数据的指针,所以可以对这些数据的内容进行修改。
但是如果直接替换或重新赋值整个对象或数组,那么会改变它的实际地址,出现报错。

const aoo = {
    
    a: 1}

aoo.a = 2
aoo.b = 1

console.log(aoo); // { a: 2, b: 1 }


aoo = {
    
     c: 3 }

console.log(aoo); // 不执行

冻结对象

要让对象不能修改,可以使用Object.freze()

const aoo = Object.freze({
    
    a: 1}) // TypeError: Object.freze is not a function

aoo.a = 2 // 以下不执行
aoo.b = 1

console.log(aoo);

1.3 块级作用域

es6新增了块级作用域,只要有{}{}内就代表一个块级作用域,使用letconst声明的变量都是在当前块级作用域内使用。

无块级作用域导致内层变量泄露为全局变量

在es5中只有全局作用域和函数作用域(函数开辟的作用域),所以会出现内层变量泄露为全局变量(例:循环)

var s = 'hello';

for (var i = 0; i < s.length; i++) {
    
    
  console.log(s[i]);
}

console.log(i); // 5

因为没有块级作用域,只用作循环的内层变量i泄露为全局变量

扫描二维码关注公众号,回复: 15753402 查看本文章
let s = 'hello';

for (let i = 0; i < s.length; i++) {
    
    
  console.log(s[i]);
}

console.log(i); // ReferenceError: i is not defined

块级作用域限制用作循环的内层变量i只在所在作用域内,外层没有i这个变量

不能重复声明变量

再同一个块级作用域内,不能重复声明变量,否则报错

let a
let a = 1 // SyntaxError: Identifier 'a' has already been declared

1.4 无变量提升和暂时性死区

变量提升 在es5中或者是使用var命令时会出现变量可以在声明之前使用,只是值为undefined。

有变量提升导致内层变量覆盖外层变量

var tmp = new Date();

function f() {
    
    
  console.log(tmp);
  if (false) {
    
    
    var tmp = 'hello world';
  }
}

f(); // undefined

因为变量提升()里声明的tmp覆盖了外层tmp的值

let tmp = new Date();

function f() {
    
    
  console.log(tmp);
  if (false) {
    
    
    let tmp = 'hello world';
  }
}

f(); // 2021-08-18T18:20:32.471Z

没有变量提升,外层的tmp的值仍是获取到的时间

es6使用letconst命令则不允许变量提升,它们所声明的变量一定要在声明后使用(包括typeof),否则报错。

console.log(s); // ReferenceError: Cannot access 's' before initialization
let s = 'hello';

这个报错提示的就是暂时性死区。

暂时性死区

暂时性死区 是使用let和const命令时形成一个封闭的作用域,变量声明位置之前都是“死区”,限制变量只能在声明位置的后面使用。

注意typeof使用时,未声明的变量不会报错;已声明的变量在声明之前使用会报错

console.log(typeof a);  // undefined

console.log(typeof b);  // ReferenceError: Cannot access 'b' before initialization
let b = 'b'


2. 变量解构、赋值、设置别名

解构:es6允许按照一定的模式,从数组和对象中提取值,对变量进行赋值。

本质上这种写法属于模式匹配,只要两边的模式相同,左边的变量就会被赋予对应的值

let [a, b] = [1, 2]

console.log(a); // 1
console.log(b); // 2

不完全解构

但es6并未要求左右两边的模式完全一致,因此等号左边的模式只匹配一部分等号右边的模式,会出现不完全解构,即能匹配的部分解构赋值成功;不匹配的部分解构失败,变量的值就等于undefined

let [a, [b,c],d] = ['1', '2', '3']

console.log(a); // 1
console.log(b); // 2
console.log(c); // undefined
console.log(d); // 3

?当等号右边的数组的值是Number类型时,等号两边模式不同会报错

let [a, [b,c],d] = [1, 2, 3] // TypeError: undefined is not a function

console.log(a);  //以下不执行
console.log(b); 
console.log(c);
console.log(d);

2.1 不同类型数据的解构赋值

对象的解构赋值

对象是按照key值来对应解构的,key可以随意交换位置

let {
    
     b, a, c } = {
    
    a: 1,b:2}

console.log(a); // 1
console.log(b); // 2
console.log(c); // undefined

数组的解构赋值

数组是按照顺序一一对应来解构的,不能随意交换位置。可以想象数组的下标就是对象的key值,顺序不同则key就不同,因此不能随意交换位置。

// let [a, b] = [1, 2]
// console.log(a); // 1
// console.log(b); // 2

let [b, a] = [1, 2]
console.log(a); // 2
console.log(b); // 1

不过数组也可以作为特殊对象按照对象的方式进行解构

let {
    
     1: b, 0: a } = [1, 2]

console.log(a); // 1
console.log(b); // 2

字符串的解构赋值

字符串会被转化成一个类似数组的对象,以数组的方式进行解构;

let [a, [b, c], d, e, f] = 'hello'
console.log(a); // h
console.log(b); // e
console.log(c); // undefined
console.log(d); // l
console.log(e); // l
console.log(f); // o

同样也可以作为特殊对象,以对象的方式进行解构

let {
    
     0:a, 1:b, 2:c, 3:d, 4:e } = 'hello'
console.log(a); // h
console.log(b); // e
console.log(c); // l
console.log(d); // l
console.log(e); // o

数值和布尔值的解构赋值

数值和布尔值会被转化为它的包装对象,以对象的方式进行解构

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

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

undefined和null的解构赋值

解构赋值的规则是,只要右边不是数组或对象或类似数组对象的值,就先将其转化为对象。由于undefined和null无法转化为对象,所以它们解构赋值时会报错

// let { prop: x } = undefined; // TypeError: Cannot destructure property 'prop' of 'undefined' as it is undefined.
let {
    
     prop: y } = null; // TypeError: Cannot destructure property 'prop' of 'null' as it is null.

函数参数的解构赋值

函数参数可以根据不同的数据类型按照上面的规则进行解构赋值

[{
    
    name: 'a'},{
    
    name: 'b'},{
    
    name: 'c'}].map(({
     
     name}) => name)

2.2 默认值

有些时候,我们在解构时希望有一个默认值,在解构失败或确实等于undefined时使用这个默认值。
因为es6内部使用严格相等运算符(===)判断一个位置是否有值,所以只有严格等于解构失败的undefined时,默认值才会生效。

let {
    
     a='01', b='02', c='03' } = {
    
    a: 1, b: 2}

console.log(a); // 1
console.log(b); // 2
console.log(c); // 03

null值

根据规则,null值代表的的这个位置有值,值就为null,默认值不会生效。

let {
    
     a='01', b='02', c='03' } = {
    
    a: 1, b: 2, c: null}

console.log(a); // 1
console.log(b); // 2
console.log(c); // null

默认值引用解构其他的变量

默认值可以引用解构其他的变量,但改变量必须已经声明

let [x = 0, y = x] = []
console.log(x); // 0
console.log(y); // 0

x在y声明前已经声明并赋值为0,所以y可以使用x作为默认值

let [x = y, y = 0] = [] // ReferenceError: Cannot access 'y' before initialization
console.log(x); // 以下不执行
console.log(y);

x在y声明前使用y做默认值,因为没有变量提升,所以报错


2.3 别名

如果变量名和属性名不一样,那就需要把变量名设为属性名的别名

let {
    
     message: msg } = {
    
     message:'123' }
console.log(msg); // 123
console.log(message); // ReferenceError: message is not defined

其实平时写的 let {foo} = {foo:123}let {foo:foo} = {foo:123} 的简写

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


2.4 圆括号(没有用过,不是很了解,后续再补上)

将一个已声明的变量用于解构赋值

不能使用圆括号的情况

可以使用圆括号的情况

猜你喜欢

转载自blog.csdn.net/BAtodl/article/details/119792451
今日推荐