es6学习笔记2-—symbol、变量与作用域
1、新的字符串特性
标签模板:
-
String.raw(callSite, ...substitutions) : string
用于获取“原始”字符串内容的模板标签(反斜杠不再是转义字符):
> String.raw`\` === '\\' true
Unicode 和码点:
-
String.fromCodePoint(...codePoints : number[]) : string
将数字值转换成 Unicode 码点字,然后返回由码点构成的字符串。
-
String.prototype.codePointAt(pos) : number
返回在从位置
pos
处开始的码点的数字值(由一个或者两个 JavaScript 字符组成)。 -
String.prototype.normalize(form? : string) : string
不同的码点组合可能看起来是一样的。 Unicode 标准化 将它们修正为相同的标准值。这对相等比较和字符串搜索很有帮助。对于一般的文本,建议使用
NFC
形式。
查找字符串:
-
String.prototype.startsWith(searchString, position=0) : boolean
position
参数指定了字符串的开始搜索位置。 -
String.prototype.endsWith(searchString, endPosition=searchString.length) : boolean
endPosition
指定了字符串的结束搜索位置。 -
String.prototype.includes(searchString, position=0) : boolean
从字符串
position
位置开始搜索,是否包含searchString
子串。
重复字符串:
-
String.prototype.repeat(count) : string
返回重复指定次数的字符串。
padStart
用于头部补全,padEnd
用于尾部补全。
'x'.padStart(5, 'ab') // 'ababx' 'x'.padStart(4, 'ab') // 'abax' 'x'.padEnd(5, 'ab') // 'xabab' 'x'.padEnd(4, 'ab') // 'xaba' //********************** 'hello'.repeat(2) // "hellohello" 'na'.repeat(0) // "" //********************** var s = 'Hello world!'; s.startsWith('Hello') // true s.endsWith('!') // true s.includes('o') // true //********************** String.fromCodePoint(0x78, 0x1f680, 0x79) === 'x\uD83D\uDE80y' // true var s = "𠮷"; s.length // 2 s.charAt(0) // '' s.charAt(1) // '' s.charCodeAt(0) // 55362 s.charCodeAt(1) // 57271
2、symbol
ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型,前六种是:Undefined、Null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
Symbol值通过Symbol
函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的Symbol类型。凡是属性名属于Symbol类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
let s = Symbol(); typeof s // "symbol"
用途1:唯一属性键
Symbol 主要用作唯一属性键 - 一个 symbol 对象不会与任何其他属性键(另一个 symbol 对象或者字符串)冲突。例如,你可以将 Symbol.iterator
作为某个对象的键(键值是一个方法),使其变得可迭代(可以通过 for-of
或者其他语言机制来迭代,更多相关内容可以在有关迭代的章节找到):
const iterableObject = { [Symbol.iterator]() { // (A) const data = ['hello', 'world']; let index = 0; return { next() { if (index < data.length) { return { value: data[index++] }; } else { return { done: true }; } } }; } } for (const x of iterableObject) { console.log(x); } // Output: // hello // world
在行 A 处, symbol 对象用作键,键值是一个方法。这个唯一的键使得该对象可迭代,可用于 for-of
循环。
用途2:用常量代表特殊的含义
在 ECMAScript 5 中,你可能会使用字符串来表示一些特殊的含义,比如颜色。在 ES6 中,可以使用 symbol ,因为 symbol 总是唯一的:
const COLOR_RED = Symbol('Red'); const COLOR_ORANGE = Symbol('Orange'); const COLOR_YELLOW = Symbol('Yellow'); const COLOR_GREEN = Symbol('Green'); const COLOR_BLUE = Symbol('Blue'); const COLOR_VIOLET = Symbol('Violet'); function getComplement(color) { switch (color) { case COLOR_RED: return COLOR_GREEN; case COLOR_ORANGE: return COLOR_BLUE; case COLOR_YELLOW: return COLOR_VIOLET; case COLOR_GREEN: return COLOR_RED; case COLOR_BLUE: return COLOR_ORANGE; case COLOR_VIOLET: return COLOR_YELLOW; default: throw new Exception('Unknown color: '+color); } }
3 陷阱:不能将 symbol 强制转换成字符串
将 symbol 强制(隐式地)转换成字符串会抛出异常:
const sym = Symbol('desc'); const str1 = '' + sym; // TypeError const str2 = `${sym}`; // TypeError
只能通过显示的方式转换:
const str2 = String(sym); // 'Symbol(desc)' const str3 = sym.toString(); // 'Symbol(desc)'
禁止强制转换能够避免一些错误,但是也使得 symbol 的使用变得复杂起来。
4 哪些跟属性相关的操作能感知到 symbol 键?
下面的操作能感知到 symbol 键:
Reflect.ownKeys()
- 通过
[]
访问属性 Object.assign()
下面的操作会忽略掉 symbol 键:
Object.keys()
Object.getOwnPropertyNames()
for-in
循环
ES6 新增了两个定义变量的关键字:let
与 const
,它们几乎取代了 ES5 定义变量的方式:var
。
3 变量与作用域
1 let
let
语法上非常类似于 var
,但定义的变量是语句块级作用域,只存在于当前的语句块中,不存在变量提升。var
拥有函数作用域。
在如下的代码中,let
定义的变量 tmp
只存在于行 A 开始的语句块中:
function order(x, y) { if (x > y) { // (A) let tmp = x; x = y; y = tmp; } console.log(tmp === x); // ReferenceError: tmp is not defined return [x, y]; }
一些规则:
- 在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”。
- let不允许在相同作用域内,重复声明同一个变量。
2 const
const
和 let
类似,但是定义变量时必须初始化值,并且是只读的。
const foo; // SyntaxError: missing = in const declaration const bar = 123; bar = 456; // TypeError: `bar` is read-only
规则:
- const的作用域与let命令相同:只在声明所在的块级作用域内有效。
- const 声明一个只读的常量。一旦声明,常量的值就不能改变。一旦声明变量,就必须立即初始化,不能留到以后赋值。
- const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
- const命令只是保证变量名指向的地址不变,并不保证该地址的数据不变,所以将一个对象声明为常量必须非常小心。
3 定义变量的方式
下面的表格对比了在 ES6 中定义变量的 6 种方式:
Hoisting | Scope | Creates global properties | |||
---|---|---|---|---|---|
var | Declaration | Function | Yes | ||
let | Temporal | dead | zone | Block | No |
const | Temporal | dead | zone | Block | No |
function | Complete | Block | Yes | ||
class | No | Block | No | ||
import | Complete | Module-global | No |