初探TypeScript

Posted ㄏ、Forgetˊ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了初探TypeScript相关的知识,希望对你有一定的参考价值。

TypeScript菜鸟学习笔记

TypeScript是什么?

TypeScript = Type + EcmaScript6
TypeScript是javascript的强类型版本。然后在编译器去掉类型和特有语法,生成纯粹的Javascript的代码。由于最终在浏览器中运行的仍然是Javascript,所以TypeScript并不依赖于浏览器的支持,也不会带来兼容性的问题。
TypeScript是Javascript的超集,这意味着他支持所有的JavaScript语法。并在此之上对JavaScript添加了一些拓展,如class/interface/module等。这样会大大提升代码的可阅读性。
和JavaScript弱类型不同,TypesScript这种强类型语言最大的优势在于静态类型检查,可以在代码开发阶段就预知一直低级错误的发生。

学习typescript的前置知识:

  1. EcmaScript6语法基础
  2. TypeScript概念及与JavaScript关系 如同CSS和less、sass之间的关系
  3. 具有一定的JavaScript开发经验
  4. 有C#、C、C++、Java等静态类型语言开发经验更佳

TypeScript与传统JavaScript的区别

举个最简单的例子,新建一个js文件,粘贴下面的代码:

let foo = 
  name: 'bar'


console.log(foo.naem)

上述JS代码中,定义了一个foo对象,其中有一个name属性,而在console打印的时候,却是打印foo.naem,这个时候,程序是不会报错的。
我们把后缀js替换为ts(这里默认你已经全局安装了TypeScript

妈妈再也不用担心我写代码拼错单词了有木有?

解构赋值

解构赋值分两种,一个是数组的解构赋值,一个是对象的解构赋值,其实数组也是对象的一种。
假设现在有一个数组,需要分别取数组中的元素,通常情况下我们会这么写:

let arr = [10, 20]
let arr1 = arr[0]
let arr2 = arr[1]

使用TypeScript我们可以换成这样:

let arr: number[] = [10, 20]
let [arr1, arr2] = arr

同理换成对象的话,我们可以这么写:

let user = 
  name: 'jack',
  age: 2

// 由于window实例对象上也存在name属性,故这里的name我们需要给它一个别名
// 这里的name: nickname不是类型定义,而是解构的时候给name起一个别名为nickname
let  name: nickname, age  = user

我们将其应用到函数中:

// 通常写法
function add(arr: number[]): number  
  let x = arr[0]
  let y = arr[1]
  return x + y

add([10, 20])

// 解构写法
function add([x, y]): number  
  return x + y

add([10, 20])

剩余参数

剩余参数的使用依赖于ES6的...拓展操作符

// 假设现在有一个sum方法,用户直接传参计算,我们可以这么写
function sum(...args: number[]) 
  let result = 0
  args.forEach((item) => 
    result += item
  )
  return result

// 调用的时候,我们只需要直接传参即可
sum(1, 2, 3, 4)

// 数组中的应用
let arr1 = [1, 2, 3]
let arr2 = [4, 5, 6, ...arr1] // 数组arr2合并数组arr1
let arr = [...arr1, ...arr2] // 数组arr1和arr2合并

// 对象中的应用
// 假如说有各有obj1和obj2对象,对象obj2也具备obj1中的属性,那我们可以这么写
let obj1 = 
  foo: 'bar'

let obj2 = 
  ...obj1, // obj1直接通过拓展操作符写入obj2
  name: 'Jack'

类的基本使用

假设我们现在有一个Person类,它具有name、age属性和一个sayHello方法,这里我们先使用函数的方式来实现它

function Person(name: string, age: Number) 
  this.name = name
  this.age = age

// 通过prototype给Person实例追加一个sayHello方法
Person.prototype.sayHello = function (): void 
  console.log('Hello')

如果我们使用class关键字来定义的话,我们可以把上边的代码换成这样:

class Person 
  name: string
  age: number
  // constructor就是类的构造函数
  // 当你调用new Person 的时候就会调用constructor(返回值为Person实例对象)
  constructor(name: string, age: number) 
    // 我们这里实际上是动态地添加成员
    // TypeScript要求类的成员必须先定义出来并确定类型
    this.name = name
    this.age = age
  
  // 实例方法
  sayHello(): void 
    console.log('Hello')
  

// 然后我们需要通过new关键字来使用它
let p1 = new Person('张三', 18) // new出一个p1实例
p1.sayHello() // 调用实例方法

从代码量来看,其实是增加了,但是使用class来创建类,比起用function来实现清晰很多。
在实际开发中,我们肯定不止有一个类,如果有多个类,而且类之间存在相同可继承的属性或者方法,我们可以使用类的继承关键字extends来继承类:

// 假如说有一个Person类,它里面有一个eat方法
class Person 
  name: string
  age: number
  constructor(name: string, age: number) 
    this.name = name
    this.age = age
  
  eat() 
    console.log('吃饭')
  

// Student class需要继承Person class
class Student extends Person 
  constructor(name: string, age: number) 
    super(name, age) // 父类构造函数
  

new Student('张三', 18) // 这里我们就可以拿到Person类和Student类中公开的属性和方法

类成员访问修饰符

类成员默认都是公开的,默认都是public(写不写无所谓)
private私有的 私有成员无法被继承 (作用:可以把不希望被外部修改的成员设置为私有成员)
protected受保护的 和private类似,外部无法访问,但是可以被继承
还有一个比较特殊的 readonly只读的,不允许修改,和const定义常量类似

class Person 
  public name: string
  age: number
  // 我们可以在声明类成员的时候同时为其赋值
  private readonly type: string = '人类'
  // 和private类似,外部无法访问,但是可以继承
  protected foo: string = 'bar'
  // 方法默认也是public公开的
  getType() 
  	// private和protected修饰的属性,只能在内部访问
    console.log(this.type)
  
  changeType() 
    // type为readonly只读的,这里这么写系统会抛出警告,type不可被修改
    this.type = '哈哈哈'
  

class Student extends Person 
  getFoo() 
    // foo属性在父类中为受保护的,它可以被继承
    // 不能从外界访问,但可以从内部访问foo
    console.log(this.foo)
  


// 修饰符的各种写法
class Person 
  // 最基础的写法
  public name: string
  public age: number
  constructor( name: string,  age: number) 

  // 简写
  constructor(public name: string, public age: number) 

  // 也可以混写
  public gender: string
  constructor(public name: string, public age: number, gender: string) 

类中属性的get和set

假设现在定义了一个Person类,它有一个age属性,我们在new实例的时候,为age传值为-10。这样做的话,虽然程序上不会报错,可是业务逻辑上却出错了,因为人的年龄是不存在负数的,我们需要在new之前进行判断。

class Person 
  public age: number
  constructor() 


// 可在此手动校验
new Person().age = -10

但其实,我们可以使用类中属性的get和set来进行校验

class Person 
  private _age: number
  get age() 
    return this._age
  
  set age(val) 
    if (val < 0) 
      // 判断到传入的age值小于0,则抛出Error
      throw new Error('年龄不能小于0岁')
    
    // 在校验正确后,我们才对其做赋值操作
    this._age = val
  

let p1 = new Person()
p1.age = -10 // 这里赋值,就会先p1实例的set方法

类的静态成员

实例成员,只能通过new出来的实例访问
静态成员,也叫类的成员,只能通过类去访问

class Person 
  static type: string = '人类'
  name: string = '张三'
  age: number = 18
  // 默认是实例成员,加上static就会变成静态成员
  static sayHello() 
    console.log('我是人类')
  

// 访问静态成员,只能通过类去访问
// 如访问Person类中的type属性和sayHello方法
console.log(Person.type) 
Person.sayHello()

迭代器

for-of迭代的是对象的键所对应的值, for-in迭代的是对象的键的列表

let arr = [1, 2, 5]
for (let val of arr) 
  console.log(val) // for-of迭代输出的是对象的键所对应的值,这里输出 1 2 5

for (let key in arr) 
  console.log(key) // for-in迭代输出的是对象的键的列表(在这里就是数组的下标值),这里输出 0 1 2

总结

经过简单的学习,我们了解到了TypeScript强大的类型校验对JavaScript所带来的功能增强,但是并不是说它就是万能的,我们仍需要以实际环境来判断是否需要(必须)使用TypeScript。
这里有几点总结概况:

  1. TypeScript 未能带来预期的结果或价值,如开发人员学习成本过高、小团队小项目,那么这种情况下其实不推荐使用;
  2. 只有当 TypeScript 提供了你预期的那些好处时才有自己的价值,否则结果会变得很糟糕;
  3. 在你将 TypeScript 深度用于实践工作之前,必须首先搞清楚为什么你要使用它,为什么要在项目中应用它;
  4. 如果它没能提高你的生产力,没能增强你正在构建的应用程序的可靠性,那么你就没有从中获得什么价值。
    Keep learning…

以上是关于初探TypeScript的主要内容,如果未能解决你的问题,请参考以下文章

初探typescript

初探TypeScript

初探typescript

Vue3通透教程初探TypeScript

TypeScript初探,行则将至

TypeScript初探,行则将至