理解JS中的类

330 阅读4分钟

作为一个前端小白白,本篇将从最基础的部分来说~

前言

​ 大多数面向对象的编程语言都支持类和类继承的特性,而JavaScript却不支持这些特性,因为JavaScript的创造者在设计JS语言时并没有借鉴从C, Java中关于类的部分,Javascript语言实际上是(简化的)函数式编程+(简化的)面向对象编程的混合产物,它不是真正的面向对象编程(OOP)语言,它的语法最初并没有class(类)。从ES1到ES5,开发者们都在使用着各种方法来实现类似的类特性,终于在ES6中引入了类的特性。

面向对象

要理解类,我们首先需要了解面向对象编程的思想。

​ 面向对象(Object Oriented)是一种新兴的程序设计方法,或者是一种新的程序设计规范(paradigm),其基本思想是使用对象、类、继承、封装、多态等基本概念来进行程序设计。从现实世界中客观存在的事物(即对象)出发来构造软件系统,并且在系统构造中尽可能运用人类的自然思维方式。

对象

​ 对象是系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位。一个对象由一组属性和对这组属性进行操作的一组服务(方法)组成。

类的实例化可生成对象,一个对象的生命周期包括三个阶段:生成、使用、消除。

​ 类是具有相同属性和方法的一组对象的集合,它为属于该类的所有对象提供了统一的抽象描述,其内部包括属性和方法两个主要部分。在面向对象的编程语言中,类是一个独立的程序单位,它应该有一个类名并包括属性和方法两个主要部分。

20210524103142.png

ES5中类的实现

​ ES5及早期版本中没有类的概念,实现近似类的方法就是创建一个自定义类型,首先创建一个构造函数,里面定义了类的属性,类的方法通过赋值给构造函数的原型来定义。最后,通过new操作符来创建一个类的实例,也就是对象。

// 构造函数
function Person(name, age) {
  this.name = name;
  this.age = age;
}
//给构造函数的原型添加方法
Person.prototype.running = function() {
  console.log(this.name + this.age + "running");
}
//实例化对象
var p = new Person("blend", 18);
p.running(); 

ES5中的继承

ES5的继承需要多个步骤才能实现,如下例:

// Shape - 父类(superclass)
function Shape( length,width) {
  this.length =length ;
  this.width = width;
}

// 父类的方法
Shape.prototype.getArea = function() {
  return this.length*this.width
};

// Rectangle - 子类(subclass)
function Rectangle(length) {
  Shape.call(this,length,length); // call super constructor.
}

// 子类续承父类
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?',
  rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?',
  rect instanceof Shape); // true
rect.getArea(1, 1); // Outputs, '1'

ES6中的类

​ ES6中引入了类的特性,可以直接使用class关键字进行类声明,但实际上ES6的类声明只是基于ES5中自定义类型声明的语法糖,typeof

Person 最终返回的结果是 function ,所以ES6中的类声明实际上创建了一个具有构造函数方法行为的函数。👉深入理解 JavaScript 中的 class

class Person {
    //等价于ES5中的构造函数
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
   //等价于Person.prototype.running
  running() {
    console.log(this.name + this.age + "running");
  }
   //静态方法
  static create(name,age){
        return new Person(name,age)
    }
}

const p = new Person("blend", 18);
p.running();

⚠️特点

  1. 在类中所有的方法都是不可以枚举的

  2. 必须通过关键字new来调用函数

  3. 可以使用static关键字来定义静态成员,静态方法只能通过类来直接调用,不能通过实例对象来调用

ES6中的继承

ES6中使用extends关键字来指定类继承的函数,使用super()方法即可以访问父类的构造函数。

//父类
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  running() {
    console.log(this.name, this.age, "running");
  }
}
//子类
class Student extends Person {
  constructor(name, age, sno, score) {
    super(name, age);
    this.sno = sno;
    this.score = score;
  }

  studying() {
    console.log(this.name, this.age, this.sno, this.score, "studing");
  }
}
const stu = new Student1("why", 18, 110, 100);
stu.studying();

❗️ 注意

  1. 在constructor中,子类必须通过super来调用父类的构造方法,对父类进行初始化,否则会报错。
  2. 在构造函数访问this之前一定要调用super( ),它负责初始化this。

私有变量

​ ES6 中 class 的出现拉近了 JS 和传统 OOP 语言的距离。但是在其中,比较大的一个问题就是私有变量问题,私有变量就是只能在类内部访问的变量,外部无法访问的变量。ES6中如何实现?

可以参考下面这些博客来读一读:

👉 JavaScript 中的私有变量

👉ES6 系列之私有变量的实现