在ES5中,咱们常用方法或者对象去模拟类的使用,并基于原型实现继承,虽然能够实现功能,可是代码并不优雅,不少人仍是倾向于用 class 来组织代码,不少类库、框架创造了本身的 API 来实现 class 的功能。javascript
ES6 时代终于有了 class (类)语法,能让咱们能够用更简明的语法实现继承,也使代码的可读性变得更高,同时为之后的JavaScript语言版本添加更多的面向对象特征打下基础。有了ES6的class 之后妈妈不再用担忧咱们的代码乱七八糟了,这简直是喜大普奔的事情。ok,咱们看看神奇的class.java
1、 类的定义程序员
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 类的写法,这个就很接近于传统面向对象语言了。若是你想了解传统面向对象语言,这里是一个好切入点。dom
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定义的仍然是函数:this
console.log(typeof Person); // 'function'
因此说,class仅仅是经过更简单直观的语法去实现原型链继承。这种对语言功能没有影响、可是给程序员带来方便的新语法,被称为语法糖。
2、类的传参 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方法,把参数相加。这和之前咱们的函数传参方法有些不同,因此小伙伴们要注意转换下思惟。
3、静态方法
在面向对象语言中,静态方法是指不须要实例化,能够经过类名直接调用的方法,但静态方法不会继承到类实例中,所以静态方法常常用来做为工具函数。好比咱们常常用的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(); //"我会走路, 我还会跑步"
4、封装与继承
封装和继承,是面向对象编程三大核心特征中很是重要的两个,封装和继承在咱们实际生活中也有很是多的应用。举个例子,你去驴肉火烧店去吃饭。
老板把驴肉面和火烧一块儿买,起名字叫“精英驴火套餐”,这就是封装。
而进去之后跟老板说,老板给我来个“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(),这样能让咱们更顺利的扩充功能。
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'
5、总结
不管学什么知识,最重要也是最基础的,要实现思想上的转变,目前大部分框架和库,都采用了面向对象方式编程。并且在工做中,要书写中型和大型的项目也常用面向对象方式编程,可能你们习惯了面向过程方式编程,其实面向对象方式编程一旦习惯了,会让我开发和思路更宽阔和易于开发项目。
从学习javascript基础开始的时候,咱们就了解了js中的保留字,js中并无用到,可是未来可能会用到的将来关键字。这些保留字中就包括:class、extends、super。这些就是为未来在js中支持面向对象的类机制而预留的。
果不其然,如今ES6语法中使用到了这些保留字,这些保留字成功升级成了关键字,可见当时javascript的设计者仍是颇有前瞻眼光的。
经过这些新的关键字,使类成为了JS中一个新的一等公民。可是目前为止,这些关于类的新关键字仅仅是创建在旧的原型系统上的语法糖。这样作的缘由是为了保证向后兼容性。也就是,旧代码能够在不作任何hack的状况下,与新代码同时运行。
不过,它使代码的可读性变得更高,而且为从此版本里更多面向对象的新特性打下了基础。