JavaScript 与 OOP

Posted GoldenaArcher

tags:

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

javascript 与 OOP

面向对象编程(Objected- Oriented Programming,OOP)是一种以对象和类为基础进行开发的编程思想,主要核心组成部分有四个:

  1. 属性(attributes)

    可以代表其状态(state)的变量(variables)

  2. 函数(methods)

    可以代表其行为(behavior),函数可以直接操纵类的属性,可以接受参数,返回值,用于实现对类的操作

  3. 类(classes)

    包含状态(states)与行为(behaviors)

  4. 对象(objects)

    对象的定义为 创建类的蓝图

OOP 的四大原则包涵:

  • 封装 Encapsulation
  • 抽象 Abstract
  • 继承 Inheritance
  • 多态 Polymorphism

封装 Encapsulation

封装的主要用途在于不暴露数据的操作与数据本身,以 Movie 这个类为例,它可以包含 3 个属性:电影名(title)、年(year)与类别(genre)。

JavaScript

class Movie 
  #title = '';
  #year = -1;
  #genre = '';

  // constructor
  constructor(t = '', y = -1, g = '') 
    this.title = t;
    this.year = y;
    this.genre = g;
  

  set title(t) 
    this.#title = t;
  

  get title() 
    return this.#title;
  

  set year(y) 
    this.#year = y;
  

  get year() 
    return this.#year;
  

  set genre(g) 
    this.#genre = g;
  

  get genre() 
    return this.#genre;
  

  printDetails() 
    console.log('Title: ', this.title);
    console.log('Year: ', this.year);
    console.log('Genre: ', this.genre);
  


const movie = new Movie('The Lion King', 1994, 'Adventure');
movie.printDetails();

console.log('---');
movie.title = 'Forrest Gump';
console.log('New title: ', movie.title);

运行结果:

这是一个至少 ES6 以后的写法,其中 #attributes 的写法代表了私有变量,这也意味着实例化的对象无法直接访问该变量,如:

而可以直接获取 movie.genre 则是依赖于 setter/getter 的实现,如果类中没有 getter 的实现,那么输出就会直接变成 undefined:

修改私有属性值也依赖于 setter:

可以说 private properties 让 JS 的 OOP 实现更贴合其他语言的实现,也更有意义了——不然都是 public,就算会约定俗成的使用 _properties 代表私有属性,也可能会引起滥用。

TypeScript

class Movie 
  private _title: string;

  constructor(title = '', private year = -1, private genre = '') 
    this.title = title;
  

  public get title() 
    return this._title;
  

  public set title(t: string) 
    this._title = t;
  

  printDetails() 
    console.log('Title: ', this.title);
    console.log('Year: ', this.year);
    console.log('Genre: ', this.genre);
  


const movie = new Movie('The Lion King', 1994, 'Adventure');
movie.printDetails();

console.log('---');
movie.title = 'Forrest Gump';
console.log('New title: ', movie.title);

TS 的变量名其实会稍微有点麻烦,如果用构造函数的缩写,那么 getter/setter 就会有重复变量的问题:

封装的另一个好处就在于属性的获取方式会变得更简单一些,比如说获取一些需要转换的值,可以直接在 setter/getter 中进行计算:

继承 Inheritance

先把继承提出来是因为抽象要用。

继承主要有的一个 IS-A 的关系,即子类是复类的一种,如车是一种载具,鸟是一种动物等。

继承的方式主要有以下几种:

  • 单独继承 Single Inheritance

    Fuel Vehicle Vehicle

    即 燃油车 继承载具。

  • 多继承 Multiple inheritance

    Fuel Vehicle Electric Vehicle Hybrid Vehicle

    这里混合汽车继承了油车,也继承了电车。

    目前我接触到的语言……好像只有 C++ 支持多继承。

  • 多重继承 Multi-level inheritance

    Fuel Vehicle Vehicle Gas Vehicle

    这里 汽油车 继承 燃油车。

  • 层次继承 Hierarchical inheritance

    Fuel Vehicle Vehicle Electric Vehicle

    这里油车电车都继承了载具。

  • 混合继承 Hybrid inheritance

    混合继承是多继承+多层继承的组合

    Fuel Vehicle Vehicle Hybrid Vehicle Electric Vehicle

JavaScript

// Base class (Parent)
class Vehicle 
  constructor(name, model) 
    this.name = name;
    this.model = model;
  

  getName() 
    return 'The car is a ' + this.name + ' ' + this.model;
  


// Single inheritance
// FuelCar class extending from Vehicle class
// Derived class (Child)
class FuelCar extends Vehicle 
  constructor(name, model, combustType) 
    super(name, model);
    this.combustType = combustType;
  
  getFuelCar() 
    return this.getName() + ', combust type is ' + this.combustType;
  


// Hierarchical inheritance
// Alongside the FuelCar class, the ElectricCar class is also extending from Vehicle class
// Another Derived class (Child)
class ElectricCar extends Vehicle 
  constructor(name, model, batteryPower) 
    super(name, model);
    this.batteryPower = batteryPower;
  
  getElectricCar() 
    return this.getName() + ', battery power is ' + this.batteryPower;
  


// Multi-level inheritance
// GasolineCar class is derived from the FuelCar class, which is further derived from the Vehicle class
// Derived class (Grandchild)
class GasolineCar extends FuelCar 
  constructor(name, model, combustType, gasCapacity) 
    super(name, model, combustType);
    this.gasCapacity = gasCapacity;
  
  getGasolineCar() 
    return this.getFuelCar() + ', gas capacity is ' + this.gasCapacity;
  


// JavaScript does not support Multiple inheritance via classes

// main
console.log('Single inheritance:');
let Fuel = new FuelCar('Tesla', 'ModelX', '200MWH');
console.log(Fuel.getFuelCar());
console.log(' ');

console.log('Hierarchical inheritance:');
let Electric = new ElectricCar('Honda', 'Accord', 'Petrol');
console.log(Electric.getElectricCar());
console.log(' ');

console.log('Multi-Level inheritance:');
let Gasoline = new GasolineCar('Toyota', 'Corolla', 'Gasoline', '300MWH');
console.log(Gasoline.getGasolineCar());
console.log(' ');

console.log('JavaScript does not support Multiple inheritance via classes');

TypeScript

TS 的实现和 TS 没什么区别,不过这里因为用了缩写,所以代码量可以稍微少一点点。

// Base class (Parent)
class Vehicle 
  constructor(private name: string, private model: string) 
  getName() 
    return 'The car is a ' + this.name + '

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

JavaScript 与 OOP

JavaScript OOP Javascript模板与构造函数和继承

重型柴油车SAE J1939总线数据结构分析及应用

重型柴油车SAE J1939总线数据结构分析及应用

javascript OOP类与对象

JavaScript 精粹 基础 进阶OOP面向对象编程(上)