ES6中类的使用
认识class定义类
按照构造函数的形式创建类,不仅仅和编写普通的函数过于相似,而且代码并不容易理解
- 在ES6(ECMAScript2015)新的标准中使用了class关键字来直接定义类
- 但是类的本质上只是构造函数,原型链的语法糖
- 最终还是会被 babel 工具转换为ES5的代码
定义类的方式
可以发现类和构造函数的特性是一致的
class Person {
}
var Student = class {
}
console.log(Person) console.log(Person.prototype); console.log(Person.prototype.__proto__); console.log(Person.prototype.constructor); console.log(typeof Person);
var p = new Person() console.log(p.__proto__ === Person.prototype);
|
类的构造方法
一个类只能有一个构造函数 constructor,如果包含多个会报错
new 的时候:
- 在内存中创建一个对象 moni = { }
- 将类的原型prototype赋值给创建出来的对象的[[prototype]],
moni.__ptoto__ = Person.prototype
- 将对象复制给函数的this:new绑定 this = moni
- 执行函数体中的代码
- 自动返回创建出来的对象
class Person { constructor(name, age) { this.name = name this.age = age } }
var p1 = new Person("kac", 12) var p2 = new Person("awe", 20) console.log(p1, p2);
|
类中的方法定义
三种定义方法
普通的实例方法:实际上是放到原型上的,可以被多个实例共享
类的访问器方法:setter,getter
类的静态方法:直接使用类来调用的方法 Person.xxx(),不需要借助实例来调用,例如Promise.all(),也是类方法
使用 static关键字来定义
var names = ["abc", "cba", "nba"] class Person { constructor(name, age) { this.name = name this.age = age this._address = "广州市" }
eating() { console.log(this.name + " eating~"); }
get address() { console.log("拦截访问操作"); return this._address }
set address(newAddress) { console.log("拦截设置操作"); this._address = newAddress }
static randomPerson() { var nameIndex = Math.floor(Math.random() * names.length) var name = names[nameIndex] var age = Math.floor(Math.random() * 100) return new Person(name, age) } }
var p = new Person("axf", 18) p.eating()
console.log(p.address); p.address = "北京市" console.log(p.address);
for (var i = 0; i < 50; i++) { console.log(Person.randomPerson()); }
|
类的继承extends
ES6中新增了 extends 关键字,可以方便的帮助我们实现继承
super关键字,三个使用位置:子类的构造函数、实例方法、静态方法
子类的构造函数:JS引擎在解析子类的时候就有要求,如果我们有实现继承,那么子类的构造方法中,在使用this之前,要调用super()
否则报错
ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
|
子类可以重写父类的方法,在重写方法中使用 super 来复用父类中的逻辑
class Person { constructor(name, age) { this.name = name this.age = age } running() { console.log('逻辑1'); console.log('逻辑2'); console.log('逻辑3'); console.log(this.name + ' running~'); } static staticMethod() { console.log('person staticMethod'); } }
class Student extends Person { constructor(name, age, sno) { super(name, age) this.sno = sno } running() { super.running() console.log('逻辑4'); console.log('逻辑5'); console.log('逻辑6'); console.log("student " + this.name + " running"); } static staticMethod() { super.staticMethod() console.log('student staticMethod'); } }
let p = new Student("asx", 12, 111) console.log(p);
Student.staticMethod()
|
继承内置类
让我们的类继承内置类,比如:Array
这样我们就可以得到Array的方法了
class MyArray extends Array{ firstItem() { return this[0] }
lastItem() { return this[this.length - 1] } }
var arr = new MyArray(1,2,3) console.log(arr.firstItem()); console.log(arr.concat([33]))
|
类的混入(少用)
JavaScript 的类只支持单继承,也就是只能有一个父类
如果想在一个类中添加更多相似的功能时,可以使用混入
class Person {}
function mixinRunner(BaseClass) { class NewClass extends BaseClass { running() { console.log('I am running~'); } } return NewClass }
function mixinEater(BaseClass) { class NewClass extends BaseClass { eating() { console.log('I am eating~'); } } return NewClass }
class Student extends Person {}
var NewStudent = mixinEater(mixinRunner(Student))
var stu = new NewStudent() stu.running() stu.eating()
|
JavaScript中的多态
维基百科:多态(英语:polymorphism)指为不同数据类型的实体提供统一的接口,或使用一 个单一的符号来表示多个不同的类型
总结:不同的数据类型进行同一个操作,表现出不同的行为,就是多态的体现
所以说,JS也是有多态的,虽然跟别的一些面向对象语言有些区别
function calcArea(foo) { console.log(foo.getArea()); }
var obj1 = { name: "sfr", getArea: function() { return 1000 } }
class Person { getArea() { return 100 } }
var p = new Person()
calcArea(obj1) calcArea(p)
function sum(m, n) { return m + n }
sum(20, 30) sum("abc", "asf")
|
ES6转ES5
可以在 babeljs.io 中看es6通过babel转es5后的代码
有点难度,不要浮躁,慢慢看
可以打 debug 一点点看
例如:
class Person { constructor(name, age) { this.name = name this.age = age }
eating() { console.log(this.name + " eating~") } }
"use strict";
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
var Person = (function () { function Person(name, age) { this.name = name; this.age = age; }
_createClass(Person, [{ key: "eating", value: function eating() { console.log(this.name + " eating~"); } }]);
return Person; })();
|