说明:本文参考阮一峰的ECMAScript 6 入门
1.Class
类的由来
JavaScript语言中,生成实例对象的传统方法是通过构造函数。
function Person (name, age) {
this.name = name
this.age = age
}
Person.prototype.toString = function () {
return `${name},${age}`
}
var per = new Person("wangwu", 19)
上面这种写法跟面向对象语言(C++、Java)差异很大,很容易让学习这门语言的程序员感到困惑。
ES6提供了更接近传统语言的写法,引入了class(类)这个概念,作为对象的模板。通过class关键字可以定义类。
新的Class写法只是让对象原型的写法更加清晰、更加面向对象编程的语法而已。上面代码用ES6的class写法,就是下面这样。
calss Person {
constructor(name, age){
this.name = name
this.age = age
}
toString() {
return `${this.name},${this.age}`
}
}
var per = new Person("wangwu", 19)
上面代码,定义了一个类,里面有一个constructor方法,这就是构造方法,this代表实例对象。构造实例的时候,也是直接对类使用new命令,跟构造函数的用法完全一致。
Person类还定义了一个toString方法。注意,定义类的方法时候,不需要在前面加上关键字function,直接把函数定义放进去就可以了。另外方法之间,不需要逗号分隔,加了逗号会报错。
ES6的类可以看作构造函数的另一种写法。
class Person {
}
typeof Person //function
Person === Point.prototype.constructor //true
上面代码说明,类的数据类型就是函数,类本身指向构造函数。类的所有方法都是定义在类的prototype属性上面。在类的实例上调用方法就是调用原型上的方法。
另外,类的内部所有定义的方法,都是不可枚举的(non-enumerable)。
注意点
- 严格模式,类和模块的内部,默认就是严格模式。考虑到未来所有的代码,其实都是运行在模块之中,所以 ES6 实际上把整个语言升级到了严格模式。
- 不存在提升,类不存在变量提升(hoist)。
- this指向,类的方法内部如果含有this,它默认指向类的实例。
- 静态方法,如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。如果静态方法包含this关键字,这个this指的是类,而不是实例。
2.CLass的继承
class是通过extends关键字来继承的,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。
class Person {
}
class Student extends Person {
}
上面代码定义了一个Student类,该类通过extends关键字继承了Person类的所有属性和方法。
类的prototyppe属性和__proto__属性
大多数浏览器ES5实现之中,每一个对象都有__proto__属性,指向对应的构造函数的prototype属性。Class作为构造函数的语法糖,同时有prototype属性和__proto__属性。因此具有两条继承链。
(1)子类的__proto__属性,表示构造函数的继承,总是指向父类。
(2)子类的prototype的__proto__属性,表示方法的继承,总是指向父类的prototype属性。
class A {
}
class B extends A {
}
B.__proto__ === A //true
B.prototype.__proto__ === A.prototype
上面代码中,子类B的__proto__属性指向父类A,子类B的prototype属性的__proto__属性指向父类A的prototype属性。
这样的结果是因为,类的继承是按照下面的模式实现的。
class A {
}
class B {
}
// B 的实例继承 A 的实例
Object.setPrototypeOf(B.prototype, A.prototype);
// B 继承 A 的静态属性
Object.setPrototypeOf(B, A);
const b = new B();
下面这段代码是Object.setPrototypeOf方法的实现。
Object.setPrototypeOf = function (obj, proto) {
obj.__proto__ = proto;
return obj;
}
因此,就得到了上面的结果。