参考文章:阮一峰 Class 的基本语法
类的由来
JavaScript语言的传统方法是通过构造函数定义并生成新对象,这种写法和传统的面向对象语言差异较大。所以,ES6引入了Class这个概念作为对象的模板。
class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到。
// es5 中的构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.toString = function () {
return '(' + this.name + ',' + this.age + ')';
}
var p = new Person('xiaoMing', 18);
// es6 通过class实现
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
toString() {
return '(' + this.name + ',' + this.age + ')';
}
}
var p = new Person('xiaoMing', 18);
上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。也就是说,ES5 的构造函数Point,对应 ES6 的Point类的构造方法。
ES6的类可以看作构造函数的另一种写法。
class Person {
// ...
}
typeof Person // "function"
Person === Person.prototype.constructor // true
上面代码表明,类的数据类型就是函数,类本身就指向构造函数。
ES6的类在es5中的实现原理
es6中的class的具体使用可以参考阮一峰Class 的基本语法。
我们现在看下es6中的class是怎么通过es5语法实现的,让我借助babel来一步一步看一下class转换成es5的代码
先添加一个类
// es6
class Person {
}
// 通过babel转换成的es5语法
"use strict";
// 判断某对象是否为某构造器的实例
function _instanceof(left, right) {
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
return !!right[Symbol.hasInstance](left); } else { return left instanceof right; }
}
// 检查声明的class类是否通过new的方式调用,否则会报错
function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) {
throw new TypeError("Cannot call a class as a function"); }
}
var Person = function Person() {
_classCallCheck(this, Person);
};
类必须使用new调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行。
添加属性和方法(包括静态方法)
// es6
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
eat() {
return 'eat'
}
static say() {
return 'say'
}
}
// 通过babel转换成的es5语法
"use strict";
// 判断某对象是否为某构造器的实例
function _instanceof(left, right) {
if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) {
return !!right[Symbol.hasInstance](left); } else { return left instanceof right; }
}
// 检查声明的class类是否通过new的方式调用,否则会报错
function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) {
throw new TypeError("Cannot call a class as a function"); }
}
/**
*将方法添加到原型上,如果是静态方法添加到构造函数上,
**/
function _defineProperties(target, props) {
// 遍历函数数组,分别声明其描述符 并添加到对应的对象上
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false; // 设置该属性是否能够出现在对象的枚举属性中。默认为 false
descriptor.configurable = true; // 设置该属性描述符能够被改变,同时该属性也能从对应的对象上被删除。
if ("value" in descriptor) descriptor.writable = true; // 如果属性中存在value, value设置为可以改变。
Object.defineProperty(target, descriptor.key, descriptor); // 写入对应的对象上
}
}
// 收集公有函数和静态方法,将方法添加到构造函数或构造函数的原型中,并返回构造函数。
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps); // 共有方法写在property原型上
if (staticProps) _defineProperties(Constructor, staticProps); // 静态方法写到构造函数上
return Constructor;
}
var Person = function () {
function Person(name, age) {
_classCallCheck(this, Person);
this.name = name;
this.age = age;
}
_createClass(Person, [{
key: "eat",
value: function eat() {
return 'eat';
}
}], [{
key: "say",
value: function say() {
return 'say';
}
}]);
return Person;
}();