美文网首页
使用es6新的class语法来体验js的面向对象编程

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

作者: 剑来___ | 来源:发表于2018-12-25 17:13 被阅读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());
    

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

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

    • 基于类的面向对象
      在基于类的面向对象语言中(比如Java和C++), 是构建在类(class)和实例(instance)上的。其中类定义了所有用于具有某一特征对象的属性。类是抽象的事物, 而不是其所描述的全部对象中的任何特定的个体。另一方面, 一个实例是一个类的实例化,是其中的一个成员。

    • 基于原型的面向对象
      在基于原型的语言中(如JavaScript)并不存在这种区别:它只有对象!不论是构造函数(constructor),实例(instance),原型(prototype)本身都是对象。基于原型的语言具有所谓的原型对象的概念,新对象可以从中获得原始的属性。

    所以,在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方法,他们通过函数覆盖实现了多态。

    相关文章

      网友评论

          本文标题:使用es6新的class语法来体验js的面向对象编程

          本文链接:https://www.haomeiwen.com/subject/ewpflqtx.html