使用es6新的class语法来体验js的面向对象编程

2018-12-25  本文已影响14人  剑来___

今天在看一本书,只有小小的一百多页,半天快看完半本了,名字叫《学习JavaScript数据结构预算法》.看下来的感受就是,短小精悍,适合复习一下大学学的数据结构。
在读到使用js实现栈的结构的时候,看到它的写法是之前的构造函数继承的写法,突发奇想,想用es6的语法改写一下试试,这是书上的写法:

function Stack() {
  var items = []

  this.push = function(element) {
    items.push(element)
  }
  this.pop = function() {
    return items.pop()
  }
  this.peek = function() {
    return items[items.length - 1]
  }
  this.isEmpty = function() {
    return items.length === 0
  }
  this.size = function() {
    return items.length
  }
  this.clear = function() {
    items = []
  }
  this.print = function() {
    console.log(items.toString());
  }
}

算不上是类的写法,只是在函数里定义了几个方法,去修改items的值而已,新写的写法如下:

class Strack {
  constructor() {
    this.item = []
  }

  // 栈的压入
  push(value) {
    this.item.push(value)
  }

  // 栈的弹出
  pop() {
    this.item.pop()
  }

  // 返回栈顶元素
  peek() {
    let lengthTemp = this.item.length
    return this.item[lengthTemp - 1]
  }

  // 判空
  isEmpty() {
    return this.item.length === 0
  }

  // remove all

  clear() {
    this.item = []
  }

  // sum all items
  size() {
    return this.item.length
  }
}

export default Strack

使用:

 const newStrack = new Strack()
    newStrack.push(1)
    newStrack.push(2)
    newStrack.push(3)
    newStrack.pop()
    console.log(newStrack, newStrack);
    console.log('newStrack is empty? : ', newStrack.isEmpty());

很简单,但是没有弄清楚,这样写和以前的写法有什么的本质的区别,这一点需要去研究一下。

基于类的面向对象和基于原型的面向对象

所以,在JavaScript中有一个很有意思的proto属性(ES6以下是非标准属性)用于访问其原型对象, 你会发现,上面提到的构造函数,实例,原型本身都有proto指向原型对象。其最后顺着原型链都会指向Object这个构造函数,然而Object的原型对象的原型是null,不信, 你可以尝试一下Object.prototype.proto === null为true。然而typeof null === 'object'为true。到这里, 我相信你应该就能明白为什么JavaScript这类基于原型的语言中没有类和实例的区别, 而是万物皆对象!

封装

js实现封装的办法和java其实差不多

function Person(name) {
  this.name = name
  var smallName = 'xiaoming'
}
Person. prototype.sayHi = function() {
  console.log('hello')
}

上面代码,定义了一个私有变量smallName和一个方法sayHi,我们并不能通过实例化Person去访问smallName,还有我们也不知道sayH是怎么实现的,这样就实现了封装。

继承和多态

在es6以前,我最常使用的继承方式是使用protutype

function Person(name) {
    this.name = name
    this.career = function() {
      console.log('I am a Person' + name)
    }
  }
  Person.prototype.sayHi = function () {
    console.log('my name is ' + this.name);
  }

  function Teacher(career) {
    this.career = function() {
      console.log('I am a ' + career + ', my name is ' + this.name)
    }
  }
  Teacher.prototype = new Person('Ma')
Teacher.prototype.constructor = Teacher

  var personOne  = new Person('Zhang')
  personOne.career()

  var teaMa = new Teacher('math')
  console.log(teaMa);
  teaMa.career()

Person是一个父类,子类Teacher想要继承父类,就在它的prototype指向变为一个新的父类实例,同时将prototype的constructor属性指向自己,如果constructor属性不指回自己的话,将会导致

console.log(teaMa.constructor === Person)  // true

这是一个重大错误,明明是Teacher实例化出来的,结果显示父类实例化的......
新实例化的Teacher有父类的name属性,这就实现了继承,同时Person和Teacher类都有career方法,他们通过函数覆盖实现了多态。

上一篇下一篇

猜你喜欢

热点阅读