美文网首页TypeScript 文档学习
TypeScript 02 - 变量声明

TypeScript 02 - 变量声明

作者: 晓风残月1994 | 来源:发表于2019-11-27 00:37 被阅读0次

    在 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 - 变量声明

        本文链接:https://www.haomeiwen.com/subject/szhuwctx.html