第五章 原型模式——JavaScript的灵魂

语言中的原型

JavaScript中的继承是靠原型链实现的,而原型模式就是将原型对象指向创建对象的类,使这些类共享原型对象的方法与属性,而不是对属性和方法的复制。

原型继承实例

不使用原型实现继承

首先我们来假设一个场景:车的类型有很多,比如卡车、公交车、轿车、火车等。每种车都有不同的价格和速度以及功能。那现在就以交通工具为父类,轿车和卡车为子类,实现继承。


// 交通工具类
    var Vehicle = function(price,speed){
    
    
      this.price = price
      this.speed = speed
      this.getPrice = function(){
    
    
        return this.price
      }
      this.changePrice = function(){
    
    
      }
    }
    // 汽车类
    var Car = function(price,speed){
    
    
      // 构造函数继承交通工具类
      Vehicle.call(this,price,speed)
      // 重写修改价格方法,打9折
      this.changePrice = function(){
    
    
        return this.price * 0.9
      }
    }
    // 卡车类
    var Truck = function(price,speed,weight){
    
    
      // 构造函数继承交通工具类
      Vehicle.call(this,price,speed)
      // 添加卡车私有变量
      this.weight = weight
      // 重写修改价格方法,打9折
      this.changePrice = function(){
    
    
        return this.price * 0.8
      }
    }

    // 实例化一个汽车类
    var BMW = new Car(6000000,100)
    console.log('宝马')
    console.log(BMW.changePrice()) 

    console.log('奔驰')
    var BenzTruck = new Truck(1000000,200,150)
    console.log(BenzTruck.price)
    console.log(BenzTruck.speed)
    console.log(BenzTruck.weight)
    console.log(BenzTruck.changePrice())

在这里插入图片描述

我们发现直接使用构造函数继承,将Vehicle(交通工具)为基类,是可以实现继承的。但是这样也会有一些问题,就是每次子类继承都要创建一次父类,当父类构造函数创建时存在很多耗时较长的逻辑,或者说每次创建的时候都要进行一些重复性的操作,这样其实对性能的消耗是挺大的。
所以我们才需要引入一种共享机制,这样每当创建基类时,我们将一些简单又差异化的属性可以直接放在构造函数中(比如this.price = price),而将一些消耗资源比较大的方法放在基类的原型中,这样我们就会避免很多不必要的消耗。

原型模式

// 交通工具类
    var Vehicle = function(price,speed){
    
    
      this.price = price
      this.speed = speed
    }
    Vehicle.prototype = {
    
    
      getPrice:function(){
    
    
        return this.price
      },
      changePrice:function(){
    
    
      }
    }
    // 汽车类
    var Car = function(price,speed){
    
    
      // 构造函数继承交通工具类
      Vehicle.call(this,price,speed)
      // 重写修改价格方法,打9折
      this.changePrice = function(){
    
    
        return this.price * 0.9
      }
    }
    Car.prototype = new Vehicle()
    // 卡车类
    var Truck = function(price,speed,weight){
    
    
      // 构造函数继承交通工具类
      Vehicle.call(this,price,speed)
      // 添加卡车私有变量
      this.weight = weight
      // 重写修改价格方法,打9折
      this.changePrice = function(){
    
    
        return this.price * 0.8
      }
    }
    Truck.prototype = new Vehicle()

    // 实例化一个汽车类
    var BMW = new Car(6000000,100)
    console.log('宝马')
    console.log('继承的原型方法',BMW.getPrice())
    console.log('重写的原型方法',BMW.changePrice()) 

    console.log('奔驰')
    var BenzTruck = new Truck(1000000,200,150)
    console.log(BenzTruck.price)
    console.log(BenzTruck.speed)
    console.log(BenzTruck.weight)
    console.log(BenzTruck.changePrice())

在这里插入图片描述
下面的这两段代码就是原型继承的精髓了。

Vehicle.prototype = {
    
    
      getPrice:function(){
    
    
        return this.price
      },
      changePrice:function(){
    
    
      }
    }
Car.prototype = new Vehicle()

原型继承

原型模式更多的是用在对对象的创建上,当创建一个实例对象的构造函数比较特殊,或者要继承多个基类时,此时最好不要用new关键字取复制这些基类,但可以通过对这些对象属性或者复制来实现创建。

function prototypeExtend(){
    
    
 // 缓存类
   let F = function(){
    
    }
   for(let i = 0;i < arguments.length;i++){
    
    
     // 遍历各个模版对象的属性
     for(let key in arguments[i]){
    
    
       // 将这些属性复制到缓存类原型中
       F.prototype[key] = arguments[i][key]
     }
   }
   // 返回一个原型对象的实例
   return new F()
 }

 var plugin = prototypeExtend(
   {
    
    
     price:100,
     changePrice:function(){
    
    
       return this.price * 0.9
     }
   },
   {
    
    
     speed:150,
     changeSpeed:function(){
    
    
       console.log('提不了速了!')
     }
   },
   {
    
    
     weight:200
   }
 )

 console.log(plugin.changePrice())
 plugin.changeSpeed()
 console.log(plugin.weight)

在这里插入图片描述

什么时候用原型继承

**原型模式可以让多个对象分享同一个原型对象的属性和方法,这也是一种继承方式,这种继承方式的实现是不需要创建的,而是将原型对象分享给那些继承的对象。**当然有时候每个继承对象独立拥有一份原型对象,此时我们就需要对原型对象进行复制。
由此可以看出,原型对象更适合在创建复杂的对象时,对于那些需要 一直在变化而导致对象结构不停改变时,将那些比较稳定的属性与方法共用而提取的继承实现。

谈谈“原型继承的实现不需要了解创建的过程”的理解

通过以上的学习,我们可以知道原型继承的关键就是将父类的实例赋值给子类的原型prototype,而我们在实例化子类时,是不会对prototype进行new的操作的。换句话说,原型继承的精髓就是让子类的实例共享prototype上的属性和方法,减少消耗,而非重新复制或者创建一个新的对象,这也是原型继承的最初思想。

下一章 单例模式

猜你喜欢

转载自blog.csdn.net/qq_39055970/article/details/115985587