TS和JS的区别
- TypeScript同JavaScript相比,最大的特点是强类型,支持静态和动态类型,和JavaScript不同,这种强类型相比弱类型,可以在编译期间发现并纠正错误,降低了试错的成本也提升了代码的规范性。
TS例子
- 先说一下 JS 的现状:
- 在 JS 中的变量本身是没有类型,变量可以接受任意不同类型的值,同时可以访问任意属性,属性不存在无非是返回 undefined
- JS 也是有类型的,但是 JS 的类型是和值绑定的,是值的类型,用 typeof 判断变量类型其实是判断当前值的类型
// JavaScript
var a = 123
typeof a // "number"
a = 'sdf'
typeof a // "string"
a = { name: 'Tom' }
a = function () {
return true
}
a.xxx // undefined
- TS 做的事情就是给变量加上类型限制
- 限制在变量赋值的时候必须提供类型匹配的值
- 限制变量只能访问所绑定的类型中存在的属性和方法
- 举个简单的例子,如下是一段能够正常执行的 JS 代码
let a = 100
if (a.length !== undefined) {
console.log(a.length)
} else {
console.log('no length')
}
- 直接用 TS 来重写上面的代码,把变量 a 的类型设置为 number。在 TS 中给变量设置类型的语法是 【 : Type 】 类型注解
let a: number = 100
if (a.length !== undefined) { // error TS2339: Property 'length' does not exist on type 'number'.
console.log(a.length)
} else {
console.log('no length')
}
创建数组
- TS创建数组的方式
let array1:Array<number>;
let array2:number[];
- JS创建数组的方式
let array1 = new Array()
let array1 = []
- TS创建的数组只允许存放相同类型的数据。
- 例子
let character:string[] = ["杨过", "小龙女", "郭襄", "郭靖", "黄蓉", "李莫愁", 1];
console.log(character); // Type 'number' is not assignable to type 'string'.
- TS创建对象类型的数组
interface IArrStudent{
name:string,
age:number
}
const arrType5:Array<IArrStudent>=[{ name:"Mr.A",age:18},{ name:"Mr.B",age:20}]
const arrType6:IArrStudent[]= [{ name:"Mr.A",age:18},{ name:"Mr.B",age:20}]
- TS中如果需要一个数组需要存放两种数据类型,需要使用联合类型(string | number)[] demo:
var foo: (string|number)[] = [ 1, "message" ];
!和?
let y:number
y = null // 无法通过编译
y = undefined // 无法通过编译
y = null!
y = undefined!
interface IDemo {
x?: number
}
let y:number
const demo = (parma: IDemo) => {
y = parma.x || 1 // 如果为undefined,返回y=1,如果不为undefined,则返回parma.x的值
return y
}
小知识
- Typescript的作者是C#之父,C#和java的语法非常接近。所以TS比较容易被写java的人接受
extends,implements区别
- 类实现接口(支持多个接口实现)
// 动物的接口
interface Animal {
type: string;
sound: string;
voice():void;
}
// Dog类实现接口
class Dog implements Animal {
type:string;
sound: string;
voice():void {
console.log(`${this.sound}, 我是${this.type}`)
}
constructor(sound: string,type: string) {
this.sound = sound
this.type = type
}
}
// Cat类实现接口
class Cat implements Animal {
type: string;
sound: string;
voice(): void {
console.log(`${this.sound}, 我是${this.type}`)
}
constructor(sound:string, type: string) {
this.sound = sound;
this.type = type;
}
}
new Cat("喵喵~","哺乳类").voice();
new Dog("汪汪~","哺乳类").voice();
结果:
喵喵~, 我是哺乳类
汪汪~, 我是哺乳类
2.接口继承接口(支持多继承)
// 生物体的接口
interface Creature {
name: string;
}
// 动物接口 继承生物接口
interface Animal extends Creature {
// 自己拥有的属性 action
action(): void;
}
class Dog implements Animal {
name: string; // name是 Animal继承自 Creature的,不实现会报错
action(): void {
console.log(`我是${this.name}`)
}
constructor (name: string) {
this.name = name;
}
}
new Dog("狗狗").action() // 我是狗狗
TIPS
- 类必须实现它的接口的所有属性,包括它继承自父类的属性
- 接口可以多继承:一个接口可以继承多个接口
// 生物体的接口
interface Creature {
name: string;
}
// 动物接口
interface Animal {
// 自己拥有的属性 action
action(): void;
}
// 狗Dog接口继承 生物Creature 和 Animal 多继承
interface Dog extends Creature, Animal{
color: string;
}
class Golden implements Dog {
name: string;
color: string;
action():void {
console.log(`我是${this.name},我的颜色是${this.color}`)
}
constructor(name: string, color:string) {
this.name = name;
this.color = color;
}
}
new Golden("金毛","金黄色").action() // 我是金毛,我的颜色是金黄色
Golden 实现了 Dog接口,Dog接口多继承了Creature 和 Animal两个接口,拥有了他们的属性,所以Golden要将他们全部实现。
- 类继承类(单继承)
// 父类
class Person {
name: string;
constructor(name: string) {
this.name = name;
}
run(): string {
return `${this.name}在奔跑`;
}
}
let p = new Person('张三');
console.log(p.run());
// 子类Web继承父类Person
class Web extends Person {
constructor(name: string) {
super(name); // 表示调用父类的构造函数
}
}
let w = new Web('李四');
console.log(w.run());
面向对象的三大特点
- 继承
子类可以继承父类的protected,public的方法和属性,private是私有属性不能获取
- 封装
封装的意义
- 封装的意义在于保护或者防止代码(数据)被我们无意中破坏。
- 保护成员属性,不让类以外的程序直接访问和修改;
- 隐藏方法细节
- 多态
多态的条件
- 继承的存在(继承是多态的基础,没有继承就没有多态).
- 子类重写父类的方法(多态下调用子类重写的方法).
- 父类引用变量指向子类对象(子类到父类的类型转换).
/**
* Animal 是一个抽象类,里面含有一个eat()抽象方法
*/
abstract class Animal{
public name:string;
constructor(name:string){
this.name=name;
}
//抽象方法 ,不包含具体实现,要求子类中必须实现此方法
abstract eat():any;
//非抽象方法,无需要求子类实现、重写
run(){
console.log('非抽象方法,不要子类实现、重写');
}
}
class Dog extends Animal{
//子类中必须实现父类抽象方法,否则ts编译报错
eat(){
return this.name+"吃肉";
}
}
class Cat extends Animal{
//子类中必须实现父类抽象方法,否则ts编译报错
eat(){
return this.name+"吃鱼";
}
}
var dog =new Dog("tom");
var cat=new Cat("kitty");
console.log(dog.eat());
console.log(cat.eat());
//多态 ,一种事物的不同表现形态。如下面的代码中 先声明变量f是Animal类型,具体是Dog还是Cat,在new 对象时才知道
//如果是Dog,则f.eat()调用的是Dog类中的eat方法;如果是Cat,则f.eat()调用的是Cat类中的eat方法,这就是多态!!!
var f:Animal;//声明变量为Animal类型
//f=new Dog("sunny");
f=new Cat("sunny");
console.log(f.eat());
抽象类
- 抽象类不一定要有抽象方法
- 有抽象方法的一定是抽象类
- 父类有抽象方法,子类必须去实现抽象方法
- 抽象类只能作为基类,不能实例化的(不能new)
- 若子类继承抽象类,并重写了所有的抽象方法,则此类是一个”实体类”,即可以实例化
- 若子类继承抽象类,没有重写所有的抽象方法,意味着此类中仍有抽象方法,则此类必须声明为抽象的!
type 与 interface 的区别
官方文档
- An interface can be named in an extends or implements clause, but a type alias for an object type literal cannot.
- An interface can have multiple merged declarations, but a type alias for an object type literal cannot.
相似的
- type 用于定义数据的类型别名。interface 用于定义数据的类型别名。
interface User {
name: string
age: number
}
interface SetUser {
(name: string, age: number): void;
}
type User = {
name: string
age: number
};
type SetUser = (name: string, age: number)=> void;
- 都允许拓展(extends)
interface Name {
name: string;
}
interface User extends Name {
age: number;
}
type Name = {
name: string;
}
type User = Name & { age: number };
type Name = {
name: string;
}
interface User extends Name {
age: number;
}
interface Name {
name: string;
}
type User = Name & {
age: number;
}
不同点
- type 可以声明基本类型别名,联合类型,元组等类型
- interface只能定义对象类型。
// 基本类型别名
type Name = string
// 联合类型
interface Dog {
wong();
}
interface Cat {
miao();
}
type Pet = Dog | Cat
// 具体定义数组每个位置的类型
type PetList = [Dog, Pet]
- type 语句中还可以使用 typeof 获取实例的 类型进行赋值
// 当你想获取一个变量的类型时,使用 typeof
let div = document.createElement('div');
type B = typeof div
- interface 可以而 type 不行
// interface 能够声明合并
interface User {
name: string
age: number
}
interface User {
sex: string
}
/*
User 接口为 {
name: string
age: number
sex: string
}
*/
结论
- 一般来说,如果不清楚什么时候用interface/type,能用 interface 实现,就用 interface , 如果不能就用 type
- 根据官方文档所说,如果构建的是公开第三方库的类型,还是建议使用interface.
- interface 更倾向于继承;而 type 则更倾向于组合。