自從有了webpack以後,我們這些jscoder好像得到了亘古未有的解放,箭頭函數,對象解構,let,const關鍵字,以及class、extends等等關鍵字運用得不亦樂乎,橫豎,webpack會幫我們把這些es6代碼轉換成瀏覽器能夠辨認的es5代碼,那末,我們有多少人真正的看過,babel轉換以後的代碼呢?本日,我就來看一下,當我們運用關鍵詞class的時刻,babel究竟做了什麼?
1、翻開網址:https://babeljs.io/repl
我引薦翻開網址:https://babeljs.io/repl,這裏我們左邊寫es6代碼,立時右邊就能夠轉譯出es5代碼,然後,我在左邊輸入了如下代碼:
class A {
constructor(name) {
this.name = name
}
getName() {
return this.name
}
}
這是一個最簡樸的類,一個屬性,一個要領。
這時刻,右邊框已給我轉譯出了瀏覽器可辨認的es5代碼了,格式化以後是如許的:
'use strict';
var _createClass = function () {
function defineProperties(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);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError('Cannot call a class as a function');
}
}
var A = function () {
function A(name) {
_classCallCheck(this, A);
this.name = name;
}
_createClass(A, [{
key: 'getName',
value: function getName() {
return this.name;
}
}]);
return A;
}();
好,如今來剖析一下這段代碼。
2、es6內里的類,本質上實在就是一個函數
// 自實行函數
var A = function () {
function A(name) {
// 這個函數的目的實際上是防備這個組織函數被當作一般函數實行
_classCallCheck(this, A);
this.name = name;
}
// 對函數A實行_createClass要領,實在就是給A的原型上綁定要領
_createClass(A, [{
key: 'getName', //要領名
value: function getName() { //函數體
return this.name;
}
}]);
return A;
}();
這段代碼,變量A是一個自實行函數的返回值,該自實行函數的返回值實在就是我們熟習的組織函數,所以,es6內里的類實在就是一個組織函數。
3、_classCallCheck函數
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError('Cannot call a class as a function');
}
}
這個函數迥殊簡樸,當實行函數A的時刻,不允許this不是A的子類實例,比方直接如許挪用A(),但是在A的子類B中能夠如許挪用:A.apply(this, arguments)。
該函數的目的是防備組織函數被當作一般函數實行。
4、_createClass函數
//該函數也是一個自實行的函數,其返回值是一個函數
var _createClass = function () {
// 把props數組上每個對象,經由過程Object.defineProperty要領,都定義到目的對象target上去
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
//這裏要確保props[i]是一個對象,而且有key和value兩個鍵
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);
}
}
return function (Constructor, protoProps, staticProps) {
// 假如傳入了原型屬性數組,就把屬性悉數定義到Constructor的原型上去
if (protoProps) defineProperties(Constructor.prototype, protoProps);
// 假如傳入了靜態屬性數組,就把屬性悉數定義到Constructor對象本身上去
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
實在_createClass函數做的事變,就是把幾個要領拷貝到組織函數A的原型上去。
4、運用關鍵詞extends,發生了什麼?
我在https://babeljs.io/repl 左邊輸入框上加了下面這行代碼:
class B extends A {}
這時刻,右邊多出了以下幾行代碼:
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError('this hasn\'t been initialised - super() hasn\'t been called');
}
return call && (typeof call === 'object' || typeof call === 'function') ? call : self;
}
function _inherits(subClass, superClass) {
if (typeof superClass !== 'function' && superClass !== null) {
throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
var B = function (_A) {
_inherits(B, _A);
function B() {
_classCallCheck(this, B);
//這裏的重點是第二個參數:(B.__proto__ || Object.getPrototypeOf(B)).apply(this, arguments);
//這裏實際上是將子類的實例對象,挪用了父類的組織函數要領,如許父類的屬性就都能夠拷貝到子類上來
return _possibleConstructorReturn(this, (B.__proto__ || Object.getPrototypeOf(B)).apply(this, arguments));
}
return B;
}(A);
5、_inherits函數
function _inherits(subClass, superClass) {
//簡樸校驗
if (typeof superClass !== 'function' && superClass !== null) {
throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass);
}
//把子類的原型指向父類的原型建立出來的對象(注重不是直接指向父類原型),而且修改constructor屬性為子類本身
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
// 這一步操縱,實際上是想把superClass放到subClass下,相當於subClass.super = superClass,如許背面的代碼中,subClass內里能輕易的引用到superClass函數
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
6、_possibleConstructorReturn函數
function _possibleConstructorReturn(self, call) {
if (!self) {
throw new ReferenceError('this hasn\'t been initialised - super() hasn\'t been called');
}
return call && (typeof call === 'object' || typeof call === 'function') ? call : self;
}
假如call不是對象或許函數,即該挪用:(B.__proto__ || Object.getPrototypeOf(B)).apply(this, arguments)的返回值既不是對象,也不是函數,那末,就直接返回當前的self,而self實在就是子類B內里的實例指針this。一般狀況,(B.__proto__ || Object.getPrototypeOf(B)).apply(this, arguments)的返回值就是一個對象,實在也就是對象。
好了,上面算是基礎說清楚了運用es6語法定義類、繼續類,究竟發生了什麼,假如毛病,還請斧正,感謝!