簡單的多態
多態:
1.同一個接口,在不同情況下做不一樣的事情;相同的接口,不同的表現;
2.接口本身只是一組定義,實現都是子類里面;需要子類去實現的方法(子類只需重寫與父類同名的方法,即可達到覆蓋的效果),若子類有跟父類同名的方法,則會直接走子類的方法,不會走父類的;
3.非靜態方法中,仍然子類可通過super..方法名( )(舉例:super.say( ) ),來調用父類的方法(supe指向的事父類的原型)
重載:根據函數的參數類型,參數個數
作用:為一個函數提供了更豐富的行為
js的重載和其他語言的重載是完全不一樣的概念。因為js是一門弱類型語言, JS中函數可以傳入任意類型、任意個數的參數,通通可以通過在函數內使用this.arguments獲得。這樣,就無法實現同名函數參數列表不同實現不同功能。 而且js不是一個面向對象的語言, 即使在ES6中引入了Class類的概念, 但這只是一種語法糖, js並沒有實現真正的面向對象。 這里的重載其實可以簡單的理解就是為函數提供更豐富的行為
1. 父類的原型對象,是指父類的屬性prototype,二者不是一個東西,原型對象prototype上可以保存父類的一些方法(es6中,父類的屬性不放在原型對象上)。
2. 父類的原型對象的方法,是在constructor外面定義的,
2.“父類自身的方法”,則是直接在類身上定義的方法,
如果是指“父類原型上的方法”,則是在constructor外面定義的(第一張圖);如果是指“父類構造函數上的方法”,則是指在constructor里面定義的,
es6的構造函數constructor相當於es5的構造函數本身,它倆的作用都是給實例添加屬性,與es5的構造函數的原型對象prototype上的constructor不是一個東西。
super方法,用來繼承父類,所以super里的參數,是實例的屬性,在class外面,可以被實例直接訪問
//多態就是同一個接口,在不同情況下做不一樣的事情。即相同的接口,不同的表現
//接口本身只是一組定義,實現都是在類里面.可以直接理解成需要子類去實現的方法,子類只要重寫一個和父類同名的方法,就可以達到一個覆蓋的效果
//多態的優點,1、提高類的擴充性與靈活性
//2,暴露接口
//重寫 class Human{ say(){ console.log('我是人') } } //子類如果擁有父類的同名方法,則會直接調用子類的方法,不會去走父 類的 class Man extends Human{ say(){ super.say() //輸出 我是人 console.log('我是小哥哥') } } class Woman extends Human{ //有的時候子類自己實現的內容,還是依賴父類中的一些操作,可以通過super.xxx的方式去進行訪問 say(){ super.say(); //訪問父類的同名方法,這里super是作為對象的形式去訪問,在非靜態方法中訪問到的是父類的原型 console.log('我是小姐姐') } } new Man().say(); new Woman().say();
、
重載 是根據函數的參數類型以及參數個數去做不一樣的事情,
class SimpleCalc{ addCalc(...args){ if(args.length === 0){ return this.zero(); } if(args.length === 1){ return this.onlyOneArgument(args); } return this.add(args); } zero(){ return 0; } onlyOneArgument(){ return args[0]; } add(args){ return args.reduce((a,b) => a+b , 0) //返回a+b,從0開始作為基數傳遞 } }
重載的其他場景:比如一個Ajax的封裝,寫函數的時候非常常見
function post(url,header,params){ if(!params){ params = header; header = null; //或者等於undefined也可以 } } post('https://imooc.com',{ a:1, b:2 });
//一個非常實用的場景,利用重寫的特性,達到預留接口的效果
//比如有方法必須要用子類去實現,如果沒有就報錯
class Monster{ constructor(name,level,model){ this.model = model; this.name = name; this.level = level; } attack(){ throw Error('必須由子類來實現`attack`(攻擊)方法') } } //模型的映射表 const ModelMap = { '紅眼僵屍':1, '南瓜精':2, '獨眼蝠':3, '綠眼僵屍':4 } class RedEyeZombie extends Monster{ //這邊的構造函數不用接收參數,因為它的參數開發者是非常明確地,是不需要外部傳入的 constructor(){ //通過ModelMap['紅眼僵屍']可以訪問到模型對應的ID super('紅眼僵屍',10,ModelMap['紅眼僵屍']); } } class GreenEyeZombie extends Monster{ constructor(){ super('綠眼僵屍',10,ModelMap['綠眼僵屍']) } attack(){ console.log('綠眼僵屍發動了攻擊') } } const gez = new GreenEyeZombie(); //覆蓋了父類的attack方法 gez.attack(); const rez = new RedEyeZombie(); //子類沒有attack,所以去調用父類的,報錯 rez.attack();