JavaScript学习笔记—面向对象

1. 类的简介

  • 类是对象的模板,可以将对象中的属性和方法直接定义在类中,定义后,就可以直接通过类来创建对象。
  • 通过同一个类创建的对象,成为同类对象
    • 可以用instanceof来检查一个对象是否由某个类创建
    • 如果某个对象是由某个类所创建,则我们称该对象是这个类的实例
  • 语法:
class 类名 {} // 类名使用大驼峰命名
const 类名 = class {} //不常用

2. 类的属性

class Person {
  name = "孙悟空"; // Person的实例属性name 调用:p1.name
  age = 18;
  static test = "test静态属性"; // 使用static声明的属性是静态属性(类属性) 调用:Person.test
}

3. 类的方法

class Person {
  name = "孙悟空";
  sayHello(){
    console.log("大家好,我是" + this.name);
  } // 添加方法(实例方法)this就是当前实例(如:p1)
  static test(){
    console.log("我是静态方法", this);
  } // 静态方法(类方法)通过类来调用,静态方法中this指向的是当前类(如:Person)
}
const p1 = new Person();
pa.sayHello();
Person.test();

4. 类的构造函数

class Person {
  // 以下三个属性可以省略不写
  name;
  age;
  gender;
  // 该方法称为构造函数(构造方法),在调用类创建对象时执行
  constructor(name, age, gender){
    // 可以在构造函数中为实例属性进行赋值,this表示当前所创建的对象
    this.name = name;
	this.age = age;
	this.gender = gender;
  }
}
const p1 = new Person("孙悟空", 18, "男");

5. 面向对象的特点

(1)封装
  • 对象就是一个用来存储不同属性的容器
  • 对象不仅存储属性,还要负责数据的安全
  • 直接添加到对象中的属性不安全,因为可以被任意修改,确保数据的安全需要:
    (1)私有化数据:将需要保护的数据设置为私有,只能在类内部使用
    (2)提供setter和getter方法来开放对数据的操作
    • 可以控制属性的读写权限
    • 可以在方法中对属性的值进行验证
  • 封装主要用来保证数据的安全
  • 实现封装的方式
    (1)属性私有化 加#
    (2)通过getter和setter方法来操作属性
get 属性名(){
  return this.#属性
}
set 属性名(){
  this.#属性 = 参数
}

// 私有化属性
class Person {
  // 私有属性必须先声明
  #name;
  #age;
  #gender;
  constructor(name, age, gender){
    this.#name = name;
	this.#age = age;
	this.#gender = gender;
  }
}
(2)多态
  • JS中不会检查参数的类型,所以这就意味着任何数据都可以作为参数传递
  • 要调用某个函数,无需指定类型,只要对象满足某些条件即可
  • 多态为我们提供了灵活性
(3)继承
  • 可以通过extends关键词来完成继承
  • 当一个类继承另一个类时,就相当于另一个类中的代码复制到了当前类中(简单理解)
  • 继承发生时,被继承的类为父类(超类),继承的类为子类
  • 通过继承可以减少重复的代码,并可以在不修改一个类的前提下对其进行扩展
  • OCP 开闭原则
    • 程序应该对修改关闭,对扩展开放
class Animal {
  constructor(name){
   this.name = name;
  }
  sayHello(){
    console.log(this.name + "在叫~~~");
  }
}

class Dog extends Animal {
  // 在子类中,可以通过创建同名方法来重新父类的方法
  sayHello(){
    console.log("汪汪汪");
  }
}

class Cat extends Animal {
  // 重写构造函数
  constructor(name, age){
    // 重写构造函数的第一行代码必须为super();
	super(name); // 调用父类的构造函数
	this.age = age;
  }
  
  sayHello(){
    // 调用一下父类的sayHello
	super.sayHello(); // 在方法中可以使用super来引用父类的方法
    console.log("喵喵喵");
  }
}

const dog = new Dog("旺财");
const cat = new Cat("汤姆", 3);
console.log(dog); // Dog: {name: "旺财"}
console.log(cat); // Cat: {name: "汤姆", age: 3}
dog.sayHello(); // 旺财在叫~~~   重写父类方法后:汪汪汪
cat.sayHello(); // 汤姆在叫~~~   重写父类方法后:喵喵喵

总结:封装(安全性)、继承(扩展性)、多态(灵活性)

6. 对象结构

对象中存储属性的区域实际有两个:
(1)对象自身

  • 直接通过对象所添加的属性
  • 在类中通过 x = y 的形式添加的属性

(2)原型对象(prototype)

  • 对象中还有一些内容,会存储到其他的对象里(原型对象)
  • 在对象中会有一个属性来存储原型对象,这个属性叫做 __proto__
  • 原型对象也负责为对象存储属性(当我们访问对象中的属性时,会优先访问对象自身的属性,如果对象自身不包含该属性时,才会去原型对象中寻找)
  • 会添加到原型对象中的情况:
    (1)在类中通过xxx(){}方式添加的方法
    (2)主动向原型中添加属性或方法
posted @ 2023-01-17 22:57  程序员张3  阅读(21)  评论(0编辑  收藏  举报