ES6的类&&ES6前的继承
aermin opened this issue · comments
在ES6出来前,js并无类,与类最接近的是:创建一个构造器,然后将方法指派到 该构造器的原型上。
可以通过我之前结合高程这本书整理的文章看看,js面对对象(创建对象,实现继承)
接下来,根据代码看看两者之间的联系,在原有的基础上吸收使用ES6的类。
ES6 之前,实现自定义类型的继承是个繁琐的过程。严格的继承要求有多个步骤。
ES6前的代码实现
function Rectangle(length, width) { // ①
this.length = length;
this.width = width;
this.test = "test~"
}
Rectangle.prototype.getArea = function() { // ②
return this.length * this.width;
};
Rectangle.prototype.doTest = function() { // ②
console.log(this.test);
};
function Square(length) { // ③
Rectangle.call(this, length, length); //构造器继承属性
}
Square.prototype = Object.create(Rectangle.prototype, { //④ 原型继承方法,且书写配置
constructor: {
value:Square,
enumerable: true, //可枚举
writable: true, //可写
configurable: true //可配置
}
});
Square.prototype.getDataFromSuperClass = function(){
console.log(this.length ,"===", this.width);
}
var square = new Square(3); //创建实例
console.log(square.getArea());// 9
square.doTest(); //"test~"
square.getDataFromSuperClass();//3 "===" 3
console.log(square instanceof Square);// true
console.log(square instanceof Rectangle);// true
这例子和js面对对象(创建对象,实现继承) 的例子基本一样
ES6的代码实现(类)
class Rectangle {
constructor(length, width) { //①
this.length = length;
this.width = width;
this.test = "test~" //在constructor定义的this.变量 都将可以在class中访问 (有木有vue的data既视感😄)
}
getArea() { //②
return this.length * this.width;
}
doTest () {
console.log(this.test);
console.log("theWidth in super class", this.theWidth); //使用本类中的取值函数
}
get theWidth() { //取值函数
return this.width;
}
}
class Square extends Rectangle { //extends 方法相当于 ④
constructor(length) {
super(length, length); // ③ super() 用来访问父类的构造器 与 Rectangle.call(this, length, length) 相同
}
getDataFromSuperClass(){ //因为super 所以这边可以访问到父类Rectangle的this.变量
console.log(this.length ,"===", this.width);
console.log("theWidth in sub class ", this.theWidth); //使用父类的取值函数
}
}
var square = new Square(3);
console.log(square.getArea());// 9
square.doTest(); //"test~" "theWidth in super class" 3
square.getDataFromSuperClass();//3 "===" 3 "theWidth in sub class " 3
console.log(square instanceof Square);// true
console.log(square instanceof Rectangle);// true
两个例子我都用序号标了,序号相同的代表着不同的写法,一样的意思
继承了其他类的类(如上文的Square)被称为派生类( derived classes )。
如果派生类指定了构造器,就需要 使用 super() ,否则会造成错误。若你选择不使用构造器, super() 方法会被自动调用, 并会使用创建新实例时提供的所有参数。
class Square extends Rectangle {// 没有构造器
}
// 等价于:
class Square extends Rectangle {
constructor(...args) {
super(...args);
}
}
此例中的第二个类展示了与所有派生类默认构造器等价的写法,所有的参数都按顺序传递给 了基类的构造器。在当前需求下,这种做法并不完全准确
,因为 Square 构造器只需要单个 参数,因此最好手动定义构造器
。
使用super()需注意
- 你只能在派生类中使用super()。若尝试在非派生的类(即:没有使用extends关键字的类)或函数中使用它,就会抛出错误。
- 在构造器中,你必须在访问 this 之前调用 super() 。由于 super() 负责初始化this(ES5的.call()),因此试图先访问this自然就会造成错误。
- 唯一能避免调用 super()的办法,是从类构造器中返回一个对象。
class 的静态方法
在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。要直接在Foo类上调用(Foo.classMethod()),而不是在Foo类的实例上调用(会报错),调用静态方法不需要实例化该类,但不能通过一个类实例调用静态方法。
class Foo {
static bar () {
this.baz();
}
static baz () { //静态成员
console.log('hello');
}
baz () { //实例对象的成员, 如 new Foo();
console.log('world');
}
}
Foo.bar() // hello
class Foo {
bar () {
this.baz();
}
static baz () {
console.log('hello');
}
baz () {
console.log('world');
}
}
const newFoo = new Foo();
newFoo.bar() // world
静态方法只能访问静态成员,实例方法只能访问实例成员。
然后为啥要有静态方法呢,有些东西是不需要实例的,只要有类就存在的,比如Array.isArray(obj); 静态方法通常用于为一个应用程序创建工具函数。
未完待续....