自从有了babel这一个利器以后,es6如今已经被普遍的使用。JavaScript 类实质上是 JavaScript 现有的基于原型的继承的语法糖。类语法不会为JavaScript引入新的面向对象的继承模型。也就是说babel不管是实现类,仍是实现继承,本质上都是基于原型及原型链的,那我咱们就顺这这个思路,一步一步往下走,直到揭开babel是如何实现类及类的继承的。javascript
javascript中原型的概念比较抽象,不是很好理解,咱们仍是老老实实上代码,用代码来举例说明。前端
function Person (name, age, job) {
this.name = name;
this.age = age;
this.job = job;
}
let p1 = new Person('张三', 18, '前端攻城狮')
复制代码
咱们建立了一个Person的构造函数,并用new 建立了一个该对象的实例对象p1。java
前面咱们聊了聊原型和原型链,其实就是为了咱们聊继承作铺垫的。废话很少说,咱们上代码吧:es6
// 咱们定义一个动物类,里面有一个类型的属性
function Animal (type) {
this.type = type
}
// 动物都有吃东西的方法
Animal.prototype.eat = function () {
console.log('我在吃东西')
}
// 咱们来个小猫咪类吧
function Cat () {}
// 如今咱们要实现让Cat继承Animal的属性和方法,该怎么作呢?
复制代码
// 咱们将cat类的原型直接指向Animal的实例
Cat.prototype = new Animal()
let cat = new Cat()
console.log(cat.eat())
复制代码
结果如图 chrome
function Animal (type) {
this.type = type
}
Animal.prototype.eat = function () {
console.log('我在吃东西')
}
function Cat (type) {
Animal.call(this, type)
}
Cat.prototype = new Animal()
let cat = new Cat('喵咪')
console.log(cat.eat())
console.log(cat.type)
复制代码
运行结果以下:数组
function Animal (type, val) {
this.type = type
this.sum = [4,5,6] // 随便给的属性啊,为了说明问题。
this.setSum = function () {
this.sum.push(val)
}
}
Animal.prototype.eat = function () {
console.log('我在吃东西')
}
function Cat (type, val) {
Animal.call(this, type, val)
}
Cat.prototype = new Animal()
let cat = new Cat('喵咪', 1)
let cat2 = new Cat('猫咪2', 2)
console.log(cat.setSum())
console.log(cat2.setSum())
console.log(cat.sum)
console.log(cat2.sum)
复制代码
运行结果如图: bash
function inherit(C, P) {
// 等同于临时构造函数
C.prototype = Object.create(P.prototype);
C.prototype.constructor = C; // 修复constructor
C.super = P;//存储超类
}
function Animal(type) {
this.type = type;
}
Animal.prototype.eat = function () {
console.log('动物都是要吃饭滴')
}
function Cat(type, talk) {
Cat.super.call(this, type)
this.talk = talk
this.getTalk = function () {
return this.talk
}
}
inherit(Cat, Animal)
let cat = new Cat('猫咪', '咱们一块儿学猫叫')
console.log(cat.getTalk())
复制代码
代码运行以下:babel
在背景中咱们已经聊到了es6中类的继承其实是一个语法糖,如今咱们就想办法拨开这颗糖。函数
class Animal {
constructor (type) {
this.type = type
}
eat () {
console.log('动物都要吃饭')
}
}
class Cat extends Animal {
constructor (type,talk) {
super(type) // 继承父类constructor的属性
this.talk = talk
}
getTalk () {
return this.talk
}
}
let cat = new Cat('喵咪', '喵喵喵')
console.log(cat.getTalk()) // 喵喵喵
console.log(cat.type) // 喵咪
复制代码
var Animal = function () {
function Animal (type) {
this.type = type
this.getType = function () {
return this.type
}
}
return Animal
}()
var Cat = function () {
function Cat (talk) {
this.talk = talk
this.getTalk = function () {
return this.talk
}
}
return Cat
}()
复制代码
function Animal() {
return {
name: '牛逼',
age: 18
}
}
let animal = new Animal()
console.log(animal) // { name: '牛逼', age: 18}
复制代码
所以babel中对此作了校验,这就是第二步要干的事情。代码以下:var _classCallCheck = function (instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("不能返回一个对象")
}
}
// 嗯,你没有看错就是这么几行代码
var Animal = function () {
function Animal (type) {
_classCallCheck(this, Animal)
this.type = type
}
}()
...此处省略喵咪类
复制代码
class Animal {
eat () {
console.log('aaa')
}
sleep () {
console.log('bbb')
}
}
复制代码
如上面代码中的eat方法和sleep方法的处理。那怎么能把方法添加到一个对象上呢?没错,Object.defineProperty()这个方法就是用来干这件事情的,babel中也是用他来处理的。回到咱们的话题,在babel中,它是经过_createClass这个函数来处理的。废话很少说咱们上代码:/*
_createClass()这个函数接受两个参数,
一个是这个类的构造函数,即给哪一个类添加方法。
第二个参数是一个数组对象,相似这样婶的
[{key: 'eat', val: function eat () { console.log('aaa') }}]
是否是恍然大悟?那接下来咱们就实现一下吧
*/
function definePropties (target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ('value' in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor)
}
}
var _createClass = function () {
return function (Constructor, protoProps, staticProps) {
// 添加原型上的方法
if (protoProps) definePropties(Constructor.prototype, protoProps)
// 添加静态的方法
if (staticProps) definePropties(Constructor, staticProps)
return Constructor
}
}()
_createClass(Animal,[{
key: 'eat',
value: function () {
console.log('aaa')
}
}])
复制代码
接下来,终于到了咱们的大boss啦,上面咱们聊了聊babel中是怎么处理es6中类的,这节咱们就聊聊babel中是怎么处理es6中的继承。ui
function _inherits(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true;
}
})
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
复制代码
好啦,这个话题就聊到这里,欢迎你们拍砖啊。