语法变化是最明显的,也是最容易理解的。ECMAScript 6 没有对 JavaScript 整体语法进行太多改动(仍是基于 C 的语言,包含分号和花括号),但确实清理了对开发人员具有细微影响的 “小” 东西。
ECMAScript 6 现在要符合 Unicode Standard 8.0 版或更高版本。意味着必须兼容 ECMAScript 的环境,因 8.0 拥有表情符号的字符代码。
大部分文本编辑器都尚未直接支持 Unicode 8.0 的所有字符代码,所以要将大部分 Unicode 字符作为转义字符,比如字符串字面量中的 \u{1d306}。因为还可以使 Unicode 作为标识符,所以 ECMAScript 6 也支持对变量名称使用 Unicode 转义语法。以下示例:
var \u{102C0} = { \u{102C0} : 2 };
return \u{102C0};
开发人员将 Unicode 用于国际化用途,这意味着它将出现在字符串字面量内,而不是用作变量标识符。考虑在其代码中使用英语以外的语言的开发人员可能仍会喜欢变量标识符中新增的灵活性
无处不在的整数字面量:9。由于 9 是一个字面量值,而且考虑到阿拉伯记数制(十进制)的主导性,9 被视为一个十进制字面量。但是,计算机不会以十进制形式思考;它们以二进制、八进制或十六进制形式进行思考。ECMAScript 很早就支持十六进制字面量(通过在字面量中添加 0x 作为前缀来表示)。在 ECMAScript 6 中,可以通过在字面量中分别添加 0b 或 0o 作为前缀来表达二进制和八进制字面量。因此,在 ECMAScript 6 中,下面的表达式中的所有字面量都会打印 true,因为它们都是相同的值:
var decimalLit = 15;
var hexadecimalLit = 0xF;
var octalLit = 0o17;
var binaryLit = 0b1111;
console.log(decimalLit == hexadecimalLit);
console.log(decimalLit == octalLit);
console.log(decimalLit == binaryLit);/span>
多年来,ECMAScript 开发人员使用了一些难看的字符串串联来将变量成员放入字符串中,比如:
var message = "The user " + user.firstName + " " + user.lastName +
" cannot be " + action + " because " + validationError;
尽管此策略不是 JavaScript 中最大的错误来源,但它容易出错,更别提难以读取了。在适用性方面,它使得 JavaScript 落后于支持字符串插值的语言。为了不继续落后,ECMAScript 6 引入了重音符字符串字面量(backtick string literal)。这个字面量使用重音符 (`) 表示支持字符串插值的字符串字面量。
var message = `The user ${user.firstName} ${user.lastName} cannot be
${action} because ${validationError}`;
在 be 和 ${action} 之间使用硬换行符,是因为重音符字符串也是 “多行字面量”。这意味着字符串中保留了空格,所以上面的消息将显示在两行上。它将在 “be” 后断开,然后在继续之前显示两个空格(因为代码缩进了两个空格)。
当然,不幸的是 ECMAScript 6 需要引入一种新的字符串字面量,而不是简单地支持在现有的单引号或双引号字符串中进行插入。但是,支持插值的向后兼容性意义非常大。这可能是最佳解决方案。随着时间的推移,我们可以预期大部分字符串字面量都将变成重音符字符串
ECMAScript 在过去允许程序员使用变量而不声明它们。但是,这么做会隐式地让它们成为全局变量,这被认为是一种不可取的行为。(除非它被称为 “单例模式”,进而被视为一种模式。)为了解决此问题,JavaScript 程序员开始使用 var 声明样式来在使用前声明变量。
不同于其他许多语言,ECMAScript 从来没有出现特定变量被重新声明多次的问题。因此,在守旧的 ECMAScript 中,您可以编写以下没有用的代码
var msg = "Howdy";
var msg = "Hello there"; // acceptable, just reassigns:
ECMAScript 6 解决了所有这些问题:首先,它建议将 var 替换为 let,let 不可以重新声明。除此之外,let 的操作与 var 完全相同:
var msg = "Howdy";var msg = "Hello there"; // acceptable, just reassigns let mevar msg = "Howdy";
var msg = "Hello there"; // acceptable, just reassigns
let message = `This is your message.`;
let message = `This is another message.`; // ERROR!
在变量声明中使用 const,满足了对不可变性的需求。完成设置之后,使用 const 声明的变量绝对不能修改:
const message = `This is your message.
`;message = `This is your second message.`; // ERROR!
尽管使用 const 声明的变量不能更改其值,但该变量指向的 object 不是常量,所以它仍是可修改的:
const user = request.user;
user = new User(); // ERROR!
user.authorized = true; // acceptable, changes a property
因此,我的建议是首先使用 const。如果确实需要修改该变量,始终可以将声明更改为 let。
谈到变量声明,令许多 ECMAScript 开发人员感到奇怪的是声明的变量没有绑定到声明它们的 “代码块”。它们被绑定到函数。这是一个函数范围变量的示例:
function bar() {
var i = 10;
while (i > 0) {
var j = 1;
while (j > 0) {
var i = 1; // This is the same i as above
j--;
i--;
}
}
}
上面的函数将进入嵌套循环一次,因为 i 的第二个 “声明” 仅将值 1 赋给它。或许这不符合程序员的意图,但其中已考虑到了所有方面。
从 ECMAScript 6 开始,使用 let 和 const 声明的变量都具有代码块范围,所以在当前表达式代码块结束时,而不是函数结束时,它们将超出范围。重写前面的代码,使用 let 代替 var,这将得到预期的行为:
function bar() {
let i = 10;
while (i > 0) {
let j = 1;
while (j > 0) {
let i = 1; // Different i
j--;
i--;
}
} // This loop will execute 10 times, as intended
}
更广义地讲,代码块范围意味着使用 let 和 const 声明的变量的行为将与其他基于 C 的语言中的变量相同。与 ECMAScript 目前为止管理变量的奇怪方式相比,这是一大改进。
还有最后一个与变量声明相关的变化,而且该变化是 ECMAScript 6 中最重要的更新之一。解构赋值(destructuring assignment) 允许从一个对象或数组向多个变量赋值。实质上,该操作将数组或对象 “解构” 为它的构成部分。
或许通过操作而不是通过文字才能更好地了解什么是解构。给定一个类似这样的数组
let names = ["Ted", "Jenni", "Athen"];
let [ted, jenni, athen] = names;
console.log(ted, jenni, athen); // prints "Ted Jenni Athen"
注意,数组将变量声明放在括号中。这些括号告诉 ECMAScript,等号右侧需要一个数组。如果数组中的元素比声明的变量要多,那么数组中剩余的元素将被丢弃。(当然,这些值仍在数组中 — 数组的值被复制到变量中,最初的数组不受影响。)如果数组中的值比声明的变量少,ECMAScript 将为所有剩余的变量填入值 “undefined”。
在许多方面,解构赋值的数组形式只是相同操作的旧形式的语法糖:
var ted = names[0];
var jenni = names[1];
var athen = names[2];
解构版本更短,而且可能表达得更清楚。
解构赋值的最适用用例之一是,从一次正则表达式解析中提取值:
var url = "http://www.newardassociates.com/#/speaking";
var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
var [, protocol, fullhost, fullpath] = parsedURL;
console.log(protocol); // "http"
也可对对象执行类似的解构类型。先给定一个简单对象,然后就可以执行以下类似操作:
let point = { x:2, y: 5 };
let {x, y} = point;
console.log(x, y); // prints 2, 5
在这里,解构发生在对象上,并通过在右侧对象中找到同名的变量来绑定变量。也就是说,即使我们以相反顺序编写变量,x 的值仍会收到 point.x,y 仍会收到 point.y:
let point = { x:2, y: 5 };
let {y, x} = point;
console.log(x, y); // prints 2, 5
如果出于某种原因,您不关心对象字段名称是否匹配,可以使用字段式语法来重命名字段,左侧表示要匹配的名称,右侧表示实际声明的变量名:
let {y: pty, x: ptx} = point;
console.log(ptx, pty); // prints 2, 5
这使您在解构对象时能够对变量命名有更多的控制权。
解构也可以在多个层上发生;例如,矩形通常使用两点来表示:
let rect = { lowerLeft: { x:0, y:0 }, upperRight: { x:3, y:4} };
如果提取矩形的 4 个值,可以将两个 x/y 对拉入 4 个不同的变量中,就像这样:
let { lowerLeft: { x:llx, y: lly }, upperRight: { x:urx, y:ury } } = rect;
console.log(llx, lly, urx, ury); // prints "0 0 3 4"
在这种情况下,“lowerLeft” 和 “upperRight” 不是实际的变量;它们是占位符,表示其子字段应如何绑定到被解构的对象中具有对应名称的字段。本例中仅实际引入了变量 llx、lly、urx 和 ury。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。