前言
es6的class其实是构造函数的语法糖,但是又有区别,下面来详细分析下class
定义
先来看下class的定义的代码
class Point{
constructor(){}
toString(){}
}
var p = new Point()
p.constructor === Point.prototype.contructor//true
Object.keys(Point.prototype)//[]
Object.getOwnPropertyNames(Point.prototype)//['constructor','toString']
区别
- 在类的实例上调用方法,就是调用类的原型上的方法,但是类内部的方法是不可枚举的,构造函数的方法是可枚举的(是否可被for...in遍历,object.keys),构造函数可以遍历除contructor之外的方法
- constructor是类默认的方法,通过new生成实例时自动调用该方法,如果没有被显示定义,这个方法会被自动创建。
- 类只能通过new生成实例对象,如果像直接调用class会报错。
- 类的所有实例共享一个原型对象
p2.__proto__ === p1.__proto__;//true
这也就意味着可以通过实例的__proto__属性为class添加方法,不推荐使用,因为会影响到其他实例 - class不存在变量提升,这个和继承有关,必须保证子类在父类之后定义
- 类和模块内部默认都是使用严格模式
- class可以自定义原生数据结构(Array,String等)的子类,这是es5无法做到的,因为es5是先新建子类的this,再将父类的属性添加到子类上,由于父类的内部属性子类无法获取,导致无法继承原生的构造函数
继承
子类必须在constructor中调用super方法,否则新建实例会报错,因为子类没有自己的this,而是继承了父类的this,这和es5中的继承不一样,
因为es5中的继承是先创造子类的实例对象this,再将父类的方法添加到this上(parent.call(this)),es6中是先继承父类的实例对象this,然后再用子类的构造函数修改this。如果子类没有定义constructor,那么这个方法会被默认添加。
在子类的构造函数中,只有调用super关键字之后,才可使用this关键字,否则会报错,因为子类实例的构建基于对父类实例的加工,只有super方法才能返回父类的实例。
prototype和__proto__
大多数浏览器的es5实现中,每一个对象都有__proto__属性(IE8除外),指向对应的构造函数的prototype属性。class作为构造函数的语法糖,同时有prototype属性和__proto__属性,因为存在两条继承链。
- 子类的__proto__属性表示构造函数的继承,总是指向父类
- 子类prototype属性的__proto__属性表示方法的继承,总是指向父类的prototype属性
class的静态方法
如果在一个方法前加上static关键字,就表示该方法不会被实例继承,而是直接通过类调用,成为‘静态方法’。
看下代码
class Foo{
static classMethod(){}
}
Foo.classMethod();
class Bar extends Foo(){
static classMethod(){
return super.classMethod()
}
}
Bar.classMethod();
上面Foo类有静态方法classMethod,只能通过Foo.classMethod调用,不可通过实例调用,否则会报错,父类的静态方法可被子类继承。
class的静态属性
静态属性是指class本身的属性,即class.propname,而不是定义在实例对象(this)上的属性。
class Foo{}
Foo.prop = 1;
Foo.prop //1
上面的方法可以读、写Foo类的静态属性prop,但是es6中规定,class中只有静态方法,没有静态属性
new.target属性
es6为new命令引入了new.target属性,返回new命令所作用的构造函数,如果构造函数不是通过new命令调用的,那么new.target会返回undefined,因此这个属性可以判断构造函数是如何被调用的
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。