ES6中class的语法与继承

在es5中,我们常常会使用_proto_、prototype、constructor来实现继承,这样写代码多,写法也不太清晰,所以在es2015版本中增加了class。

class a {
}
a.prototype         //{constructor: ƒ}
                    //constructor: class a
                    //__proto__: Object

从上面打印出的东西我们其实可以把class定义的认定为一个function,其实typeof a打印出也是一个function。

同时我们也可以看到,定义class的时候其实已经初始化了一个constructor。

如果你在这个类里写其他function,在es5中其实默认是prototype里的方法。

所以其实如果是实例化了也和es5是一样的。

在另外一篇文章我已经简单讲过proto和prototype,https://blog.csdn.net/YuFun_0923/article/details/89209196

class表达式

先看一段代码:

var Class = class a {
  getName() {
    return a.name;
  }
};

在es5可以这样写:

var Class = function a() {
  getName() {
    return a.name;
  }
};

如果在方法里面没有使用a,那可以把a省去不写,因为你在外部不能调用a这个方法,只能通过Class这个变量来访问。在es6中,这个var最好是const来定义,防止其他地方把他篡改掉。

class也有类名,暂时没有遇到实用场景。

class的this指向:

不规范会导致this指向错误导致报错。

第一个方法就是使用bind绑定this指向。例如:this.login=this.login.bind(this)。

第二个方法就是箭头函数。(箭头函数是可以绑定this的,在https://blog.csdn.net/YuFun_0923/article/details/87875053里有写到箭头函数)

第三个方法是proxy(这是es6的一个新语法,不太会的不建议使用,可读性较差)

class的静态方法:static

直接在方法前面写static就能变成静态方法,静态方法不会被实例化继承。

如果这个static方法里有this,他的this指向这个类,而不是实例。并且他可以与非静态方法重名。

class的继承:

(“子类extends父类”)

class a {
}

class a1 extends a {
  constructor(x, y, color) {
    super(x, y); // 调用父类的constructor(x, y)
    this.color = color;
  }

  toString() {
    return this.color + ' ' + super.toString(); // 调用父类的toString()
  }
}

为什么要写super?

其实子类如果要用this方法的时候必须要通过父类来拿,super就是子类获得this的方法。

ES6的继承,实际上就是将父类实例对象的属性和方法加到this上面,所以必须在constructor里面最先就调用super。同样必须写类似下面的代码:

 constructor(...args) {
    super(...args);
  }

继承会继承静态属性和方法,但是不能被实例化,即不能被new。

super关键字

super既可以作为函数,也可以作为对象。

函数情况下:super()是代表调用父类的构造函数,继承的函数必须在constructor方法里面写super函数,否则会报错。

对象情况下:普通方法中指向父类的原型对象,静态方法中指向父类。

class A {
  constructor() {
    this.x = 1;
  }
  print() {
    console.log(this.x);
    console.log(this);
  }
}

class B extends A {
  constructor() {
    super();
    this.x = 2;
  }
  m() {
    super.print();
  }
}

let b = new B();
b.m()
//下面是打印的东西
//2
//B {x: 2}

从上我们可以发现,在父类A的方法里的this并没有指向他的constructor,而是指向了子类,如果是new A(),将会正常指向到A,从这里我们就应该明白:

m里的super.print()实际是执行的super.print.call(this),他的 this 指向被 B 强行绑定给自己

super对象赋值和读取的this指向也是不同的,如果是赋值操作,则指向当前this,如果是读取操作,则指向父类。

使用super必须明确是函数还是对象,否则会报错——Uncaught SyntaxError: 'super' keyword unexpected here

 

先看一段代码:

class A {
}

class B {
}

// B 的实例继承 A 的实例
Object.setPrototypeOf(B.prototype, A.prototype);

// B 继承 A 的静态属性
Object.setPrototypeOf(B, A);

const b = new B();

你可能看不太懂上面的代码,其实他就是class B extends A的内部实际执行的代码。

原型和原型对象(即_proto_和prototype)

class A {
}

class B extends A {
}

B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true

子类的原型是父类,子类的原型对象是父类原型对象的实例,父类有两种继承,一种继承object,一种是继承Function,不继承Object就默认继承function。

从上面的代码里,我们可以知道B.__proto__._proto_ === A._proto_。

原生构造函数的继承

原生构造函数就是内置的一些函数,比如Array()、Date()、Function()、Object()等等。

由于他们的特殊性,你不能构造一个与原生构造函数同名的类,也不能自己定义他们的子类。(因为会通过继承改变子类的方法间接改变父类的方法),你只能实例化。

但是es6可以用extends来继承。有兴趣的可以自己尝试。

 

(基本更新完成,后续遇到重点再做补充。)

你可能感兴趣的:(JS)