参考文章:阮一峰 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;
}();