244 lines
4.5 KiB
Markdown
Executable File
244 lines
4.5 KiB
Markdown
Executable File
# 面向对象
|
||
|
||
> 封装, 继承, 多态
|
||
>
|
||
> 封装: 属性私有化
|
||
> 继承: extends
|
||
> 多态: js不会检查参数的类型,任何数据都可以作为参数传递
|
||
|
||
## es6 class类
|
||
|
||
> 替代了es5的构造函数和原型,使之代码结构上更加简洁
|
||
> 简单理解, 类是一个模板, 实例化就是进行个性化填充参数
|
||
|
||
```js
|
||
// 关键字class
|
||
class 类名{//类名大驼峰
|
||
属性名 = 属性值 //属性直接写, 不能用let
|
||
属性名 //也可以不用赋值
|
||
函数名() {} //函数写法, 直接写函数名, 不用写function
|
||
//ES6的语法, 最终系统会转成es5, 函数是挂载在原型上的, 只占用一份空间
|
||
}
|
||
```
|
||
|
||
```js
|
||
class Student {
|
||
name = '张三'
|
||
age = 33
|
||
sayhello(){
|
||
console.log('hello')
|
||
}
|
||
}
|
||
let s = new Student()
|
||
console.log(s)
|
||
console.log(s.name)
|
||
s.sayhello()
|
||
```
|
||
|
||
new的原理
|
||
|
||
1. 开辟内存空间(堆)
|
||
2. 设置原型链
|
||
3. 产生this对象
|
||
4. 初始化: 执行构造函数(这里是执行构造器)
|
||
5. 返回对象的内存地址
|
||
|
||
### 属性
|
||
|
||
* 非静态属性
|
||
* 静态属性: static, 只能通过类访问, 不能通过实例访问
|
||
* 私有属性: #, 只能在类内部访问, 数据更安全
|
||
* 通过getter方法读取, 通过setter方法修改
|
||
|
||
```js
|
||
class Student {
|
||
static name = '张三'
|
||
age = 33
|
||
#address = '长安'
|
||
|
||
getAddress(){
|
||
return this.#address
|
||
}
|
||
setAddress(address){
|
||
this.#address = address
|
||
}
|
||
}
|
||
let s = new Student()
|
||
console.log(s.name, s.age) // undefined 33
|
||
console.log(Student.name, Student.age) // 张三 undefined
|
||
|
||
console.log(s.#address) // must be declared in an enclosing class
|
||
console.log(s.getAddress())
|
||
console.log(s.setAddress('123'))
|
||
```
|
||
|
||
如果想读还是正常读, 写需要调用方法
|
||
|
||
```js
|
||
get address(){
|
||
return thisl#address
|
||
}
|
||
|
||
setAddress(address){
|
||
this.#address = address
|
||
}
|
||
```
|
||
|
||
同理也可以改成直接写
|
||
|
||
```js
|
||
set address(address){
|
||
this.#address = address
|
||
}
|
||
```
|
||
|
||
### 方法
|
||
|
||
* 非静态方法
|
||
* 静态方法: static, 只能通过类访问, 不能通过实例访问
|
||
|
||
```js
|
||
class Student {
|
||
static sayhello(){
|
||
console.log('hello')
|
||
}
|
||
saybye (){
|
||
console.log('bye')
|
||
}
|
||
}
|
||
let s = new Student()
|
||
s.sayhello() // not a function
|
||
s.saybye()
|
||
Student.sayhello()
|
||
Student.saybye() // not a function
|
||
```
|
||
|
||
### constructor 构造器
|
||
|
||
> 构造器存在的价值: 初始化属性
|
||
> 只要实例化, 对象就会在产生后的第一件事, 调用constructor
|
||
|
||
```js
|
||
class Student {
|
||
constructor(name, age){
|
||
console.log('立刻被执行')
|
||
console.log(this) // this指向新实例的那个对象
|
||
this.name = name
|
||
this.age = age
|
||
}
|
||
sayhello(){
|
||
console.log(`hello, my name is ${this.name}`)
|
||
}
|
||
}
|
||
let s = new Student('张三', 18)
|
||
s.sayhello()
|
||
```
|
||
|
||
### extends 继承
|
||
|
||
> 子类没有的, 直接继承父类, 继承之后, 可以直接使用父类的属性和方法
|
||
|
||
```js
|
||
语法:
|
||
1. 定义父类
|
||
class 父类{属性和方法}
|
||
2. 定义子类要实现继承
|
||
class 子类 extends 父类{}
|
||
```
|
||
|
||
```js
|
||
// 如果我还有一个猫的类, 一个鸟的类, 每个类都要创建一遍, 太麻烦, 把公共的抽出来,变成一个公共动物类
|
||
|
||
class Animal {
|
||
name:string
|
||
age:number
|
||
|
||
constructor(name:string, age:number){
|
||
this.name = name
|
||
this.age = age
|
||
|
||
}
|
||
|
||
say(){
|
||
console.log('动物在叫')
|
||
}
|
||
}
|
||
|
||
class Dog extends Animal {
|
||
food: string = "骨头"
|
||
say(){
|
||
console.log('汪汪汪')
|
||
}
|
||
}
|
||
|
||
class Cat extends Animal {
|
||
say(){
|
||
console.log("喵喵喵")
|
||
}
|
||
}
|
||
|
||
const dog = new Dog("小白",1)
|
||
const cat = new Cat("小黑",1)
|
||
```
|
||
|
||
### 重写
|
||
|
||
> 当子类继承了父类后,子类拥有与父类同名的属性或者方法,同名的子类方法或者属性就叫做重写
|
||
> 属性被重写: 被覆盖掉
|
||
> 方法被重写: 不会被覆盖, 在不同的原型中
|
||
|
||
### 访问父类被重写的方法/构造函数
|
||
|
||
```js
|
||
super.父类被重写的方法名()
|
||
```
|
||
|
||
```js
|
||
class Father {
|
||
name = 'father'
|
||
say(){
|
||
console.log("I'm father")
|
||
}
|
||
}
|
||
|
||
class Son extends Father {
|
||
name = 'son'
|
||
say(){
|
||
super.say() // 调用父类的方法
|
||
console.log("I'm son")
|
||
}
|
||
}
|
||
|
||
let s = new Son()
|
||
s.say()
|
||
```
|
||
|
||
* 也可以在构造函数中调用父类的构造函数
|
||
|
||
```js
|
||
class Bird extends Animal {
|
||
color:string
|
||
constructor(name:string, age:number, color:string){
|
||
super(name, age)
|
||
this.color = color
|
||
}
|
||
}
|
||
```
|
||
|
||
### 重写构造函器
|
||
|
||
> 一般写在第一行
|
||
> 构造器可以重写, 必须保证父类的构造器先运行
|
||
> 父类构造器有参数, 就必须给super传入
|
||
> 子类有构造方法且使用this前,必须使用super()
|
||
|
||
```js
|
||
class Bird extends Animal {
|
||
color:string
|
||
constructor(name:string, age:number, color:string){
|
||
super(name, age)
|
||
this.color = color
|
||
}
|
||
}
|
||
```
|