TypeScript 02 - 变量声明

在 TypeScript 中,var 还是 var,let 还是 let,const 还是 const,这里简单温习一下 var、let 和 const。

  1. var
  2. let
  3. const
  4. 解构
  5. 展开

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

通常来说会把默认值放在前边,用于被一些后来设定的属性所覆盖。

你可能感兴趣的:(TypeScript 02 - 变量声明)