资讯专栏INFORMATION COLUMN

js对象的封装、继承和多态

Stardustsky / 1717人阅读

摘要:面向对象三大特性就是封装继承和多态,简单理解,对于猫这种动物,它本身就是一个封装好的类,你只需要供它吃喝输入,它就能表现猫的行为输出,同时它继承了动物所具有的习性吃东西等,而不同的猫因为所处环境或者习性的不同,可能会有不同的表现和行为,这就

面向对象三大特性就是封装继承和多态,简单理解,对于猫这种动物,它本身就是一个封装好的类,你只需要供它吃喝(输入),它就能表现猫的行为(输出),同时它继承了动物所具有的习性(吃东西等~),而不同的猫因为所处环境或者习性的不同,可能会有不同的表现和行为,这就是多态。

封装
把客观事物封装成抽象的类,隐藏属性和方法的实现细节,仅对外公开接口。

① 在ES6之前,没有class这个概念,借由原型对象和构造函数来实现

function Cat(name, food) {
  this.name = name // 公有属性
  this.food = food
}
Cat.prototype.say = function() { // 公有方法
  console.log(this.name + " likes eating " + this.food)
}
Cat.see = function() {
  console.log("这是静态方法,无需实例化可调用")
}
var cat = new Cat("Lazier","mouse")
cat.say() // 实例共享原型属性和方法

② ES6的class

class Cat{
  constructor(name, food){
    this.name = name
    this.food = food
  }
  static see() {
    console.log("这是静态方法,无需实例化可调用")
  }
  say(){
    console.log(this.name+" likes eating " + this.food)
  }
}
var cat = new Cat("Lazier","mouse")
cat.say()

以上class的基本实现原理如下 ↓

var Cat = function(){
  function Cat(name, food){
    this.name = name
    this.food = food
  }
  // 执行挂载函数,创建类
  createClass(Cat,[{key:"say",value:function(){
    console.log(this.name+" likes eating " + this.food)
  }}],[{key:"see",value:function(){
    console.log("这是静态方法,无需实例化可调用")}])
}

// 定义对象属性
let defineProperties = function(target, props) {
  for (var i = 0; i < props.length; i++) {
    var descriptor = props[i]
    Object.defineProperty(target, descriptor.key, descriptor)
  }
}   
// 挂载函数,将静态或动态方法分别挂载到Cat和Cat的prototype上
var createClass = function({
  return function(Constructor,protoProps,staticProps){
    if(protoProps){ // 原型方法
      defineProperties(Constructor.prototype,protoProps)
    }
    if(staticProps){ // 静态方法
      defineProperties(Constructor,staticProps)
    }
  }
})

了解面向对象的公有、私有、静态属性和方法可以看下面这篇文章的总结

js面向对象之公有、私有、静态属性和方法详解

继承
子类可以使用父类的所有功能,并且对这些功能进行扩展。继承的过程,就是从一般到特殊的过程。

js实现继承有多种方式

原型链继承

// 将子类的prototype指向父类的实例
function Parent(){}
function Son(){}
Son.prototype = new Parent()
// * 把Son的原型对象的constructor指向Son,解决类型判断问题
Son.prototype.constructor = Son
借助构造函数继承(使用call和apply实现继承)
function Parent(){}
function Son(){
    // 将父类函数中的this,强行绑定为子类的this
    // 可传参
    Parent.call(this, arguments);
}
组合继承
// 原型属性方法由原型链实现继承,实例属性方法由借用构造函数实现继承
// 这样,在原型上定义方法实现了函数复用,又保证每个实例都有它自己的属性
function Parent(name){
    this.name = name
}
function Son(name, age){
    // 继承父类的实例属性方法,之后再添加自己的实例属性方法
    Parent.call(this, name);
    this.age = age
}
Son.prototype = new Parent()
// 重写Son的原型对象
Son.prototype.constructor = Son

var demo = new Son("jacksonzhou", 23)
寄生式组合继承 – 现在最常用的继承方法
// 获得父类原型属性方法的副本,解决组合继承的属性重复问题
function inheritPrototype(son, parent) {
    var prototype = object(parent.prototype)
    prototype.constructor = son
    son.prototype = prototype
}

function Parent(name){
    this.name = name
}
function Son(name, age){
    Parent.call(this, name)
    this.age = age
}
Son.prototype = inheritPrototype(Son, Parent)

var demo = new Son("jacksonzhou", 23)

多态
同一操作用在不同对象上,可以产生不同的解释和不同的执行结果

var makeSound=function(animal){
  animal.sound()
}
// 声明狗的构造函数
var Dog=function(){}
Dog.prototype.sound=function(){
  console.log("汪汪汪")
}
// 声明猫的构造函数
var Cat=function(){}
Cat.prototype.sound=function(){
  console.log("喵喵喵")
}
// 分别调用他们的叫法
makeSound(new Dog())
makeSound(new Cat())
// 非多态写法
var makeSound=function(animal){
  if(animal instanceof Dog){
    console.log("汪汪汪")
  }else if(animal instanceof Cat){
    console.log("喵喵喵")
  }
}
var Dog=function(){}
var Cat=function(){}
// 分别调用他们的叫法
makeSound(new Dog())
makeSound(new Cat())
// 很明显,后续有其他动物加入都要去修改makeSound函数,很不优雅!
这里要介绍下方法重载

方法重载是让类以统一的方式处理不同类型数据的一种手段。表现为多个同名函数同时存在,但具有不同的参数个数或类型。调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法, 这也是一种多态性。

其实js本身并没有这个概念,但我们可以通过操作参数的类数组arguments,根据该类数组的长度以及其元素的类型来选择不同的实现,来模拟实现函数重载效果

// js的函数参数相当灵活~可理解成一个动态的类数组
// 不加参数,调用时有传入参数也不会报错
function countCat(){ 
  if(arguments.length==1){ 
    console.log(`这是一只猫,${arguments[0]}`)
  } 
  else if(arguments.length==2){ 
    console.log(`这是两只猫,${arguments[0]}和${arguments[1]}`)
  } 
  else{
    console.log("没猫了~")
  } 
} 
countCat()
countCat("Tom")
countCat("Tom","Mary")

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/106883.html

相关文章

  • js面向对象特征

    摘要:我们都知道面向对象拥有三大特征,分别为封装继承多态,其实在脚本语言中是不存在多态的,但是可以用的方式实现多态中的两种效果重载重写,那下面我们就来说一下面向对象的特征封装把抽象出的属性和对属性的方法封装在一起对外实现接口开放,说白了就是封装一 我们都知道js面向对象拥有三大特征,分别为封装、继承、多态,其实在javaScript脚本语言中是不存在多态的,但是可以用js的方式实现多态中的两...

    Jenny_Tong 评论0 收藏0
  • 浅谈JavaScript面向对象封装继承多态

    摘要:会造成内存浪费的问题构造函数继承声明父类声明子类生成实例组合式继承组合式继承是汲取了两者的优点,既避免了内存浪费,又使得每个实例化的子类互不影响。 写在前面 既然是浅谈,就不会从原理上深度分析,只是帮助我们更好地理解... 面向对象与面向过程 面向对象和面向过程是两种不同的编程思想,刚开始接触编程的时候,我们大都是从面向过程起步的,毕竟像我一样,大家接触的第一门计算机语言大概率都是C语...

    MAX_zuo 评论0 收藏0
  • 学习设计模式前需要知道事情

    摘要:为什么要学习设计模式做事情之前问个为什么总是好的。设计模式的使用方法关于使用方式,像我这种初学者最容易犯的错误就是生搬硬套,但是模仿本来也是学习的一个过程,最重要的事情是在模仿中要学会思考。 为什么要学习设计模式? 做事情之前问个为什么总是好的。关于设计模式的好坏,我在知乎上也看过一些讨论,有知友对其提出过一些疑问,里面有一些关于设计模式的观点: 设计模式有何不妥,所谓的荼毒体现在哪...

    kviccn 评论0 收藏0
  • SegmentFault 技术周刊 Vol.32 - 七夕将至,你对象”还好吗?

    摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...

    李昌杰 评论0 收藏0
  • SegmentFault 技术周刊 Vol.32 - 七夕将至,你对象”还好吗?

    摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...

    Lyux 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<