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

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

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


封装

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

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

JavaScript中创建对象的7种模式

ECMA-262把对象定义为:”无需属性的集合,其属性可以包含基本值、对象或者函数。对象的每个属性或方法都有一个名字,而每个名字都映射到一个值。正因为这样,我们可以把ECMAScript的对象想象成散列表:无非就是一组名对值,其中值可以是数据或函数。

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

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

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

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

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

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

JS声明对象时属性名加引号与不加引号的问题

JS声明对象时属性名加引号与不加引号的问题,一般情况下属性名加引号和不加引号是都可以的,效果是一样的。如果属性名是数字,则必须用“”包围,并且用 [] 方括号访问。

javascript的本地对象,内置对象和宿主对象

javascript的原生对象:也叫内部对象、本地对象、native object;内置对象:Global(全局对象)、Math ;宿主对象:有宿主提供的对象,在浏览器中window对象以及其下边所有的子对象(如bom、dom等等),在node中是globla及其子对象,也包含自定义的类对象。

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

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

JavaScript Error对象详解

error,指程序中的非正常运行状态,在其他编程语言中称为“异常”或“错误”。解释器会为每个错误情形创建并抛出一个Error对象,其中包含错误的描述信息。

如何禁止JavaScript对象重写?

由于JavaScript的灵活性,我们可以轻易地重写(override)一些于其他人定义的对象(object)。换句话说,任何人都可以重写我们所定义的对象。这是一个非常强大的特性,许多开发者都有兴趣试试,来拓展或者修改某些对象的行为。

JavaScript面向对象编程中_优雅的类写法

虽然现在已经是ES6的时代,但是,还是有必要了解下ES5是怎么写一个类的。本文详述JavaScript面向对象编程中的类写法,并分步骤讲述如何写出优雅的类。

点击更多...

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