ES6 总结(二)

摘要:
之前已经对 ES6有了一个详细的介绍,作为一个前端 user,想要打好基础就必须了解 ES6,
这边文章主要是关于 :let和 const、解构赋值、symbol的一些总结,看完这篇文章相信你会对这些知识有一个清晰的认识。

ES6 let与 const

ES6新增加了两个重要的 JavaScript 关键字:let 和 const。
let声明的变量只在 let 命令所在的代码块内有效。
const 声明一个只读的常量,一旦声明,常量的值就不能改变了。

1、let 命令

基本用法:

{
   let a = 0;
   a       //0
}
a          // 报错 referenceError: a is not defined

代码块内有效
let 是在代码块内有效,var 是在全局范围内有效:

{
    let a = 0;
    var b = 1;
}
a      // referenceError: a is not defined
b      // 1

不能重复声明
let 只能声明一次 var 可以声明多次:

let a = 1;
let a = 2;
var b = 3;
var b = 4;
a     // Identifier 'a' has already been declared
b     // 4

针对于 for 循环计数器,let 很适合

for  (var i = 0; i < 10; i++){
   setTimeout(function(){
     console.log(i);
  })
}
//输出十个10
for (let j = 0; j < 10; j++){
   setTimeout(function(){
      console.log(j)  
   })
}
//输出0123456789

变量 i 是用 var 声明的。在全局范围内有效,所以全局中只有一个变量 i,每次循环时,setTimeout 定时器里面的 i 指的就是全局变量 i,而循环里的十个 setTimeout 是在循环结束后才执行,所以此时的 i 都是10。

变量 j 是用 let 声明的,当前的 j只在本轮循环中有效,每次循环的 j其实就是一个新的变量,所以 setTimeoout 定时器里面的 j 其实是不同的变量,即输出0123456789(若每次循环的变量 j 都是重新声明的,如何知道前面的值?这是因为 Javascript 引擎内部会记住前一个循环的值)。

不存在变量提升
let 不存在变量提升,var 会变量提升:

console.log(a);  //referenceError:a is not defined
let a = 'apple';

console.log(b); //undefined
var b = 'banana';

变量 b 用 var 声明声明存在变量提升,所以当脚本开始运行的时候,已经存在了,但是还没有赋值,所以会输出 undefined。
变量 a用 let 声明不存在变量提升,在声明变量a 之前,a不存在,所以会报错。

2、const 命令

const声明一个只读变量,声明之后不允许改变。意味着,一旦声明必须初始化,否则会报错。
基本用法:

const PI = "3.1415926";
PI  //3.1415926

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

暂时性死区:

var PI = 'a'
if(true){
   console.log(PI);  //referenceError: PI is not defined
   const PI = "3.1415926";
}

ES6明确规定,代码块内如果存在 let或者 const,代码块会对这些命令声明的变量从块的开始就形成一个封闭作用域。代码块内,在声明变量 PI 之前使用它会报错。

注意要点
const 如何做到变量在声明初始化之后不允许改变的?其实 const 保证的不是变量的值不变,而是保证变量指向的内存地址所保存的数据不允许改动。此时,你可能已经想到,简单类型和复用类型保存值的方式是不同的。对于简单类型(数值number,字符串string,布尔值 boolean),值就保存在变量指向的那个内存地址,因此 const 声明的简单类型变量等同于常量。而复杂类型(对象 object,数组 array,函数function),变量指向的内存地址其实是保存了一个指向实际数值的指针,所以 const 只能保证指针是固定的,至于指针指向的数据结构变不变就无法控制了,所以使用 const 声明复杂类型对象时要慎重。

ES6解构赋值

解构赋值是对赋值运算符的扩展。
他是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。
在代码书写上简洁且易读,语义更加清晰明了;也方便了复杂对象中数据字段获取。

1、解构模型
在解构中,有下面两部分参与:
·解构的源,解构赋值表达式的右边部分。
·解构的目标,解构复制表达式的左边部分。

2、数组模型的解构

基本:

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

可嵌套:

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

可忽略:

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

不完全解构

let [ a = 1, b ] = []; //a = 1, b = undefined

剩余运算符

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

字符串等
在数组的解构中,解构的目标若为可遍历对象,皆可进行解构赋值。可遍历对象即实现 lterator接口的数据。

let [ a, b, c, d, e ] = 'hello';
// a = 'h'
// b = 'e'
// c = 'l'
// d = 'l'
// e = 'e'

解构默认值

let [ a = 2 ] = [ undefined ]; // a = 2

当解构模式有匹配结果,且匹配结果是 undefined,会触发默认值作为返回结果。

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

·a与 b匹配结果为 undefined,触发默认值: a = 3; b = a = 3
·a 正常解构赋值, 匹配结果: a = 1, b 匹配结果 undefined,触发默认值:b = a = 1
·a 与b 正常解析,匹配结果:a = 1, b = 2

3、对象模型的解构

基本:

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

let { baz: foo } = { baz : 'ddd' };
//foo = 'ddd'

可嵌套可忽略

let obj = { p: [ 'hello', {y: 'world'}] };
let { p: [x, { y }] } = obj;
//x = 'hello'
//y = 'world'

let obj = { p: ['hello', {y: 'world'}] };
let { p: [x, {}] } = obj;
//x = 'hello'

不完全解构

let obj = { p: [{y: 'world'}] };
let {p: [{ y }, x ] } = obj;
//x = undefined
//y = 'world'

剩余运算符

let { a, b, ...reset} = {a: 10, b: 20, c: 30, d: 40};
//a = 10
//b = 20
// reset = {c: 30, d: 40}

解构默认值

let {a = 10, b = 5} = { a: 3};
//a = 3; b = 5;
let { a: aa = 10, b: bb =5 } = { a: 3 };
// aa = 3; bb = 5;

ES6 Symbol

ES6引入了一种新的原始数据类型 Symbol,表示独一无二的值,最大的用法是用来定义对象的唯一属性名。
ES6数据类型除了 Number、String、Boolean、Object、null和 undefined,还新增了 Symbol。

基本用法
Symbol 函数栈不能用 new 命令,因为 Symbol 是原始数据类型,不是对象。可以接受一耳光字符串作为参数,为新创建的Symbol 提供描述,用来显示在控制台或者作为字符串的时候使用,便于区别。

let sy = Symbol("kk");
console.log(sy);   //Symbol(kk)
typeof(sy);   //"symbol"

//相同参数 Symbol()返回的值不相等
let sy1 = Symbol("kk");
sy === sy1;    //false

使用场景
作为属性名
用法
由于每一个 Symbol 的值都是不相等的,所以 Symbol 作为对象的属性名,可以保证属性不重名。

let sy = Symbol("key1");
//写法1
let syObject = {};
syObject[sy] = 'kk';
console.log(syObject);  //{Symbol(key): "kk"}
 //写法2
 let syObject = {
 [ sy ]: "kk"
 };
 console.log(syObject);   // {Symbol(key1): "kk"}
 
//写法3
let syObject = {};
Object.defineProperty(syObject, sy, {value: "kk"});
console.log(syObject);   //{Symbol(key1): "kk"}

Symbol 作为对象属性名时不能用".“运算符,要用方括号。因为”."运算符后面是字符串,所以取到的是字符串 sy 属性,而不是 Symbol 值sy属性。

let syObject = {};
syObject[ sy ] = "kk";

syObject[ sy ];  //"kk"
syObject.sy;  //undefined

注意点
Symbol 值作为属性名时,该属性是共有属性而不是私有属性,可以在类的外部访问。但是不会出现在 for…in、for…of的循环中,也不会被 Object.keys()、Object.getOwnPropertyNames()返回。如果要读取到一个对象的 Symbol 属性,可以通过 Object.getOwnPropertySymbols()和 Reflect.ownKeys()取到。

let syObject = {};
syObject[ sy ] = "kk";
console.log(syObject);

for(let i in syObject) {
  console.log(i);
}//无输出

Object.keys(syObject);   //[]
Object.getOwnPropertySymbols(syObject);   //[Symbol(key1)]
Reflect.ownKeys(syObject);   //[Symbol(key1)]

定义常量
在 ES5使用字符串表示常量。例如:

const COLOR_RED = 'red';
const COLOR_YELLOW = "yellow";

但是字符串不能保证常量是独特的,这会引起一些问题:

const COLOR_RED = "red";
const COLOR_YELLOW = "yellow";
const COLOR_BULE = "blue";
const MY_BULE = "bule";

function getConstantName(color) {
   switch (color) {
      case COLOR-RED : 
           return "COLOR_RED";
       case COLOR_YELLOW:
           return "COLOR_YELLOW";
       case COLOR_BLUE:
           return "COLOR_BLUE";
        case MY_BLUE:
            return "MY_BLUE";
         default:
            throw new Exception('Can't find this color');
   }
}

但是使用 Symbol 定义常量,这样就可以保证这一组常量的值都不想等。用 Symbol 来修改上面的例子。

const COLOR_RED = Symbol("red");
const COLOR_YELLOW = Symbol("yellow");
const COLOR_BULE = Symbol("blue");

function getConstantName(color) {
   switch (color) {
      case COLOR-RED : 
           return "COLOR_RED";
       case COLOR_YELLOW:
           return "COLOR_YELLOW";
       case COLOR_BLUE:
           return "COLOR_BLUE";
        case MY_BLUE:
            return "MY_BLUE";
         default:
            throw new Exception('Can't find this color');
   }
}

Symbol 的值是唯一的,所以不会出现相同值得常量,即可以保证 switch 按照代码预想的方式执行。

Symbol.for()

Symbol.for()类似单例模式,首先会在全局搜索被登记的Symbol 中是否有该字符串参数作为名称的 Symbol 值,如果有即返回该 Symbol 值,若没有则新建并返回一个以该字符串参数为名称的 Symbol 值,并登记在全局环境中供搜索。

let yellow = Symbol("yellow");
let yellow1 = Symbol.for("yellow");
yellow === yellow1;   //false

let yellow2 = Symbol.for("yellow");
yellow1 === yellow2;  //true

Symbol.keyFor()
Symbol.keyFor()返回一个已登记的 Symbol 类型值得 key,用来检测该字符串参数作为名称的 Symbol 值是否已被登记。

let yellow1 = Symbol.for("yellow");
Symbol.keyFor(yellow1); // 'yellow'

总结

这里对 let、const、解构赋值、Symbol 有了一个大致的总结,明白了这些知识的概念,当然 ES6的知识不会只有这么一点,接下来还会总结 ES6的其他知识扩充自己的武器库。加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值