ES6专题— class与面向对象编程

栏目: JavaScript · 发布时间: 6年前

内容简介:在ES5中,我们经常使用方法或者对象去模拟类的使用,并基于原型实现继承,虽然可以实现功能,但是代码并不优雅,很多人还是倾向于用 class 来组织代码,很多类库、框架创造了自己的 API 来实现 class 的功能。ES6 时代终于有了 class (类)语法,能让我们可以用更简明的语法实现继承,也使代码的可读性变得更高,同时为以后的JavaScript语言版本添加更多的面向对象特征打下基础。有了ES6的class 以后妈妈再也不用担心我们的代码乱七八糟了,这简直是喜大普奔的事情。ok,我们看看神奇的cla

在ES5中,我们经常使用方法或者对象去模拟类的使用,并基于原型实现继承,虽然可以实现功能,但是代码并不优雅,很多人还是倾向于用 class 来组织代码,很多类库、框架创造了自己的 API 来实现 class 的功能。

ES6 时代终于有了 class (类)语法,能让我们可以用更简明的语法实现继承,也使代码的可读性变得更高,同时为以后的JavaScript语言版本添加更多的面向对象特征打下基础。有了ES6的class 以后妈妈再也不用担心我们的代码乱七八糟了,这简直是喜大普奔的事情。ok,我们看看神奇的class.

一、 类的定义

1.1 ES5 模拟类定义

function Person( name , age ) {
    this.name = name;
    this.age = age;
}
Person.prototype.say = function(){
    return '我叫' + this.name + ',今年' + this.age + '岁';
}
var  p = new Person('大彬哥',18);  // Person {name: "大彬哥", age: 18}
p.say()                           //"我叫大彬哥,今年18岁"

使用ES5语法定义了一个Person类,该类有name和age两个属性和一个原型say方法。

这种写法跟传统的面向对象语言(比如 C++ 和 Java)差异很大。接下来我们看下ES6 类的写法,这个就很接近于传统面向对象语言了。如果你想了解传统面向对象语言,这里是一个好切入点。

1.2 ES6 class类定义

class Person {
  constructor( name , age ) {
    this.name = name;
    this.age = age;
  }
  say() {
    return '我叫' + this.name + ',今年' + this.age + '岁';
  }
}
var  p = new Person('大彬哥',18);  // Person {name: "大彬哥", age: 18}
p.say()                           //"我叫大彬哥,今年18岁"

上面代码定义了一个同样的Person类,constructor方法就是构造方法,而this关键字则代表实例对象,这更接近传统语言的写法。

注意:

虽然引入了class关键字,但ES6中并没有真的引入类这个概念,通过class定义的仍然是函数:

console.log(typeof Person); // 'function'

所以说,class仅仅是通过更简单直观的语法去实现原型链继承。这种对语言功能没有影响、但是给 程序员 带来方便的新语法,被称为语法糖。

ES6专题— class与面向对象编程

二、类的传参 constructor

在类的参数传递中我们用constructor( )进行传参。传递参数后可以直接使用this.xxx进行调用。

class Person {
   constructor(a,b){
        this.a=a;
        this.b=b;
   }
   add(){
        return this.a + this.b;
   }
}
let p = new Person(18,30);
console.log(p.add());  // 48 (18+30)

我们用constructor来传递参数,然后用了一个add方法,把参数相加。这和以前我们的函数传参方法有些不一样,所以小伙伴们要注意转换下思维。

三、静态方法

在面向对象语言中,静态方法是指不需要实例化,可以通过类名直接调用的方法,但静态方法不会继承到类实例中,因此静态方法经常用来作为 工具 函数。比如我们经常用的Math.random(),我们并不需要先new 一个Math然后再去用,一是如果作者那么设计JS一来是没必要,二是用起来太繁琐。

在使用函数模拟类时,可以像下面这样定义静态方法:

function Person(name, sex) {}

Person.walk = function() {
    console.log('我会走路')
}

Person.walk();  // 我会走路
var person = new Person();
person.walk();  // TypeError

在ES6 class类定义中,可以使用static关键字定义:

class Person {
  constructor() {}

  static walk(){
      console.log('我会走路')
  }
}
Person.walk();  // 我会走路
var person = new Person();
person.walk();  // TypeError

static关键字是ES6的另一个语法糖,static 使静态方法声明也成为了一个一等公民。

于此同时,静态方法也是可以从子类中的super对象上调用的。

class Person {
  constructor() {}

  static walk(){
      return '我会走路'
  }
}

class People extends Person {
  static walk() {
    return super.walk() + ', 我还会跑步';
  }
}

People.walk();  //"我会走路, 我还会跑步"

四、封装与继承

封装和继承,是面向对象编程三大核心特征中非常重要的两个,封装和继承在我们实际生活中也有非常多的应用。举个例子,你去驴肉火烧店去吃饭。

老板把驴肉面和火烧一起买,起名字叫“精英驴火套餐”,这就是封装。

而进去以后跟老板说,老板给我来个“82年的驴火套餐”这就是继承。当然了你不仅仅能继承,还能扩展自己的功能。比如你可以跟老板说,老板再给我加一个驴板肠。说的我都饿了,不过我们还是教编程的专栏,不是开店的专栏,我们继续,看看ES6里面怎么玩继承。

4.1 extends

旧的原型继承有时看起来让人非常头疼。

function Child(firstName, lastName, age) {
  Parent.call(this, firstName, lastName)
  this.age = age
}

Child.prototype = Object.create(Parent.prototype)
Child.constructor = Child

ES6中新的extends关键字解决了这个问题:

class Child extends Parent {}

上面代码定义了一个Child类,该类通过extends关键字,继承了Parent类的所有属性和方法。

由于没有在Child内部写任何代码,所以这两个类完全一样,等于复制了一个Parent类。

之后,我们在Child内部加上代码:

class Child extends Parent {
  constructor(firstName, lastName, age) {
    super(firstName, lastName)  
    // 调用父类的constructor(firstName, lastName)
    this.age = age
  }
  speak(){
    return this.age + ' ' + super.speak(); 
    // 调用父类的speak()
  }
}

使用简介的 extends 达到继承的目的,而非杂乱的 Object.create()、.proto、Object.setPrototypeOf(),这样能让我们更顺利的扩充功能。

ES6专题— class与面向对象编程

4.2 super

super这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。

(1)super作为函数调用

代表父类的构造函数,ES6中规定,子类的构造函数必须执行一次super函数。

class A {}

class B extends A {
  constructor() {
    super();
  }
}

上面代码中,子类B的构造函数之中的super(),代表调用父类的构造函数,这是必须的,否则 JavaScript 引擎会报错。

注意,super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B,因此super()在这里相当于A.prototype.constructor.call(this)。

(2)super作为对象时,指向父类的原型对象。

class A {
  p() {
    return 2;
  }
}

class B extends A {
  constructor() {
    super();
    console.log(super.p()); // 2
  }
}

let b = new B();

Java 一样,JavaScript也使用extends关键字实现继承,子类中可以通过super关键字调用父类:

在 constructor 里面,super 的用法是 super()。它相当于一个函数,调用它等于调用父类的 constructor 。

但在普通方法里面,super 的用法是 super.prop 或者 super.method(),它相当于一个指向对象的 [[Prototype]] 的属性。

4.3 getter(取值函数)、 setter(存值函数)

与 ES5 一样,在“类”的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。

class Person {
  constructor() {}
  get prop() {
    return 'getter';
  }
  set prop(value) {
    console.log('setter: '+value);
  }
}

let p = new Person();
p.prop = 666;   // setter: 666
p.prop           // 'getter'

五、总结

ES6专题— class与面向对象编程

无论学什么知识,最重要也是最基础的,要实现思想上的转变,目前大部分框架和库,都采用了面向对象方式编程。而且在工作中,要书写中型和大型的项目也经常使用面向对象方式编程,可能大家习惯了面向过程方式编程,其实面向对象方式编程一旦习惯了,会让我开发和思路更宽阔和易于开发项目。

从学习javascript基础开始的时候,我们就了解了js中的保留字,js中并没有用到,但是将来可能会用到的未来关键字。这些保留字中就包括:class、extends、super。这些就是为将来在js中支持面向对象的类机制而预留的。

果不其然,现在ES6语法中使用到了这些保留字,这些保留字成功升级成了关键字,可见当时javascript的设计者还是很有前瞻眼光的。

通过这些新的关键字,使类成为了JS中一个新的一等公民。但是目前为止,这些关于类的新关键字仅仅是建立在旧的原型系统上的语法糖。这样做的原因是为了保证向后兼容性。也就是,旧代码可以在不做任何hack的情况下,与新代码同时运行。

不过,它使代码的可读性变得更高,并且为今后版本里更多面向对象的新特性打下了基础。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Usability for the Web

Usability for the Web

Tom Brinck、Darren Gergle、Scott D. Wood / Morgan Kaufmann / 2001-10-15 / USD 65.95

Every stage in the design of a new web site is an opportunity to meet or miss deadlines and budgetary goals. Every stage is an opportunity to boost or undercut the site's usability. Thi......一起来看看 《Usability for the Web》 这本书的介绍吧!

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具