定义class类
对象中包含两个部分:属性和方法
实例属性:
属性存在实例,只有new了实例,才能看到这些属性
类属性:
通过类访问属性
上图中 如果能访问成功,age就是类属性
在上方代码中应该会报错,因为类指的是Person,而age是实例属性,在Person外部也没有定义过Person.age所以访问不到
怎么定义类属性
类中的属性前添加static
关键字
类属性也被称为静态属性
总结:
正常情况下实例属性可随意修改值
但属性前添加readonly关键字后,只读,该属性不可修改
只读的静态属性:
static readonly
属性
注:
static和readonly的书写顺序不可改变,先写readonly会报错
上方是实例方法,需要先new
如果属性前加上static
,那就变为类方法,无需new,直接使用Person.方法
注:
类方法也叫静态方法
静态方法的使用相对要少一些
constructor
构造函数会在对象创建时调用
为什么要使用构造函数:
因为要用 同一个类 创建/实例话多个 属性 不同的对象
调用constructor的时机:
constructor中的this
图中的this指向不同的实例话的对象(指向的是当前实例化的对象)
constructor中添加this.
属性,等于就是在new(实例化)的对象中添加属性
传参,设置通用的类,通过传不同的参数,创建的对象属性也不同
注:
this.name和this.age报错
解决方法:
在class中添加name和age
图中红框内的name和age指的是constructor构造函数中的this.name和this.age
this表示当前对象
this表示当前对象:
哪个对象调用这个方法,this就是哪个对象
注:
绿色的是直接在控制台中输入dog.bark()运行的结果
控制台中可以直接输入代码 执行并查看效果
继承(面向对象中很重要的点):
像css样式中也有继承的概念
立即执行函数:
注:
写在立即执行函数中的代码,与外部没有冲突,因为作用域不一样
如何调用js并执行查看结果:
在立即执行函数中创建两个类,狗和猫
写完发现除了叫声这里的代码不一样,其他的地方代码都是重复的代码
设置一个animal的类,把重复的代码提取出来
extends
继承:
执行结果
在子类中添加一些父类没有的方法(直接添加即可)
ocp原则 o:open c:close p:原则,叫开闭原则
编写一段代码时,要对扩展开放(可扩展),对修改关闭
也就是不能去修改(别人写的类,源代码),但可以去扩展
怎么去扩展?
去创建一个新类,去继承需要修改的类,然后去修改这个新的类,在这个新的类中添加功能,这样对原有的类也没有影响
这样就可以在不修改原来类的基础上进行扩展
上方的子类中添加的run方法其实就是一种扩展
在子类中添加了和父类相同的方法,则在子类中(仅在该子类中),会覆盖父类的方法
执行修改过的子类方法的结果:
这种子类覆盖掉覆盖掉父类方法的形式 叫 重写
继承中的super
父类 也叫 超类
super
就相当于是 父类
子类(Dog)调用父类(Animal)中的方法(sayHello)
添加新属性,就得先运行constructor构造函数,但子类中写与父类相同的函数会覆盖
,因为constructor
是和new
一起运行的,那父类中的constructor
就会失效不执行
(所以dog.sayHello打印的结果为空)
一般用于在子类中添加新属性
添加新属性,就得先运行constructor构造函数,但子类中写与父类相同的函数会覆盖,因为constructor是和new一起运行的,那父类中的constructor就会失效不执行
所以在子类中如果重写constructor
,必须先执行父类
(因为要让父类的constructor
先执行)
所以要先执行super
方法,并且如果父类的constructor
中有参数的话,子类中调用的super
方法也得传入相同的参数
该参数不用重新定义,因为继承父类时,已经一起继承下来了
调用子类方法也得传入两个参数
抽象类和其他类区别不大
只是不能用来创建对象
抽象类只是用来继承的
报错信息:
注:
一个类的范围太大,不想让其创建对象,可让其变为抽象类
比如 狗,猫等new对象,但 动物 范围太大 把动物这个词变为对象不太好
抽象类中的 方法 开头添加abstract
抽象方法必须写在抽象类中
抽象方法 没有方法体
抽象方法 子类必须对这个抽象方法重写
方法体 就是 方法名()后面{}中的就是方法体
定义的抽象方法不去实现,但继承的子类必须去实现
,不实现会报错
子类必须重写抽象方法:
用来定义一个类/对象的结构
上方就是定义了一个叫myInterface的类,这个类里必须有两个属性,一个叫name,一个叫age,name的类型必须是string类型,age的值的类型必须是number
创建一个对应这个接口的对象,少属性或者多属性都会报错
如果同时写了两个名字一样的接口
,那么 它们里面设置的属性叠加
等于是两个 合并成 一个接口
如上图:等于是创建了一个叫my Interface的接口,里面包含三个属性,分别是name,age和gender
完整写法:
别名
来描述一个对象的类型(type)
或者
别名 和 接口的区别:
接口可以在定义类的时候去限制类的结构(只定义对象的结构)
接口中的所有属性都不能有实际的值
注:
接口中的方法 都是 抽象方法
实现接口:
就是类 满足接口的要求
正规的写法:
设置了 name:string,必须要 初始化 这个变量(constructor 构造函数)
接口定义了一个标准
属性的封装(通过public,private等修饰配合自定义的get(必须return),set等方法)
属性可以任意修改 将会导致对象中的数据变的非常不安全(比如年龄,年龄如果是负数,比如一些敏感信息,比如钱)
可以在任意位置访问或修改
public是默认的,不写就是public
private 私有属性
在类 里面可以访问
在类 外面 无法访问
,会报错
通过return
来获取私有属性的值
通过 自定义的方法
去修改 对象内部的私有属性
通过自定义的方法来取值,修改值,或者添加判断,不让访问就不写方法(因为是私有属性,内部不写方法,外部访问不了)
这样的好处可以把值的修改等等的主动权保留在自己手上,并且更加的安全
代码会变的更加的健壮,降低了的代码的出错的几率
这些方法被称为 属性的 存取器
获取方法的简写:
上图中的name指的是属性名
外部调用可以用.name,而实际访问的是内部的_name
注:
其实对象中没有叫name
的属性,只有叫_name
的属性
这么写的话,外部调用可以用.name,而实际访问的是内部的_name
这样就不用去改变我们的使用习惯,去通过方法获取/修改值了
set 设置的写法:
更多例子(设置age中添加判断)
注:
在属性 容易被修改错,或者技术要求比较高时,可以用get 和 set
修饰符public和private区别:
public子类中也可访问父类的属性
private只能父类内部访问
子类虽然不能访问父类的私有变量,但是子类继承了父类的变量和方法
protected 受保护的
只能在当前类和子类中使用
通过new
实例话后去访问,是访问不了的,会报错
三个修饰符:
在tsconfig.json中配置“noEmitOnError”:true
把需要的属性直接写在构造函数中
这么写 等同于 先设置属性 再写构造函数
注:
简写
里 的参数前
一定要加public
等于是一种语法糖
描述类型通常大写
<大写字母>
上图中 大写T就是泛型,具体是什么类型不知道,只有在执行的时候才会知道
用泛型 可以避免使用any,使用any会关闭类型判断
使用:
不指定泛型 和 指定 泛型:
设置完泛型,然后在调用时 可以选择 指定(<类型>)或不指定泛型
多个泛型:
多个泛型 指定 写法:
给 泛型 定一个范围:
建一个接口 或 一个 类,然后 包含 泛型 的方法继承 类或者实现 接口
方法里 泛型 的继承和实现统一都用extends
上图中,传的参数T 必须有 length
这个属性(类型继承了Inter
’接口),字符串是具有length属性的
或者 参数是一个包含length
属性的对象
不包含length
属性会报错
(数字等)
没有
设置length
属性的对象
也会报错
泛型 搭配 class,并new 调用:
上图调用的是指定类型string
的泛型,尖括号string不写就是 不指定类型的泛型
!
表示不会为空
let foo = () =>{
let name = "alberto";
return name!;
}
document.body.innerHTML = foo();
编译成js后的代码如下:
var foo = function () {
var name = "alberto";
return name;
};
document.body.innerHTML = foo();
感叹号! (非空断言操作符) ,这个代码中没有什么意义,因为name是常量,如果name可能为空,可以用这个。因为如果name为空,会丢出断言失败。
string表示原生类型,而String表示对象
let msg3: String = new String('Hello world!');
这个变量msg3的类型就是object:
console.log(typeof(msg3)); // object
可以把 类 放在单独的js里 然后再 暴露 (通过export default)出去
需要使用 可以通过import引入