寫在前面的話
我會将過去幾年學到的 Canvas 制圖理論、實踐進行濃縮、并編輯成冊。希望通過體系化的内容組織助你快速入門、深入了解 Canvas。當然,因篇幅有限,本課程可能無法做到面面俱到,但是有了核心知識的積累,不論是繼續閱讀 Canvas 系列書籍,還是進一步擴充 Canvas 的學習領域、如 3D 制圖等,都能做到左右逢源。
本 Canvas 系列課程已經編輯成冊并陸續更新,下面是已更新章節傳送門:
《Canvas 自動化制圖必知必會-導讀篇》
《Canvas 上下文詳解》
《一文讀懂 Canvas 中的 scale 與 translate》
《一文讀懂 Canvas 中 rotate 與 skew 操作》
《Canvas 矩陣鏡像那些你不得不知的數學原理》
話不多說,直接進入正題。
1.示例代碼
父類 Parent 定義了一個箭頭函數方法,名稱為 sayHelloArrow,同時定義了一個正常屬性方法,名稱為 sayHelloCommon,同時子類 Child 繼承了父類。接下來使用 babel 對這個類進行編譯,分析編譯後的代碼構成。
class Parent {
constructor() {
this.type = 'parent';
}
sayHelloCommon() {}
sayHelloArrow = () => {};
}
class Child extends Parent {
constructor(props) {
super(props);
this.type = 'child';
}
}
2.Babel 的寄生式組合繼承
2.1 Babel 是如何實作原型方法的繼承
實作原型方法的繼承,最核心的是下面的_inherits 方法。
function _inherits(subClass, superClass) {
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true,
},
});
}
通過将子類的原型 prototype 設定為父類 prototype 的一個副本進而繼承父類的所有原型屬性、方法。
2.2 Babel 如何從父類繼承執行個體屬性
核心實作代碼如下,即通過 Child.__proto__ || Object.getPrototypeOf(Child)擷取父類的構造方法,接着通過 call 方法傳遞 this、執行個體屬性到父類中完成最終的建構。就這樣,子類執行個體即可擷取父類的執行個體屬性。
if (superClass)
Object.setPrototypeOf
? Object.setPrototypeOf(subClass, superClass)
: (subClass.__proto__ = superClass);
return _possibleConstructorReturn(
this,
(Child.__proto__ || Object.getPrototypeOf(Child)).call(this, props)
);
關于 setPrototypeOf、isPrototypeOf 的用法檢視下面示例即可:
const obj1 = {};
const obj2 = { foo: 'bar' };
Object.setPrototypeOf(obj1, obj2);
// setPrototypeOf
obj2.isPrototypeOf(obj1);
// true
obj1.__proto__ === obj2;
// true
Object.getPrototypeOf(obj1)
// {foo:"bar"}
Object.getPrototypeOf(obj1) === obj2
// 傳回true
3.Babel 編譯完整代碼
下面是示例代碼通過Babel編譯後的完整結果,關于編譯代碼的分析可以閱讀我的其他文章,這裡不再贅述。
'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 _possibleConstructorReturn(self, call) {
// 確定super被調用
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,
},
});
// 1.寄生式組合繼承
if (superClass)
Object.setPrototypeOf
? Object.setPrototypeOf(subClass, superClass)
: (subClass.__proto__ = superClass);
// 2.靜态資源通路
}
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError('Cannot call a class as a function');
}
}
var Parent = (function () {
function Parent() {
_classCallCheck(this, Parent);
// 箭頭函數放在類的執行個體this上
this.sayHelloArrow = function () {};
}
_createClass(Parent, [
{
// 正常函數放在類的原型prototype上
key: 'sayHelloCommon',
value: function sayHelloCommon() {},
},
]);
return Parent;
})();
var Child = (function (_Parent) {
_inherits(Child, _Parent);
// 保證繼承的父類是有效的
function Child(props) {
_classCallCheck(this, Child);
return _possibleConstructorReturn(
this,
(Child.__proto__ || Object.getPrototypeOf(Child)).call(this, props)
// Child.__proto__ || Object.getPrototypeOf(Child)指向了Parent
);
}
return Child;
})(Parent);
參考資料
https://blog.csdn.net/weixin_43276913/article/details/105821919