在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来继承。有兴趣的可以自己尝试。
(基本更新完成,后续遇到重点再做补充。)