ES6之 Symbol 和 let、const

我心飞翔 分类:javascript

ES6

ES的全称是 ECMAScript,它是由 ECMA 国际标准化组织,制定的一项脚本语言的标准化规范

ES6是在2016年发布的版本,但是,ES6实际上是一个泛指,泛指ES2015机器后续的版本

ES6 新增了很多语法:声明变量关键字、多种对象结构、箭头函数、扩展运算符等

1、数据类型 Symbol

img

1.1 初识 Symbol

在ES6之前,只有6种数据类型

NumberStringBoolean、Undefined、Null、Obje
 

ES6新增了一种原始的数据类型 —— Symbol(符号),表示独一无二、不可变的值,它的出现就是因为对象属性名都是字符串容易造成属性名冲突,为确保对象属性使用唯一的标识符,不会发生属性冲突的危险

Smybol实际上是一种唯一的标识符,可以作为对象的唯一属性名,这样就不会覆盖了

符号没有字面量语法,需要使用 Symbol函数初始化,而且用typeof操作符对符号返回 Symbol

let sym = Symbol()
console.log(sym); // Symbol()
console.log(typeof sym);  // symbol 
 

调用Symbol函数时,也可以传入一个字符串参数作为对符号的描述

var a1 = Symbol()
var a2 = Symbol()

var b1 = Symbol('foo')
var b2 = Symbol('foo')

console.log(a1 == b1);  // fakse
console.log(a2 == b2);  // fakse
 

注意:Smybol()函数前不能用new命令,否则会报错,这是因为生成的 Symbol是一个原始类型,不是对象,所以它也不能属性

1.2 特性

  1. 相同参数的Symbol函数返回的值是不相同的

调用Symbol函数时,也可以传入一个字符串参数作为对符号的描述

var a1 = Symbol()
var a2 = Symbol()

var b1 = Symbol('foo')
var b2 = Symbol('foo')

console.log(a1 == b1);  // fakse
console.log(a2 == b2);  // fakse
 
  1. 符号不能与其它类型的数据进行运算,但是 Symbol的值可以显示转换为字符串和布尔值
var sym = Symbol('zxc')
console.log(String(sym), typeof String(sym));  // Symbol(zxc) string
console.log(Boolean(sym));  // true
 
  1. Symbol的值作为对象的属性名,由于Symbol值的唯一性,因此不会覆盖属性名
var sym = Symbol();
// 第一种写法
var obj = {}
obj[sym] = '张三'
console.log(obj); // { Symbol(): '张三' }

// 第二种写法
var obj = {
    [sym]: '李四'
}
console.log(obj); // { Symbol(): '李四' }

// 第三种:defineProperty方法
var obj = {}
Object.defineProperty(obj, sym, { value: '王五' })
console.log(obj);  // {Symbol(): "王五"}
 
  1. Symbol值作为对象属性名时,不能用点运算符
var obj = {}
obj,sym = '张三'
console.log(obj);  // 报错
 

1.3 遍历属性名Symbol

Symbol作为对象属性名,不能使用 for...infor...of 循环取出,也不能使用Object.keys() 等方法

必须使用 Object.getOwnPropertySymbols() 方法获取对象的所有Symbol属性名,该方法会返回一个数组

var a = Symbol('a');
var b = Symbol('b');

var obj = {
    [a]: '张三',
    [b]: '李四'
}
var arrSym = Object.getOwnPropertySymbols(obj);
console.log(arrSym);  // [ Symbol(a), Symbol(b) ]
 

1.4 for函数 和 keyFor()函数

Symbol.for()

当我们需要使用相同的 Symbol值时,Symbol.for()就可以使用生成相同的值

var a1 = Symbol.for('a');
var a2 = Symbol.for('a');

console.log(a1 === a2); // true
 

它传入一个字符串参数,然后它会先搜索全局符号注册表是否存在以参数作为名称的Symbol的值,如果不存在,就会生成一个新符号实例并添加到注册表中;后续使用相同的字符串会检查注册表,发现存在该 Symbol,就直接返回该符号

Symbol.for()Symbol() 的区别是 前者会被登记在全局注册表中,而 Symbol不会

Symbol.keyFor() 会返回一个已经被登记的Symbol类型的值key

var a1 = Symbol.for('a');
var a2 = Symbol('a');

console.log(Symbol.keyFor(a1));  // a
console.log(Symbol.keyFor(a2));  // undefined
 

2、声明变量

img

ES6中新增了两种声明变量的关键字 let const,让js真正有了块级作用域

2.1 let

  1. 声明的变量只在作用域中有效(在大括号中)
if (true) {
	let a = '张三';
};
console.log(a);  // Uncaught ReferenceError: a is not defined
 

变量只在大括号中才可被访问

注意:只有使用 let声明的变量才具有块级作用域,使用 var 声明的变量不具备块级作用域

if (true) {
	var a = '张三';
};
console.log(a);  // 张三
 

所以,let可防止循环变量变成全局变量

// var
for (var i = 0; i < 2; i++) {};
// 在{}外面依然可以访问到i
console.log(i); // 2

// let
for (let i = 0; i < 2; i++) {};
// 在{}外面不可以访问到i
console.log(i); // i is not defined
 
  • 所以推荐使用 let ,特别对于for循环、if语句这类,可以防止变量变成全局变量
  1. let 无法提升变量
// 使用 var 声明变量,不会报错
console.log(a); // undefined
var a = 10;

// 报错
console.log(a); // Cannot access 'a' before initialization
var a = 10;
 
  1. let 不能重复声明
let a = 10
let a = 20
console.log(a);  // Identifier 'a' has already been declared
 

重复声明会提示:变量已经被声明了

注意:是不能重复声明,重复赋值是可以的

  1. let 具有暂时性死区
var a = 20;
if (true) {
    console.log(a);  // Cannot access 'a' before initialization
    let a = 10;
};
 
  • console.log(a); 和 let a = 10; 会跟块级作用域 {} 绑定在一起,所以 打印的a是指{} 中的变量a

2.2 const

作用:声明常量,常量的值(内存地址)是不变化的

  1. 同样具有块级作用域
if (true) {
    const a = 10;
    console.log(a);  // 10
};
console.log(a); // a is not defined
 
  1. 声明变量必须同时赋值
const PI;
PI = 3.14
console.log(PI); // Missing initializer in const declaration
 
  1. 声明赋值后的变量不能更改
// 简单数据类型
const PI = 3;
PI = 3.14
console.log(PI); // 报错

// 复杂数据类型
const arr = [1, 2];
// 没有改变arr的地址
arr[0] = '张三'
arr[1] = '李四'
console.log(arr); // [ '张三', '李四' ]

// arr的地址已经别改变
arr = [1, 2]
console.log(arr);  // 报错
 

varletconst 的区别

var let const
函数级作用域 块级作用域 块级作用域
变量可提升 不存在变量提升 不存在变量提升
值可以更改 值可以更改 值不可更改
可以重复声明 不可以重复声明 不可以重复声明

试一下水

题目一:

let arr = []
for (var i = 0; i < 2; i++) {
    arr[i] = function() {
        console.log(i);
    }
}

arr[0]();
arr[1]();
 

输出什么?

  1. 首先需要明确一点: i 是全局变量,所以遍历结束后 i = 2
  2. 循环结束后,全局数组存储了两个函数:[function(){console.log(i)};, function(){console.log(i)};]
  3. 最后调用数组中函数,结果均为2

未命名文件 (13).png

题目二:

var arr = [];
for (let i = 0; i < 2; i++) {
    arr[i] = function() {
        console.log(i);
    };
};

arr[0]();
arr[1]();
 

现在输出什么呢?

  1. 现在,i 变成了局部变量。所以函数中存储了对应的 i
  2. 结果自然是 01

未命名文件 (14).png


回复

我来回复
  • 暂无回复内容