在 TypeScript 中,var 还是 var,let 还是 let,const 还是 const,这里简单温习一下 var、let 和 const。
- var
- let
- const
- 解构
- 展开
1. var
使用 var 声明变量并赋值时 var a = 1
; 声明 var a
会提升,但赋值 a = 1
不会提升,var 可以重复声明,var 只分函数内和函数外,不存在块级作用域,除了下面 try...catch
块中的这个 e
,但其实此处的 e
个人觉得看作是函数的形参或许更好理解:
try {
} catch(e) {
}
2. let
let 是 ES6 出现的,是块级作用域,不存在变量提升,同一个块内不能重复声明,在声明之前存在暂时性死区,不能进行操作,如下所示,在声明 a
之前就尝试调用函数 foo()
会报错 Cannot access 'a' before initialization
:
function foo() {
return a
}
foo()
let a
3. const
const 可以理解为 let 的增强,const 声明一个变量的同时要对其进行初始化,并且之后不能直接对声明变量再次赋值,但可以更改变量所指向的对象上的属性:
const a = 18
const n // 会报错
const a = 25 // 会报错
const people = {
name: 'xiaofeng',
age: a
}
// 会报错
const people = {
name: 'xiaoqian',
age: a
}
// 对属性修改是ok的,因为并没有改变对 people 的引用
people.age = 25
var、let、const 从最佳实践看来应该优先使用 const,不行再使用 let,而 var 几乎不需要使用,我一时间也想不出在可以写 ES6 的条件下,有什么特殊场景是不能用 let 非要用 var 的。
4. 解构和剩余参数
默认情况下 ts 文件在编译时会被转换为 ES3,看一下就能理解 ES6 语法了,或者到 babel 官网上 Try it out 练练手,看看是如何转换的。
4.1 数组解构
let input = [1, 2]
// 数组的解构赋值
let [first, second] = input
// 等价于
// let first = input[0]
// let second = input[1]
// 解构也能用于函数的参数
function foo([first, second]: [number, number]) {
console.log(first)
console.log(second)
}
// foo(input) // 使用 ts 编译时会报错,因为参数要求是 Tuple 元祖类型 [number, number],而实际上传入了 number[] 类型
// 解决办法是把 input 定义为同样的元祖类型即可
let input2: [number, number] = [1, 2]
foo(input2) // ok
// 解构 + 剩余参数
let [first, ...rest] = [1, 2, 3, 4]
console.log(first) // 1
console.log(rest) // [2, 3, 4]
// 还可以使用逗号分隔略过不关心的数据
let [, second, , fourth] = [1, 2, 3, 4]
console.log(second) // 2
console.log(fourth) // 4
4.2 对象解构
解构对象时,要注意如果一个属性值是 null,而不是 undefined,那么不会被默认值赋值。
// 对象解构赋值的同时还可以重命名
let o = {
a: 'foo',
b: 'bar',
c: 12,
d: false
}
let { a, b: banana, ...passthrough } = o
console.log(a) // 'foo'
console.log(b) // 报错 Uncaught ReferenceError: b is not defined
console.log(banana) // 'bar'
console.log(passthrough) // {c:12, d: false}
// 传入的对象中,b 属性有可能不存在
// type C = { a: string, b?: number }
function keepWholeObject(wholeObject: { a: string, b?: number }) {
// 所以解构时要为 b 属性提供默认值
let { a, b = 1000 } = wholeObject
console.log(a, b)
}
// 对象解构时,可以为属性可以提供默认值
// 对函数的对象参数进行时提供默认的解构来源
function foo({ a, b = 0 } = { a: '' }): void {
console.log(a, b)
}
foo({ a: 'yes' }) // 传入的对象,没有 b 属性,但好在 b 在解构时提供了默认值 0
foo() //不传参数时,默认从 { a: '' } 解构
foo({}) // 报错!因为类型不匹配。传入空对象,虽然 b 属性有默认值 0,但是 a 属性无从得知
解构表达式有时候会不好理解,尤其和 TS 的类型系统混合在一起时,因此使用时尽量保持小而简单。
5. 展开
5.1 数组的展开
let first = [1, 2]
let second = [3, 4]
let bothPlus = [0, ...first, ...second, 5]
console.log(bothPlus) // [0, 1, 2, 3, 4, 5]
5.2 对象的展开
let defaults = {
food: 'apple',
price: '$10',
total: 50
}
let search = { ...defaults, food: 'rich' }
console.log(search)
// {food: "rich", price: "$10", total: 50} 右边的同名属性 food 覆盖了左边展开后的属性 food
通常来说会把默认值放在前边,用于被一些后来设定的属性所覆盖。
网友评论