ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法
类和构造函数的区别是什么?
1.类必须要new来调用,否则就会报错,普通的构造函数不用new来调用 也可以执行
2.类上的内部定义的方法都是不可枚举的,构造函数通过protype定义的方法是可以枚举的。
3.类不存在变量的提升,因为 ES6 不会把类的声明提升到代码头部。这种规定的原因与下文要提到的继承有关,必须保证子类在父类之后定义
类
ES6 的类,完全可以看作构造函数的另一种写法。
类的数据类型就是函数,类的本身就指向构造函数(只有构造函数才有prototype属性)
使用的时候使用new的命令来创建实例,跟构造函数的用法完全一致
class Point {// ...}typeof Point // "function"Point === Point.prototype.constructor // true
构造函数的prototype属性,在ES6 的’类’上面继续存在。事实上,类的所有的方法都定义在类的prototype属性上面。
下面这些方法其实都是定义在Point.prototype 上面。
class Point {constructor() {// ...}toString() {// ...}toValue() {// ...}}// 等同于Point.prototype = {constructor() {},toString() {},toValue() {},};
在类的实例上面调用方法,事实就是调用原型上的方法:
代码中,b是B类的实例,它的constructor()方法就是B类原型的constructor()方法
class B {}const b = new B();b.constructor === B.prototype.constructor // true
另外,类的内部所有定义的方法,都是不可枚举的(non-enumerable)
class Point {constructor(x, y) {// ...}toString() {// ...}}Object.keys(Point.prototype)// []Object.getOwnPropertyNames(Point.prototype)// ["constructor","toString"]
代码采用ES5的写法,toString()方法就是可枚举的
var Point = function (x, y) {// ...};Point.prototype.toString = function () {// ...};Object.keys(Point.prototype)// ["toString"]Object.getOwnPropertyNames(Point.prototype)// ["constructor","toString"]
constructor 方法
constructor()方法是类的默认方法,通过new 命令生成对象实例时,自动调用改方法,一个类必须有constructor()方法,如果没有显式定义,一个空的constructor()方法会默认添加。
constructor() 方法默认返回实例对象(即this),但完全可以指定返回另外一个对象。
代码中,constructor()函数返回一个全新的对象,结果导致实例对象不是Foo类的实例
class Foo {constructor() {return Object.create(null);}}new Foo() instanceof Foo// false
类的实例
与 ES5 一样,实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)
//定义类class Point {constructor(x, y) {this.x = x;this.y = y;}toString() {return '(' + this.x + ', ' + this.y + ')';}}var point = new Point(2, 3);point.toString() // (2, 3)point.hasOwnProperty('x') // truepoint.hasOwnProperty('y') // truepoint.hasOwnProperty('toString') // falsepoint.__proto__.hasOwnProperty('toString') // true
静态方法
类相当与实例的原型,所有在类中的定义的方法,都会被实例继承,如果在一个方法前,加上static 关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为静态的方法。
注意,如果静态方法包含this关键字,这个this指的是类,而不是实例。
class Foo {static classMethod() {return 'hello';}}Foo.classMethod() // 'hello'var foo = new Foo();foo.classMethod()// TypeError: foo.classMethod is not a function
静态方法bar调用了this.baz,这里的this指的是Foo类,而不是Foo的实例,等同于调用Foo.baz。另外,从这个例子还可以看出,静态方法可以与非静态方法重名
class Foo {static bar() {this.baz();}static baz() {console.log('hello');}baz() {console.log('world');}}Foo.bar() // hello
父类的静态方法,可以被子类继承(注意一下:这里就是用子类的调用方法,不是new出来的实例调用方法)
class Foo {static classMethod() {return 'hello';}}class Bar extends Foo {}Bar.classMethod() // 'hello'
静态方法也是可以从super对象上调用的。
class Foo {static classMethod() {return 'hello';}}class Bar extends Foo {static classMethod() {return super.classMethod() + ', too';}}Bar.classMethod() // "hello, too"
静态属性
静态属性指的是Class 本身的属性,即Class.propName,而不是定义在实例对象的(this)上的属性
class Foo {}Foo.prop = 1;Foo.prop // 1
因为 ES6 明确规定,Class 内部只有静态方法,没有静态属性。现在有一个提案提供了类的静态属性,写法是在实例属性的前面,加上static关键
// 老写法class Foo {// ...}Foo.prop = 1;// 新写法class Foo {static prop = 1;}
