美文网首页饥人谷技术博客
JS中的面向对象编程之继承机制

JS中的面向对象编程之继承机制

作者: charllote8 | 来源:发表于2018-01-29 15:21 被阅读32次

    一.面向对象编程
    面向对象编程(OOP--Object Oriented Programming)是一种抽象方式创建模型的编程方式。继承,封装,多态是OOP的三大基本特征。许多主流编程语言都支持OOP。例如Java,c++中通过new调用‘类’来创造实例,但是学习了JS的同学知道ES6之前中没有类的概念,那么JS怎么实现面向对象编程的呢?
    JS实现OOP是通过原型链实现的,原型链的概念在这里不详细讲述,大家记住一个例子即可:

    function._proto_ ==== Function.prototype
    

    JS也通过new来创建实例,但是后面调用的不是类,而是构造函数。
    下面我们通过封装继承一个‘类’的例子来详细阐述。
    二.ES5实现封装 继承一个类
    1.封装
    我们知道宝马,奔驰,奥迪等都是汽车,汽车这个概念就是一个类,抽象出来代表了日常生活中的许多具体事物。

    //汽车 构造函数
    function Car (name,color){
    this.name = name;
    this.color = color;
    }
    

    2.prototype模式
    汽车的属性有很多,不仅仅是名字和颜色,如果全部写在构造函数里,创建实例时再去一一地调用太过于麻烦,于是JS规定了一个prototype模式,每个构造函数都有一个prototype属性指向原型,“类”里面一些共有的属性可以放在原型里面。例如汽车类的车型,动能方式等属性都是共有属性可以放在原型里。

    Car.prototype.type = 'car';
    
    Car.prototype.getType = function () {
      return this.type;
    };
    
    Car.prototype.setType = function (newType) {
      this.type = newType;
      return newType;
    };
    
    Car.prototype.getName = function () {
      return this.name;
    };
    
    Car.prototype.setName = function (newName) {
      this.name = newName;
      return newName;
    };
    

    3.new关键字
    JS中通过new关键字创建实例。

     var car1 = new Car('宝马','red');
    console.log(car1.type) // 'car'
    

    这里,我们思考一个问题:使用new创建实例,new到底做了些什么呢?
    使用new创建实例,实际上是帮助我们减少了四行代码:
    1.new创建了临时对象,可以使用this访问到临时对象
    2.new也帮我们return了这个临时对象
    3.new指定了原型的名字--prototype
    4.new创建实例,自动绑定原型。

    car1._proto_ === Car.prototype
    

    4.继承
    我们实现一个‘子类’,继承‘汽车类’

    function SUV ( price) {
     Car.call(this, 'suv');   // 将 Car 类的属性和方法赋值给 SUV
      this.price = price;
    }
    
    SUV.prototype = new Car('suv');// 继承汽车类的原型链
    
    
    SUV.prototype.getPrice = function () {
      return this.price;
    };
    SUV.prototype.setPrice = function (newPrice) {
      this.price = newPrice;
      return newPrice;
    };
    
    //创建子类实例
    var suv1 = new SUV(1000);
    console.log(suv1.getPrice());//1000
    

    三. ES6实现封装继承一个类

    1.class封装一个类

    ES6中为了让JS与主流面向对象编程语言更相似,引入class(类)的概念,这其实是一个语法糖,本质上,ES6 的类只是 ES5 的构造函数的一层包装,因为class实现的ES5中也能实现。

    //类的基本语法
    class Car{
    constructor(){
    }
    Car = Car.prototype.constructor
    }
    var car  = new Car()
    

    class的实质是一个函数,里面默认必须定义一个构造函数,如果不写,默认添加一个空的构造函数。
    原型prototype在class上同样也适用,类本身就指向构造函数,使用时也是new一个类实例。
    类的写法也可以写成表达式的形式

    const BCar = class Car{
        constructor(){
       }
          }
    /*注意,在这里BCar才是类的真正名字, Car只能在类内部使用*/
    

    关于this,类中的this默认指向类的实例。

    2.继承一个类

    ES6中通过extends关键字继承父类。
    与es5不同的是,class中不存在变量提升,默认子对象必须在父对象之后定义。

    //SUV继承Car类
    class Car{
    constructor(color,type){
       this.color = color;
       this.type = type;
    }
    }
    class SUV extends Car{
    constructor(color,type,price){
      super(color,type){
        this.price =price}}
    
    }
    

    子类也必须拥有一个默认的构造函数
    super关键字
    子类在构造函数内通过super调用父类的构造函数,否则的话新建子类实例会报错。这也是与ES5不同之处,子类是继承了父类的this对象,然后进行修改。在super内部的this指向的是子类,然而静态方法中的super指向的是父类。
    static关键字
    与其他语言相似,如果在一个方法前添加static关键字,表示这个一个静态方法,实例不继承该方法,而是需要通过类来调用。同时需要注意,静态方法包含this关键字,这个this指的是类,而不是实例。
    类的prototype与proto

    class Car{
    constructor(color,type){
       this.color = color;
       this.type = type;
    }
    }
    class SUV extends Car{
    constructor(color,type,price){
      super(color,type){
        this.price =price}}
    
    }
    //////
    SUV._proto_ = Car
    SUV.prototype._proto_ =  Car.prototype
    

    实例的proto

    var car1 = newCar('red', 'fast');
    var suv1 = new SUV('red', 'fast', 2018);
    /////////
    car1._prpto_._prpto_ =  car1._prpto_
    
    
    3.提供私有方法和私有属性

    我们知道C++中的类有私有方法和私有属性,但是ES6中的类没有提供私有方法(仅供类内部使用,外部无法访问)只能变相通过别的方法来提供私有方法和私有属性
    --1.私有方法
    将私有方法的名字命名为一个Symbol值。

    const carO = Symbol('carO');
    const carT= Symbol('carT');
    
    export default class Car{
    
      // 公有方法
      test(car) {
        this[carO](car);
      }
    
      // 私有方法
      [carO](car) {
        return this[carT] = car;
      }
    
      // ...
    };
    

    --2.私有属性
    在属性名之前,使用#表示私有属性

    class Car {
      #price;
    
      constructor(price) {
       this.#price
      }
    
      get price() { return #price }
      set price(value) { ##price = +value }
    }
    ////price是私有属性,类外部访问不了
    

    以上是JS中的面向对象编程的简单介绍,如有错误,欢迎指出。
    参考链接:
    Javascript继承机制的设计思想--阮一峰

    相关文章

      网友评论

        本文标题:JS中的面向对象编程之继承机制

        本文链接:https://www.haomeiwen.com/subject/dmhxzxtx.html