原文链接:https://leanpub.com/essentialtypescript/read#ecmascript-features
这一章讲的东西都是 “语法糖” —— syntactic sugar,就是说,它们并没有提供新的功能,只是提供了一种简便的写法。
1. Optional Parameters
var container = document.getElementById('container');
function countdown(initial, final, interval) {
var current = initial;
while(current > final) {
container.innerHTML = current;
current -= interval;
}
}
countdown(10, 0, 1);
这是一个循环递减函数。在大部分情况下,我们都会让 final等于0, interval等于1。可以给参数设置默认值:
function countdown(initial, final=0, interval=1) {
var current = initial;
while(current > final) {
container.innerHTML = current;
current -= interval;
}
}
countdown(10);
这样,在调用时,后两个参数就可以省略了。
看看tsc编译出来的es5代码:
var container = document.getElementById('container');
function countdown(initial, final, interval) {
if (final === void 0) { final = 0; }
if (interval === void 0) { interval = 1; }
var current = initial;
while (current > final) {
container.innerHTML = current;
current -= interval;
}
}
很熟悉哈。以前,自己也一直是这么写的。
2. Template Strings
var todo = {
id: 123,
name: "Pick up drycleaning",
completed: true
}
var displayName = `Todo #${todo.id}`;
程序运行时,最后一行的 ${todo.id} 会被替换成 123。
再看一个复杂的例子:
var container = document.getElementById('container');
var todo = {
id: 123,
name: "Pick up drycleaning",
completed: true
}
container.innerHTML = `
<div todo='[[Todo ID]]' class="list-group-item}">
<i class="[[ If Todo is complete, then "hidden" ]] text-success glyphicon glyphicon-ok"></i>
<span class="name">[[Name]]</span>
</div>
`
注意:
1. 用双重方括弧 [[ ]] 包起来的,都是我们希望动态替换的。
2. container.innerHTML 后面,多行字符串可以用反引号(数字1左边的按键)包起来,这种字符串中单引号和双引号都不需要转义。
${ } 中,不仅可以包含变量,还可以包含任意语句。所以,动态替换的代码可以这么写:
container.innerHTML = `
<div todo='${todo.id}' class="list-group-item}">
<i class="${todo.completed ? "" : "hidden"} text-success glyphicon glyphicon-ok"></i>
<span class="name">${todo.name}</span>
</div>
`
看一看tsc编译出来的ES5代码:
container.innerHTML = "\n <div todo='" + todo.id + "' class=\"list-group-item}\">\n <i class=\"" + (todo.completed ? "" : "hidden") + " text-success glyphicon glyphicon-ok\"></i>\n <span class=\"name\">" + todo.name + "</span>\n </div>\n";
3. Let and const
for(var x = 0; x <= 5; x++) {
var counter = x;
}
console.log(counter);
输出什么? 5
大括号不能生成新的作用域,在js中,只有function可以定义新的作用域。
let 可以解决这个问题。
for(var x = 0; x <= 5; x++) {
let counter = x;
}
console.log(counter);
这段代码运行会出错,let 使 counter的作用域限制在for循环内部。
const counter = 1;
counter = 3;
这段代码运行会出错,const定义了常量,常量不可修改。
4. For .. of Loops
for .. in 遍历的是数组的索引
var array = [ "Pick up drycleaning", "Clean Batcave", "Save Gotham" ];
for(var index in array) {
var value = array[index];
console.log(`${index}: ${value}`);
}
for .. of 可以直接遍历数组中的值
var array = [ "Pick up drycleaning", "Clean Batcave", "Save Gotham" ];
for(var value of array) {
console.log(value);
}
5. Arrow Functions
js 中的 this 变量是个很怪异的东西,看个例子:
var container = document.getElementById('container');
function Counter(el) {
this.count = 0;
el.innerHTML = this.count;
el.addEventListener('click', function () {
this.count += 1;
el.innerHTML = this.count;
});
}
new Counter(container);
把这段代码复制到 TypeScriptTodo 工程的 app.ts 文件中,保存。 确保 tsc -w 正在运行。
打开一个命令行窗口,切换到 TypeScriptTodo 目录下,运行: lite-server。
浏览器会自动打开,页面上显示0。点击页面,呃,本以为0会变成1,结果却是 NaN。这是因为event handler 不是 Counter 的成员函数,在这个function内部,this指的是js环境的全局对象(在node.js环境中是global,在browser环境中是window)。
为了解决这个问题,通常我们使用这种模式:
let _this = this;
el.addEventListener('click', function () {
_this.count += 1;
el.innerHTML = _this.count;
});
这种写法看起来很笨拙,ES6提供了一种新的语法(arrow function):
el.addEventListener('click', () => {
this.count += 1;
el.innerHTML = this.count;
});
把 "function()" 改成了 "() => " 。
看一下tsc编译后的代码:
var container = document.getElementById('container');
function Counter(el) {
var _this = this;
this.count = 0;
el.innerHTML = this.count;
el.addEventListener('click', function () {
_this.count += 1;
el.innerHTML = _this.count;
});
}
new Counter(container);