ES6面向对象


面向对象的基础概念

类和对象

  • 类:具有相同属性和行为事物的统称。比如人、动物、鸟
  • 对象:类的具体的表现。比如老王对于人这个类来说是一个具体的表现。老王家的奔驰对于汽车来说是一个具体的表现。

关系

  • 类是对象的模板,对象是类的一个实例(具体表现)

属性和行为

  • 属性:指某个事物上的特征。比如对于人这个类来说,它的对象都有姓名、年龄、性别、籍贯、肤色、发色等属性。
  • 行为:指事物的动作的描述或具有的功能。比如对于人来说,有吃饭、睡觉、上厕所、唱、跳、rap等。

面向对象和面向过程

面向过程

  • 面向过程就是分析出解决问题的步骤,然后用方法实现每个步骤,按照流程依次调用方法,最后完成程序

面向对象

  • 是一种编程的思想。指以类和对象为核心来将程序拆分成多个模块,然后模块间相互调用来完成程序的一整套设计理念,用于替代面向过程

面向对象和面向过程的比较

  • 面向对象是多个模块进行处理,如果中间某个模块需要更改,其他模块可以直接进行复用。而面向过程如果中间的步骤需要更换,可能会整个流程需要重写书写
  • 低耦合:程序的一段代码更改之后不会影响到其他代码。
  • 维护性更高: 需要更新,面向对象直接加一个新的模块即可。但面向过程需要重新书写整个流程。

优劣对比

  • 面向过程:
    • 优点 :性能比面向对象高,因为类调用时要实例化,比较消耗资源。
    • 缺点:没有面向对象易维护,易复用,易扩展
  • 面向对象:
    • 优点:易维护,易复用,易扩展,面向对象具有封装,继承,多态的特性,可以设计出低耦合的系统,使系统更加灵活,更易于维护;
    • 缺点:性能比面向过程低

ES6面向对象

  • 类在程序中是以一种特殊的复合型的数据结构存在。类中包含了各种各样的属性和函数(行为).通过类可以创建对应的对象
  • 类是对象的抽象,对象是类的具体表现
  • ES6的面向对象的语法本质上相当于ES5面向对象的语法糖
  • ES6面向对象代码编译为ES5代码。默认生成一个IIFE,目的为了隔离作用域
  • ES5没有模块化编程,作用域分为全局作用域和函数作用域,模块作用域使用IIFE实现

创建类和对象

  • 创建类(class)

    class 类名{
        //构造器:
        constructor(){
            //添加属性
            this.属性名 = 属性值
        }
        // t添加行为
        函数名(){
        }
    }
    
  • 根据某个类创建对象

    let 变量名= new 类名();
    例子:
    let p1 = new People();
    

属性和行为

class People{
    constructor(name){
        this.name=name;
        //构造函数内行为
        this.job=function(){
            console.log(this.name);
        }
    }
    //构造函数外行为
    show(){
        console.log(this.name);
    }
}
  • 方法可以在构造器中定义,也可以在类中定义
  • 类中定义的方法,默认放在原型对象身上

构造器constructor()

constructor()方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor()方法,如果没有显式定义,一个空的constructor()方法会被默认添加。

class Point {
}

// 等同于
class Point {
  constructor() {}
}

作用

  • 完成对象属性的初始化
class 类名{
    constructor(参数1,参数2,参数n){
        this.属性名1= 参数1;
        this.属性名2= 参数2;
        this.属性名n= 参数n;
    }
}
let 变量名 = new 类名(实际参数1,实际参数2,实际参数n);

特点

  • 构造器只会在创建对象时自行调用一次。不可手动调用
  • new负责分配内存空间并生成原生对象的基本架构。构造器则负责该对象属性的初始化

this

  • 概念:this在面向对象中指的是当前创建出来对象本身。即当前对象
  • 用处
    • 能够在构造器中通过this.属性名来修改属性的值
    • 在行为中通过该this.属性名能够访问当前对象的某个属性

类属性(静态属性)

静态属性指的是Class本身的属性,通过类名来调用

所有对象都可以使用,即可以认为类属性是所有对象共享的。

  • 语法

    class 类名{
        static 变量名=;
        constructor(){}
    }
    //使用和修改
    类名.属性名
    类名.属性名=新数据
    

类属性和一般属性

  • 语法:类属性需要static. 一般的属性在constructor里通过this.属性名来使用
  • 调用:类属性是类本身来调用。一般属性是通过对象名.属性名或在类里通过this.属性名来调用
  • 应用:类属性作为对象的共享属性来使用,一般属性作为对象的私有属性来使用。

类行为(静态方法)

在函数前添加static关键字,就表示该方法不会被实例继承,而是直接通过类来调用

包含this关键字,指向类

  • 实例对象不能调用静态方法
  • 父类的静态方法,可以被子类继承

应用场景

  • 作为工具函数进行使用
    • 定义一个Random类,用于实现各种各样的随机数
    • 定义一个RegUtil类,用于定义常用的正则表达式即检测类方法

类行为(静态方法)和一般行为

  • 语法:类行为需要static. 一般的行为直接写函数名(){}即可
  • 调用:类行为是类本身来调用。一般行为通过对象来调用
  • 应用:类行为一般是作为工具方法来使用。一般行为是作为对象的一般函数来使用(偏向于业务)

面向对象特性

封装

封装是将内部的实现细节封装起来,向外暴露调用的接口例如:功能函数

  • 目的是将信息隐藏

划分

  • 数据封装
    • js当中只能依靠变量的作用域来实现封装的特性,并且只能模拟出public(公有)private(私有)两种特性。
    • 利用创建函数的作用域达到数据封装
  • 封装实现
    • 对象内部的变化对外界是透明的,不可见。这种做法使对象之间低耦合,便于维护升级,团队协作开发。

优点

降低耦合率 可重复调用类中的属性 提高安全性

继承

继承是子对象可以继承父对象的属性和行为,即父对象拥有的属性和行为,其子对象也就拥有了这些属性和行为

本质还是基于原型链的继承

  • 语法

    class Person {
        constructor(name) {
            this.name = name;
        }
    }
    //子类
    class Student extends Person {
        constructor(name) {
            super(name);
        }
    }
    

特点

  • extends关键字用于表示是哪一个类继承了父类,子类会拥有父类的行为。
  • super()是用于将父类里的属性赋给子类,调用父类的构造器,
  • 子类不会继承父类的类属性和类行为
  • 如果子类的属性都是来自于父类,那么子类的构造函数可以省略不写
  • 减少类的定义代码

super关键字

super这个关键字,既可以当作函数使用,也可以当作对象使用,ES6要求子类的构造函数必须执行一次super函数。

  • super作为函数调用时,代表父类的构造函数

  • super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。

class A {
  p() {
    return 2;
  }
}

class B extends A {
  constructor() {
    super();
    console.log(super.p()); // 2
  }
}

注意,使用super的时候,必须显式指定是作为函数、还是作为对象使用,否则会报错。

子类扩展

  • 子类除了可以使用父类的属性和行为之外,本身可以写自己的属性和行为。
  • 如果子类有自己的属性的话,那么需要自己书写构造函数

重写

  • 子类可以重新编写父类已经有的行为同名函数。这样程序在调用行为时,会优先调用子类已经重写的行为,如果没有重写,直接调用父类写的行为。
  • 重写是针对父类有的行为。子类自己扩展的行为不算重写。

多态

一种定义,多种实现,即在JavaScript中,一个行为传入不同类的对象,该行为会有不同的效果。天生具备多态

  • 实现多态的三个必要条件:
  1. 继承
  2. 重写
    通俗来讲就是同一个函数,因为传递的参数列表不同,可以实现的不同的功能

面向对象面试题

// 函数名字首字母大写,看成构造函数
function Cat(){
    let showName = function(){
        console.log(1);
    }
    console.log(this);
    return this
}
Cat.showName = function(){ console.log(2) }
Cat.prototype.showName = function(){ console.log(3) }
var showName = function(){
    console.log(4);
}
function showName(){
    console.log(5);
}
// 请说出下面代码的结果
Cat.showName()  //调用的是类属性,结果为2
showName()      //4
Cat().showName() //4
new Cat.showName() //2
new Cat().showName() //3
new new Cat().showName()  //3
  • 若没有通过关键字定义变量,则默认添加为window的属性
  • 原型对象new之后,才会创建原型对象
  • this 指向问题
  • 变量函数提升(预解析) 优先级 函数>变量

文章作者: 时光路人
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 时光路人 !
评论
  目录