理解ES6 (1) var, let, const 之间的区别 (2) 字符串和正则表达式

本文深入探讨了ES6带来的变化,包括block bindings的新机制、增强的Unicode支持、字符串及正则表达式的改进等,同时介绍了模板字符串的实用技巧。

英文电子书点此阅读《understanding es6》

目录

block bindings

原先的 var

var 声明的变量会被提升到函数的顶部,如果不在函数中的话,就等于提升到全局的顶部。等于把var a = 1拆分成2部分,var aa = 1,前者被提升。

let/const

es6中引进了let和const,需要注意的地方如下:

  1. block binding是指function或者{}。let 和 const 声明的变量不会提升,只在被声明之后才存在。在这之前变量处于时间死亡域中(tdz: temporal dead zone),甚至不能用貌似安全的操作符诸如typeof 来获取。
  2. let 和 const 在循环中与var不一样。for in 和 for of 都在每一次循环的iteration中生成了一个新的引用。因此,在循环体中生成的函数可以获取到当前迭代(interation)中的引用值,而不是循环之后的最终值。let在for循环中也是同理,但const不能用于for循环,因为改变了变量值。
  3. 用let或者const声明的变量,不能在该作用域下再次声明。let可以改变其值,const不能改变。const了就是常量了!
  4. 块级绑定的最佳实践是默认使用const,只在确定变量值需要改变的时候使用let。

const prevents modification of the binding, not modification of the bound value

已经看到有人翻译了这一章,戳这里阅读

Strings and Regular Expressions

用codePointAt来更好地unicode 支持

对超出了第一个2^16个代码点的Utf-16字符(即BMP,多语言基本面之外的字符),是不能用单个16位code unit表示的。对这些扩展字符集,会用2个code unit来表示。因此,用codePointAt()而不是charCodeAt()来按code unit的位置获取unicode 的 code point 值(就是一个整数),会更加准确,得到预期的结果

function is32Bit(c) {
    return c.codePointAt(0) > 0xFFFF;
}

console.log(is32Bit("?"));         // true
// 这个值可能显示不出来,可以用console.log(String.fromCodePoint(134071))来看


console.log(is32Bit("a"));          // false

16bit字符的上限在十六进制中用ffff来代表,因此,任何code point值大于这一数值的都是用两个code unit来代表的,是32位。

String类的normalize方法
在国际化的应用中尤为有用。在比较两个字符串时,应先采用同样的方式(nfc, nfd, nfkc, nfkd)将其标准化后,再进行比较。默认的标准化形式是nfc。
let values = [str1, str2] //自己定义两个字符串用于比较
values.sort(function(first, second) {
    var firstNormalized = first.normalize("NFD"),
        secondNormalized = second.normalize("NFD");

    if (firstNormalized < secondNormalized) {
        return -1;
    } else if (firstNormalized === secondNormalized) {
        return 0;
    } else {
        return 1;
    }
});	
正则表达式中的 u 标志

正则表达式假定单个字符使用一个 16 位的码元来表示。在正则中加入u标志后,将以字符为基准而不是code单位(16位或32位)为基准来判断。u的含义是unicode。

只要是一个字符的string, 不管是16位还是32位(看Length,不管是1还是2),都可以用 /^.$/u.test(str)来校验。

var text = "𠮷";

console.log(text.length);           // 2
console.log(/^.$/.test(text));      // false
console.log(/^.$/u.test(text));     // true

也可以轻松地利用/u来获取字符串以字符为基准的长度:

function codePointLength(text) {
    var result = text.match(/[\s\S]/gu);
    return result ? result.length : 0;
}
// 这么做的速度较慢,尤其是应用于长字符串时。应当尽量减少这么做的可能,考虑用字符串迭代器(iterator)来代替

other string changes
  • 子字符串 return true/false

    1. includes()
    2. startsWith()
    3. endsWith()

    两个参数:搜索的字符串(不支持正则),和起始搜索下标(非必要,如果不传实质default为0)
    对 endsWith,是从字符串的长度减去第二个参数开始匹配

  • repeat() 方法

    'abc'.repeat(2)  //'abcabc'
    
    //应用在缩进级别中:
    
    var indent = ''.repeat(4),
    	indentLevel = 0;
    
    var newIndet = indent.repeat(++indentLevel);
    
    
other regular expression changes
  • y flag, which is short for sticky

    /y表示从正则表达式的 lastIndex 属性值的位置开始检索字符串中的匹配字符。

    对不加flag的正则表达式,pattern的lastIndex值无影响
    对有global flag的正则表达式,当pattern 的lastIndex 属性设置为某个值n时,正则表达式会从n开始全局匹配。
    对有y flag的正则表达式,其sticky属性会被设置为true,从lastIndex开始尝试匹配(但不是全局匹配)

    sticky flag会在正则表达式中保存最近一次匹配的后一位下标。如果没有任何匹配,lastIndex则会被设置为0.全局的’g’ flag 同理。

    y flag 和 u flag 都是新语法,可用try catch 包裹以防止报错。

复制正则表达式
var re1 = /ab/i,re2 = new RegExp(re1);

re1 === re2 //false

typeof re1 //"object"

es6 中,可以加入第二个参数flag符,用来覆盖掉原有的flags。注意是覆盖不是新增。

var re1 = /ab/i,
    // throws an error in ES5, okay in ES6
re2 = new RegExp(re1, "g");
flags 属性

re 的 flags 属性可以提取flag

var re = /ab/g;

console.log(re.source);     // "ab"
console.log(re.flags);      // "g"
模板字符串

这个是重头戏了,挑一些平时不太注意的细节讲讲吧。

多行文字中要注意新行之前的空格也被计入字符串的一部分,如果需要缩进的话,可以在字符串后用上trim()方法

  • tagged templates
let count = 10,
    price = 0.25,
    message = passthru`${count} items cost $${(count * price).toFixed(2)}.`;

function passthru(literals,...substitutions){
	console.log(arguments);  //Arguments(3) [Array(3), 10, "2.50"] 展开array(3)是["", " items cost $", ".", raw: Array(3)]
	
	console.log('substitutions',substitutions);  //substitutions (2) [10, "2.50"]
	
	return literals.join('***')  
}

// message 的 值为 "*** items cost $***."

注意:

  1. literals的length永远比substitutions的多一个
  2. substitutions不一定是string,也可能是number
  • String.raw()

内置的String.raw() tag 可以避免字符转义,另外literals数组中也有raw属性,literals.raw是原字符串数组(未被转义)

let message1 = `Multiline\nstring`,
    message2 = String.raw`Multiline\nstring`;

console.log(message1);          // "Multiline
                                //  string"
console.log(message2);          // "Multiline\\nstring"

function raw(literals, ...substitutions) {
    let result = "";

    // run the loop only for the substitution count
    for (let i = 0; i < substitutions.length; i++) {
        result += literals.raw[i];      // use raw values instead
        result += substitutions[i];
    }

    // add the last literal
    result += literals.raw[literals.length - 1];

    return result;
}

let message = raw`Multiline\nstring`;

console.log(message);           // "Multiline\\nstring"
console.log(message.length);    // 17

summary

完备的unicode 支持让jaascript可以从逻辑上处理utf-16字符。code point 和 字符(character)之间可以通过 codePointAt() 和 String.fromCodePoint() 转换。新增的u字符让基于code points而不是基于16位字符处理成为可能。normalize()方法可以更适当地比较字符串。

includes, startsWith, endsWith 方法可以直接用true/false 来判断是否包含子字符串。

模板字符串可以方便地创建dsls(领域专用语言,domain-specific languages)。它支持变量代入和多行。template tags 尤其适用于创建dsls。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值