面向對象編程有三個特色: 繼承,封裝,多態編程
ES6以前的繼承,通常就是構造函數的繼承。ES6以後,通常就是類的繼承函數
分爲兩部分:this
1. 實例方法和屬性繼承spa
在子類構造函數中調用父類構造函數prototype
function Child() { Father.call(this); }
2. 原型屬性和方法繼承code
Child.prototype = Object.create(Father.prototype); Child.prototype.constructor = Child; // 構造函數的prototype賦值,函數會改變構造函數的指向
子類的實例this的生成基於父類的實例,因此必須先調用super(),獲取父類實例。以後才能使用this。對象
class Child extends Father{ constructor(props) { super(props); // =Father.prototype.constructor.call(this,props) } } // super的用法: 1)做爲父類構造函數,只能用在構造函數中 2)做爲原型對象,在普通函數中:super.xxx(); super至關於父類的原型對象(super.prototype.xxx.call(this)),裏面的this指向子類實例。 取不到子類的實例上面的屬性和方法!! 3)做爲父類,在靜態方法中使用super,至關於父類,裏面的this指向子類。
類的繼承的實現原理:blog
Object.setPrototypeOf(Child, Father); Object.serPrototypeOf(Child.prototype, Father.prototype); // 即兩條原型鏈以下 Child._proto_ = Father; Child.prototype._proto_ = Father.prototype;
ES6以前,即一個構造函數繼承多個構造函數。繼承
function Child() { Father1.call(this); Father2.call(this); } Child.prototype = Object.create(Father1.prototype); Object.assign(Child.prototype, Father2.prototype); Object.prototype.constructor = Child;
function mix(...mixins) { class Mix { constructor() { for (let mixin of mixins) { copyProperties(this, new mixin()); // 拷貝實例屬性 } } } for (let mixin of mixins) { copyProperties(Mix, mixin); // 拷貝靜態屬性 copyProperties(Mix.prototype, mixin.prototype); // 拷貝原型屬性 } return Mix; } function copyProperties(target, source) { for (let key of Reflect.ownKeys(source)) { if ( key !== 'constructor' && key !== 'prototype' && key !== 'name' ) { let desc = Object.getOwnPropertyDescriptor(source, key); Object.defineProperty(target, key, desc); } } }
ES5中沒有模塊的概念,能夠模擬實現將代碼封裝成模塊。接口
爲了避免污染全局變量,不暴露內部屬性,使用IIFE進行封裝,return須要暴露的接口。
(function(){ var _prop = ""; function test(){}; return { a: test } })();
若是想和其餘模塊或者全局變量交互,能夠經過IIFE的參數傳入
這樣能夠清晰的瞭解交互內容和依賴。
ES6中出現了"模塊"的概念。type="module";
模塊經過import和export實現輸入輸出。