您好,登錄后才能下訂單哦!
本篇內容介紹了“JavaScript繼承方式介紹”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
1、構造函數方式寫類,通過方法調用復制父類屬性/字段到子類 實現繼承
這里父類,子類都采用構造函數方式寫,不用原型。子類調用父類函數來復制父類的屬性。
/** * 父類Polygon:多邊形 * @param {Object} sides */ function Polygon(sides) { this.sides = sides; this.setSides = function(s) {this.sides=s;} } /** * 子類Triangle:三角形 */ function Triangle() { this.tempfun = Polygon;//父類引用賦值給子類的一個屬性tempfun this.tempfun(3);//調用 delete this.tempfun;//刪除該屬性 this.getArea = function(){}; } //new個對象 var tri = new Triangle(); console.log(tri.sides);//繼承的屬性 console.log(tri.setSides);//繼承的方法 console.log(tri.getArea);//自有的方法 //缺點是對于Triangle的實例對象用instanceof為父類Polygon時是false console.log(tri instanceof Triangle);//true console.log(tri instanceof Polygon);//false
因為 JavaScript中具名函數的多種調用方式 ,子類還可以有以下的多種實現方式。只是在子類中調用父類方法不同而已。
function Triangle() { Polygon.call(this,3); //call方式調用父類 this.getArea = function(){}; } function Triangle() { Polygon.apply(this,[3]); //apply方式調用父類 this.getArea = function(){}; } function Triangle() { var temp = new Polygon(3); //new方式調用父類 for(atr in temp) { //全部復制給子類 this[atr] = temp[atr]; } this.getArea = function(){}; }
這種方式的缺點是子類的實例對象用instanceof檢查父類時總是false。這與java中繼承"is a "的關系是違背的。
2、原型方式寫類,原型方式繼承
core JS自身的對象系統就是采用原型方式(prototype based)繼承的。或者說core JS沒有采用常見的類繼承(class based)系統,而是使用原型繼承來實現自己的對象系統。工作中我們也可以用原型方式來實現繼承,代碼復用以構建自己的功能模塊。
/** * 父類Polygon:多邊形 * */ function Polygon() {} Polygon.prototype.sides = 0; Polygon.prototype.setSides = function(s) {this.sides=s;} /** * 子類Triangle:三角形 */ function Triangle() {} Triangle.prototype = new Polygon(); //這是原型繼承關鍵的一句 Triangle.prototype.getArea = function(){} //new個對象 var tri = new Triangle(); console.log(tri.sides);//繼承的屬性 console.log(tri.setSides);//繼承的方法 console.log(tri.getArea);//自有方法 //instanceof測試 console.log(tri instanceof Triangle);//true,表明該對象是三角形 console.log(tri instanceof Polygon);//true,表明三角形也是多邊形
雖然從輸出可以看出子類繼承了父類Polygon的屬性sides和方法setSides,但sides是0,怎么會是三角形呢。還得調用下tri.setSides(3)使之成為三角形。這樣似乎很不方便。不能傳參數,即是原型方式的缺點。優點是正確的維護了"is a"的關系。
3、組合構造函數/原型方式寫類,采用前面種方式繼承
這種方式父類,子類的屬性都掛在構造函數里,方法都掛在原型上。
/** * 父類Polygon:多邊形 */ function Polygon(sides) { this.sides = sides; } Polygon.prototype.setSides = function(s) {this.sides=s;} /** * Triangle 三角形 * @param {Object} base 底 * @param {Object} height 高 */ function Triangle(base,height) { Polygon.call(this,3);//復制父類屬性給自己 this.base = base; this.height = height; } Triangle.prototype = new Polygon();//復制父類方法給自己 Triangle.prototype.getArea = function(){ //***定義自己的方法 return this.base*this.height/2; } //new個對象 var tri = new Triangle(12,4); console.log(tri.sides);//繼承的屬性 console.log(tri.setSides);//繼承的方法 console.log(tri.base);//自有屬性 console.log(tri.height);//自有屬性 console.log(tri.getArea);//自有方法 //instanceof測試,表明正確的維護了"is a"的關系 console.log(tri instanceof Triangle);//true,表明該對象是三角形 console.log(tri instanceof Polygon);//true,表明三角形也是多邊形
這篇開始寫幾個工具函數實現類的擴展。每個工具函數都是針對特定的寫類方式(習慣)。這篇按照構造函數方式寫類:屬性(字段)和方法都掛在this上。以下分別提供了個類,分別作為父類和子類。
// 父類Person function Person(nationality) { this.nationality = nationality; this.setNationality = function(n) {this.nationality=n;}; this.getNationality = function() {return this.nationality;}; } // 類Man function Man(name) { this.name = name; this.setName = function(n){this.name=n;}; this.getName = function(){return this.name;}; }
繼承工具函數一
/** * @param {Function} subCls 子類 * @param {Function} superCls 父類 * @param {Object} param 父類構造參數 */ function extend(subCls,superCls,param) { superCls.call(subCls.prototype,param); }
使用如下
extend(Man,Person,'China'); var m = new Man('jack'); console.log(m.nationality);//China console.log(m.setNationality('Japan')); console.log(m.getNationality('Japan'));//Japan
輸出可以看到Man繼承了Person的屬性及所有方法。這種繼承方式于java的很不一樣哦,
class Animal { int legs; Animal(int l) { legs = l; } int getLegs() { return legs; } } public class Person extends Animal{ //屬性(字段) String name; //構造方法(函數) Person(int legs, String name) { super(legs);//調用父類構造器 this.name = name; } //方法 String getName() { return this.name; } public static void main(String[] args) { Person p = new Person(2,"jack"); System.out.println(p.legs); } }
Java中,子類Person在自身構造方法中調用父類構造方法super(legs),創建對象的時候直接將父類構造參數legs:2傳進去,不僅僅只傳自己的name:jack。上面JavaScript繼承是在extend時傳父類構造參數(extend函數的第三個參數),而不是在new Man時將父類構造參數傳過去。好,模擬Java來實現下extend,這里巧妙的在子類上暫存了父類引用。
繼承工具函數二
/** * @param {Function} subCls * @param {Function} superCls */ function extend(subCls,superCls) { subCls.supr = superCls; }
還是以Person為父類,來實現子類Woman
function Woman(nationality,name) { Woman.supr.call(this,nationality);//和java有點類似哦,在子類中調用父類構造器 this.name = name; this.setName = function(n){this.name=n;}; this.getName = function(){return this.name;}; }<br>extend(Woman,Person);<br>
***,創建對象的方式和java也類似,即new的時候同時將父類構造參數(nationality:Japan)傳進去。
var w = new Woman('Japan','lily'); console.log(w.nationality);//Japan w.setNationality('U.S.A'); console.log(w.getNationality());//U.S.A
繼承工具函數三
/** * @param {Function} subCls * @param {Function} superCls */ function extend(subCls,superCls) { subCls.prototype = new superCls(); }
父類,按原型方式寫,即屬性和方法都掛在原型上。
/** * 父類Person */ function Person(){} Person.prototype.nationality = 'China'; Person.prototype.getNationality = function() {return this.nationality;} Person.prototype.setNationality = function(n) { this.nationality = n;}
子類繼承與父類
function Man() {} extend(Man,Person);
繼承父類的屬性和方法后,再添加子類自有屬性,方法
Man.prototype.name = 'jack'; Man.prototype.getName = function() { return this.name;} Man.prototype.setName = function(n) { this.name=n;}
測試如下,
var m = new Man(); console.log(m); console.log(m instanceof Person);
可以看到這種寫類方式,繼承方式完全采用原型機制。
繼承工具函數四
這種方式是目前比較流行的,51ditu網站的開發就是按照這種模式的。
/** * @param {Function} subCls 子類 * @param {Function} superCls 父類 */ function extend(subCls,superCls) { //暫存子類原型 var sbp = subCls.prototype; //重寫子類原型--原型繼承 subCls.prototype = new superCls(); //重寫后一定要將constructor指回subCls subCls.prototype.constructor = subCls; //還原子類原型 for(var atr in sbp) { subCls.prototype[atr] = sbp[atr]; } //暫存父類 subCls.supr = superCls; }
按 構造函數+原型 方式寫類,即屬性掛在this上,方法掛在prototype上。
/** * 父類Person */ function Person(nationality){ this.nationality = nationality; } Person.prototype.getNationality = function() {return this.nationality;} Person.prototype.setNationality = function(n) { this.nationality = n;} /** * 子類Man */ function Man(nationality,name) { Man.supr.call(this,nationality); //很重要的一句,調用父類構造器 this.name = name; } Man.prototype.getName = function() {return this.name;} Man.prototype.setName = function(n) {this.name=n;}
注意子類Man中要顯示的調用父類構造器已完成父類的屬性/字段拷貝。
extend調用,創建Man的實例
extend(Man,Person); var m = new Man('USA','jack'); console.log(m); m.setName('lily'); console.log(m.name);
繼承工具函數五
/** * @param {String} className * @param {String/Function} superClass * @param {Function} classImp */ function $class(className, superClass, classImp){ if(superClass === "") superClass = Object; var clazz = function(){ return function(){ if(typeof this.init == "function"){ this.init.apply(this, arguments); } }; }(); var p = clazz.prototype = new superClass(); var _super = superClass.prototype; window[className] = clazz; classImp.apply(p, [_super]); }
定義父類Person
/** * 父類 Person */ $class('Person','',function(){ this.init = function(name){ this.name = name; }; this.getName = function(){ return this.name; }; this.setName = function(name){ this.name = name; } });
子類Man
/** * 子類 Man */ $class('Man', Person, function(supr){ this.init = function(name, age){ supr.init.apply(this,[name]); // 該句很重要 this.age = age; }; this.getAge = function(){ return this.age; }; this.setAge = function(age){ this.age = age; }; }); var m = new Man('Jack',25); console.log(m.name); // Jack console.log(m.age); // 25
從輸出看可以看到子類Man的確繼承了父類的屬性和方法。
“JavaScript繼承方式介紹”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。