一、class原理
(1)完全可以看作构造函数的另一种写法,定义一个类,实质就是定义一个构造函数。类的数据类型就是函数,类本身就指向构造函数。
class Point {
// ...
}
typeof Point // "function"
Point === Point.prototype.constructor // true(2)类调用必须使用new关键字,它跟普通构造函数的一个主要区别
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
Point() // 报错 (构造函数不能没有new)
new Point() // 正确写的
ncaught TypeError: Class constructor Point cannot be invoked without 'new'
(3)es6 在线转译 www.babeljs.cn/repl/
上面es6 的代码转译之后可以:
var Point = function () {
function Point(x, y) {
_classCallCheck(this, Point);
this.x = x;
this.y = y;
}
_createClass(Point, [{
key: "toString",
value: function toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}]);
return Point;
}();function _classCallCheck(instance, Constructor) {
if (!_instanceof(instance, Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _instanceof(left, right) {
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
return !!right[Symbol.hasInstance](left);
} else {
return left instanceof right; // 可以简单的直接看这里,检测对象是否是new出来的
}
}
_instanceof(instance, Constructor) 很明显的看出:检测对象是否是new出来的。
所以Point() // 报错 (构造函数不能没有new)(4)类的内部所有定义的方法,都是不可枚举的,但是ES5 的写法,原型上定义的方法就是可枚举的。
class Point {
constructor(x, y) {
// ...
}
toString() {
// ...
}
}
Object.keys(Point.prototype) // []
Object.getOwnPropertyNames(Point.prototype) // ["constructor","toString"](5)其他知识点位
constructor方法默认返回实例对象(即this),但是完全可以指定返回另外一个对象。
实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)。
类的所有实例共享一个原型对象,实例的__proto__属性改写原型,必须相当谨慎,不推荐使用,因为这会改变“类”的原始定义,影响到所有实例。
二、exteds\super干了什么
ES5 的继承实质是:先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。
ES6 的继承机制完全不同实质是:先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。子类实例的构建,基于父类实例,只有super方法才能调用父类实例。
class People{
constructor(name, age) {
this.name = name;
this.age = age;
}
}
class lily extends People{
constructor(){
super()
}
}Babel转译之后一目了然:
(1)extends的过程中创建了一个自执行函数,并将父类传进去,继承父类之后再返回该子类
var lily = function (_People) {
_inherits(lily, _People); // 继承父类原型
function lily() { // 继承父类对象属性
_classCallCheck(this, lily);
return _possibleConstructorReturn(this, _getPrototypeOf(lily).call(this)); // super干的事
}
return lily;
}(People);function _inherits(subClass, superClass) {
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}(2)super() 的实质就是People.call(this)
function _possibleConstructorReturn(self, call) {
//call指的是Object.getPrototypeOf(lily)).call(this),也就是People.call(this)
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
在子类中如果调用constructor函数,必须调用super(),在子类的constructor函数实际上指向的是父类的constructor函数,因为在子类的constructor内部的this指向的是子类实例本身,需要super去改变this指向,可以调用super()方法传递参数,动态获得父类的继承。
super当做函数使用:super()
class A { constructor() { console.log(new.target.name); //new.target指向当前正在执行的函数 }}class B extends A { constructor() { super(); }}new A() // Anew B() // B注意,super虽然代表了父类的构造函数,但是返回的是子类的实例,即super内部的this指的是B,因此super()在这里相当于A.prototype.constructor.call(this)。
可以看到,在super()执行时,它指向的是子类B的构造函数,而不是父类A的构造函数。也就是说,super()内部的this指向的是B。
super当作对象使用
在普通方法中
指向父类的原型对象;super.myMethod(msg)就相当Parent.prototype.myMethod(msg)
在静态方法中
指向父类; 注意:静态方法定义在类上,所以只能通过类来调用。
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);
var child = new Child();
child.myMethod(2); 三、static关键字定义静态方法
静态方法定义在类上,所以只能通过类来调用,同时子类可以继承父类的静态方法
class P {
constructor(name, age) {
this.name = name;
this.age = age;
}
toString() {
return '(' + this.name + ', ' + this.age + ')';
}
static F () {
console.log('i am point')
}
}
class C extends P {
constructor(name, age){
super('小小', 20)
this.name = name
}
}
var c1 = new C('hello', 20)
console.log(c1) // 输出实例
console.log(C.F) // 输入静态方法
console.log(c1.F) // undefined小白菜,白了又了白。。。