- Es6中class 可以看做是一个语法糖
- 新的class写法只是让对象原型的写法更加清晰,更加面向对象编程。
- Class通过exends关键字进行继承
class Father{
}
class Son extends Father{
}
- 代码 定义了一个Son,通过exends继承Father类的所有属性和方法,由于没有部署任何代码,所以这两个类完全一样,等于完全复制了一个Father类
class Son extends Father{
constructor(name,age,city){
super(name,age)
this.city=city
}
toString () {
return this.city+ " " +super.toString();//调用父类的toString()
}
}
- super 关键字,类的构造函数,用来新建父类的this对象。 子类必须的constructor方法中调用super方法,否则新建的实例时会报错,如果不调用 super方法,自雷就得不到this对象;
- ES5的继承,实质上是线创造自雷的实例对象this,然后再将父类的方法添加到this上,(parent.apply(this)),ES6的继承机制完全不同,实质上是先创造对象this,所以必须先调用super犯法,然后再用子类的构造函数修改this;如果子类没有定义cinstructor方法,这个方法会默认添加,也就是说不管有没有显示定义任何一个子类都有constructor方法。
class Son extends Father{}
//等于
class Son extends Parent{
constructor(...args){
super(...args)
}
}
- 在子类的构造函数中,只有调用super之后,才能使用this关键字。 因为子类实例的构件,是基于对父类实例的加工,之后super方法才能返回父类实例;
class Father{
constructor(x,y){
this.x=x;
this.y=y;
}
}
class Son extends Father{
constructor(x,y,color){
//必须先调用super
super(x,y)
this.color=color;
console.log(this.color,x,y)
}
}
let s =new Son(25,8,'green')
- Object.getPrototypeOf()方法用来从子类获取父类
Object.getPrototypeOf(Son)===Father
//用来判断是否继承
- super关键字 即可当做函数使用也可以当做对象使用。 ·super当做函数调用时,代表父类的构造函数,Es6要求,子类的构造函数必须执行一个super函数。
class Father { }
class Son extends Father {
constructor () {
super();
}
}
super肃然代表了父类Father的构造函数,但是返回的是子类son的实例,既super内部的this只想的是son,因此,super()在这里相当于 Father.constructor.call(this) 而且作为函数时,super()智能在子类的构造函数中。
class A{
constructor(){
console.log(new.target.name)
}
}
class B extends A{
constructor(){
super()
}
}
new A();
new B();
//new.target是指当前正在执行的函数,在super()执行时,他指向的是子类B的构造函数,二部是父类A的构造函数,super()内部的this指向的是B
· super 作为对象时,在普通方法中,指向的的是父类的原型对象,在静态方法中,指向的是父类。
class Father{
getName(){
return '123'
}
}
class Son extends Father{
constructor{
super();
consloe.log(super.getName())
}
}
let s=new Son();
子类son中的super.getName()就是将super当做一个对象使用,这时,super在普通放方法中,指向Father.prototype,所以super.getName()就相当于Father.prototype.getName(),由于super指向父类的圆形对象,所以定义在父类实例上的方法或者属性是无法通过super调用的。
class Father {
constructor () {
this.p =2
}
}
class Son extends Father {
get m ( ) {
return super.p;
}
getValue ( ) {
return super.a;
}
}
let s = new Son();
s.m //undefined
p是父类Father的实例属性,super.p就引用不到它 如果实行定义在父类原型对象上,super就可以取到。
class A {}
A.prototype.x = 4;
class B extends A {
constructor() {
super();
console.log(super.x) // 4
}
}
let b = new B()
属性X是定义在A.prototype上面所以super.x可以取到他的值,Es6规定,通过super调用父类的方法时,super会绑定子类的this
class Father {
constructor () {
this.x =1;//这个this指向的是Father对象的实例
}
print () {
console.log(this.x);
}
}
class Son extends Father {
constructor () {
super();
this.x = 2;//这个this指向的是Son对象的实例
}
m() {
super.print();
}
}
let s = new Son();
s.m();
//2
super.print()虽然调用的是Father.prototype.print(),但是Father.prototype.print()会绑定子类son的this,导致输入2而不是1 ,实际上执行super.print.call(this) 如果super作为对象,用在静态方法中,这时super将指向父类,而不是父类的原型对象。
class Parent {
//静态方法
static myMethod (msg) {
console.log("static",msg);
}
//普通方法
myMethod (msg) {
console.log("instance" ,msg);
}
}
class Child extends Parent {
//静态方法
static myMethod(msg) {
super.myMethod(msg);
}
//普通方法
myMethod (msg) {
super.myMethod(msg);
}
}
Child.myMethod(1);
//static 1
var child = new Child();
child.myMethod(2);
//instance 2
super 在静态方法中指向父类,在普通方法中指向父类原型对象。 使用super的时候,必须显式指定是作为函数、还是作为对象使用。
类的prototype属性和proto属性
- 大多数浏览器的es5实现之中,每一个对象都有Proto属性,指向相对应的构造函数的prototype属性。
class 作为构造函数的语法糖,同时有prototype属性和proto属性,同事存在两条继承链。
- 子类proto属性,标识构造函数的继承,总是指着父类
- 子类prototype属性的proto属性,表示方法的继承,总是指向父类的prototype属性。
class A{
}
class B{
}
//Object.prototype.__proto__
// Object.setPrototypeOf()方法的实现:
// Object.setPrototypeOf = function (obj, proto) {
// obj.__proto__ = proto;
// return obj ;
// }
//Object.setPrototypeOf( B.prototype , A.prototype );
//等同于
//B.prototype.__proto__ = A.prototype ;
//Object.setPrototypeOf(B, A);
//等同于
//B.__proto__ = A;
//B的实例继承A的实例
Object.setPrototypeOf(B.prototype,A.prototype);
//B的实例继承A的静态属性。
Object.setPrototypeOf(B,A)
const b=new B();
这两条继承链可以理解为:作为一个对象,子类型B原型(proto属性),是父类(A),作为一个构造函数,子类B的圆形对象(prototype属性)是父类的原型对象(prototype)的实例。
extends的继承目标
extends的关键字后面可以跟很多类型的值:
class B extends A{
}
只要A有一个prototype属性的函数,就能被B继承,由于函数prototype属性(除了Function.prototype函数),因此A可以使任意函数。
- 子类继承Object类
class A extends Object {
}
A.__proto__ === Object //true;
A.prototype.__proto__ === Object.prototype //true
A就是构造函数Object的复制,A的实例就是Object的实例。
- 不存在任何继承
class A{}
A.__proto__ === Function.prototype //true
A.prototype.__proto__ = Object.prototype //true
A作为一个基类,不存在任何继承,就是一个普通函数,所以直接继承Function.prototype。但是A调用后返回一个空对象(既Object实例),所以A.prototype.proto指向构造函数(Object)的prototype属性。 #####实例的proto属性 子类实例的proto属性的proto属性,指向父类实例的proto属性,也就是说子类的原型的原型就是父类的原型。
原生构造函数的继承
Boolean()
Number()
String()
Array()
Date()
Function()
RegExp()
Error()
Object()
extends关键字不仅可以用来继承类,还可以用来继承原生的构造函数。因此可以在原生数据结构的基础上,定义自己的数据结构。