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

更新日期: 2019-07-22 阅读: 2.7k 标签: 对象

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


封装

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

① 在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://fly63.com/article/detial/4879

相关推荐

js获取object对象的长度

我们都知道必须是具体数据类型才有长度,所以size和length都无法测量object对象的长度,那么如何计算对象的长度,即获取对象属性的个数呢?

JavaScript数组、对象合并的多种方法实现

这篇文章讲解Js数组和对象的一些使用技巧,如何将不同的数组,对象合并/结合为1个的方法

js中关于for...in遍历对象属性的顺序问题

对象使用obj.length时,它得到的值是undefined的,所以只能通过for...in循环获取对象的属性,我们发现并没有按属性的顺序显示,而且顺序在各个浏览器下显示也不同。 这是为什么呢?

JavaScript 判断对象中是否有某属性

判断对象中是否有某属性的常见方式总结,不同的场景要使用不同的方式。一点( . )或者方括号( [ ] )、二in 运算符、三hasOwnProperty()。三种方式各有优缺点,不同的场景使用不同的方式,有时还需要结合使用

JS 的 Document对象

Document 对象是是window对象的一个属性,因此可以将document对象作为一个全局对象来访问。当浏览器载入 HTML 文档, 它就会成为 Document 对象。Document对象的 属性和方法

Js通过.或者[]访问对象属性的语法、性能等区别

在JavaScript中可以使用 . 或者 [ ] 来访问对象的属性,但是对象中方法只能通过 . 来获取;使用.运算符来存取对象的属性的值。或者使用[]作为一个关联数组来存取对象的属性。但是这两种方式有什么区别了?

history对象详解及单页面路由实现

history对象保存着用户的上网记录,从浏览器窗口打开的那一刻算起。出于安全的考虑,开发人员无法得知用户浏览过的URL。不过,借由用户访问过的页面列表,同样可以在不知道实际URL的情况下实现后退与前进

js对象 对属性调用.和[] 两种方式的区别

在 JS 对象中,调用属性一般有两种方法——点和中括号的方法。 标准格式是对象.属性(不带双引号),注意一点的是:js对象的属性,key标准是不用加引号的,加也可以,特别的情况必须加,如果key数字啊,表达式啊等等

javascript中document是什么?

javascript中document是window对象的属性,表示对Document对象的只读引用。Document对象是Window对象的一部分,可通过window.document属性对其进行访问。

Js中Blob是什么?

MDN给出的解释:Blob 对象表示一个不可变、原始数据的类文件对象;创建一个blob只有两种方式1、通过new Blob();使用blob.slice切割,创建一个新的blob对象;读取blob唯一方式,使用fileReader

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!