面試中聊到的javascript中的繼承
物件導向程式設計是每次面試必問的知識點,而前端js如何實現繼承每次命中率高達80%
這不,近兩天我們面試時候,同事就問道面試者此問題,但是,不論之前自己做的回答,還是面試者的回答,基本都不太令人滿意
很大的原因是多數時候前端並不需要實現繼承,就jquery來說也基本上是一碼到底,沒有實現繼承,據我所知,也就prototype與ext實現過繼承
所以繼承對前端來說似乎不太適用
近兩年來情況有所變化,SPA的興起以及前端邏輯的複雜化,讓前端程式碼愈發的多,愈發的重,所以繼承慢慢的進入了一些初級一點的前端視野
所以,好好的瞭解如何實現繼承,繼承的幾個用法,是非常有意義的,就算只是為面試都是很有用的
實現繼承
當一個函式被建立時,Function建構函式產生的函式會隱式的被賦予一個prototype屬性,prototype包含一個constructor物件
而constructor便是該新函式物件(constructor意義不大,但是可以幫我們找到繼承關係)
每個函式都會有一個prototype屬性,該屬性指向另一物件,這個物件包含可以由特定型別的所有例項共享的屬性和方法
每次例項化後,例項內部都會包含一個[[prototype]](__proto__)的內部屬性,這個屬性指向prototype
① 我們透過isPrototypeOf來確定某個物件是不是我的原型 ② hasOwnPrototype 可以檢測一個屬性是存在例項中還是原型中,該屬性不是原型屬性才返回true
var Person = function (name, age) { this.name = name; this.age = age; }; Person.prototype.getName = function () { return this.name; }; var y = new Person('葉小釵', 30);
通俗一點來說,prototype是一模板,新建立物件就是對他一個複製,裡面的屬性或者方法都會賦值給例項
這裡說是模板賦值其實不太合理,反正由類產生的所有例項的__proto__都會共享一個prototype,這裡我做一個例子
我們在斷點情況下是沒有name2屬性的,但是我們如果在斷點下加上這個程式碼的話,a.name2,就有值了
Klass.prototype.name2 = '222';
所以,這裡說模板,不如說是指標指向,都是共享一個物件;繼承的情況的話就是這樣
(function () { var Person = function (name) { this.name = name; }; //Person.prototype = {};//這句將影響十分具有constructor屬性 Person.prototype.getName = function () { return this.name; }; var Student = function (name, sex, id) { this.name = name || '無名氏'; this.sex = sex || '不明'; this.id = id || '未填'; //學號 }; //相當於將其prototype複製了一次,若是包含constructor的話將指向Person Student.prototype = new Person(); Student.prototype.getId = function () { return this.id; } var y = new Person(); var s = new Student; var s1 = y instanceof Person; var s2 = s instanceof Student; var s3 = s instanceof Person; var s4 = Student.prototype.constructor === Person; var s5 = Student.constructor === Person; var s6 = Student.constructor === Function; var s = ''; })();
prototype實現繼承
我們在具體專案中,真正複雜一點的專案可能就會對繼承進行封裝,讓自己更好的使用,我們下面就來看看prototype怎麼幹的
PS:我這裡做了一點小的修改:
1 var Class = (function () { 2 function subclass() { }; 3 4 //我們構建一個類可以傳兩個引數,第一個為需要繼承的類, 5 //如果沒有的話就一定會有第二個物件,就是其原型屬性以及方法,其中initialize為建構函式的入口 6 function create() { 7 8 //此處兩個屬性一個是被繼承的類,一個為原型方法 9 var parent = null; 10 var properties = $A(arguments); 11 12 if (Object.isFunction(properties[0])) 13 parent = properties.shift(); 14 15 //新建類,這個類最好會被返回,建構函式入口為initialize原型方法 16 function klass() { 17 this.initialize.apply(this, arguments); 18 } 19 20 //擴充套件klass類的“例項”物件(非原型),為其增加addMethods方法 21 Object.extend(klass, Class.Methods); 22 23 //為其指定父類,沒有就為空 24 klass.superclass = parent; 25 26 //其子類集合(require情況下不一定準確) 27 klass.subclasses = []; 28 29 //如果存在父類就需要繼承 30 if (parent) { 31 //新建一個空類用以繼承,其存在的意義是不希望建構函式被執行 32 //比如 klass.prototype = new parent;就會執行其initialize方法 33 subclass.prototype = parent.prototype; 34 klass.prototype = new subclass; 35 parent.subclasses.push(klass); 36 } 37 38 //遍歷物件(其實此處這樣做意義不大,我們可以強制最多給兩個引數) 39 //注意,此處為一個難點,需要謹慎,進入addMethods 40 for (var i = 0, length = properties.length; i下面來一個簡單的例子:
1 var Person = Class.create({ 2 initialize: function (name) { 3 this.name = name; 4 }, 5 getName: function () { 6 console.log('我是父類'); 7 return this.name; 8 }, 9 getAge: function () { 10 return this.age; 11 } 12 }); 13 14 var Employee = Class.create(Person, { 15 initialize: function ($super, name, age) { 16 $super(name); 17 this.age = age; 18 }, 19 getName: function ($super) { 20 return '我是子類:' + $super(); 21 } 22 }); 23 24 var C = Class.create(Employee, { 25 getAge: function ($super) { 26 return $super(); 27 } 28 }); 29 30 var y = new C("葉小釵", 25); 31 console.log(y.getName() + ': ' + y.getAge());這裡,我們根據自己的需求重寫寫了下繼承相關程式碼,表現基本與上述一致,各位可以自己試試
PS:當然如果有問題請指出
簡化prototype繼承
1 var arr = []; 2 var slice = arr.slice; 3 4 function create() { 5 if (arguments.length == 0 || arguments.length > 2) throw '引數錯誤'; 6 7 var parent = null; 8 //將引數轉換為陣列 9 var properties = slice.call(arguments); 10 11 //如果第一個引數為類(function),那麼就將之取出 12 if (typeof properties[0] === 'function') 13 parent = properties.shift(); 14 properties = properties[0]; 15 16 function klass() { 17 this.initialize.apply(this, arguments); 18 } 19 20 klass.superclass = parent; 21 klass.subclasses = []; 22 23 if (parent) { 24 var subclass = function () { }; 25 subclass.prototype = parent.prototype; 26 klass.prototype = new subclass; 27 parent.subclasses.push(klass); 28 } 29 30 var ancestor = klass.superclass && klass.superclass.prototype; 31 for (var k in properties) { 32 var value = properties[k]; 33 34 //滿足條件就重寫 35 if (ancestor && typeof value == 'function') { 36 var argslist = /^s*functions*(([^()]*?))s*?{/i.exec(value.toString())[1].replace(/s/i, '').split(','); 37 //只有在第一個引數為$super情況下才需要處理(是否具有重複方法需要使用者自己決定) 38 if (argslist[0] === '$super' && ancestor[k]) { 39 value = (function (methodName, fn) { 40 return function () { 41 var scope = this; 42 var args = [function () { 43 return ancestor[methodName].apply(scope, arguments); 44 } ]; 45 return fn.apply(this, args.concat(slice.call(arguments))); 46 }; 47 })(k, value); 48 } 49 } 50 51 klass.prototype[k] = value; 52 } 53 54 if (!klass.prototype.initialize) 55 klass.prototype.initialize = function () { }; 56 57 klass.prototype.constructor = klass; 58 59 return klass; 60 }如此,我們就完成了自己的繼承了
實戰繼承
知道原型可以實現繼承是皮毛,知道各個庫是怎樣乾的也只是入門
因為,要在專案中用到才能算真正掌握繼承,這裡我們便來點實戰的小例子
這裡我寫一個簡單的view用於下面各種繼承1 var AbstractView = create({ 2 initialize: function (opts) { 3 opts = opts || {}; 4 this.wrapper = opts.wrapper || $('body'); 5 6 //事件集合 7 this.events = {}; 8 9 this.isCreate = false; 10 11 }, 12 on: function (type, fn) { 13 if (!this.events[type]) this.events[type] = []; 14 this.events[type].push(fn); 15 }, 16 trigger: function (type) { 17 if (!this.events[type]) return; 18 for (var i = 0, len = this.events[type].length; i 這裡是alert框
' + this.title + '
這裡是帶標題alert框來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4479/viewspace-2800757/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- JavaScript中的繼承JavaScript繼承
- JavaScript中的六種繼承JavaScript繼承
- JavaScript中的函式繼承JavaScript函式繼承
- 淺談JavaScript中的繼承JavaScript繼承
- JavaScript中的原型和繼承JavaScript原型繼承
- 徹底搞懂JavaScript中的繼承JavaScript繼承
- JavaScript 中的六種繼承方式JavaScript繼承
- JavaScript中的繼承和組合JavaScript繼承
- 深入理解JavaScript中的類繼承JavaScript繼承
- 征服 JavaScript 面試:類繼承和原型繼承的區別JavaScript面試繼承原型
- JavaScript中的繼承及實現程式碼JavaScript繼承
- JavaScript中class繼承超乎你的想象《一》JavaScript繼承
- Javascript中的幾種繼承方式比較JavaScript繼承
- PostgreSQL中的繼承SQL繼承
- JS中的繼承JS繼承
- java中的繼承Java繼承
- 【面試必備】javascript的原型和繼承面試JavaScript原型繼承
- [譯] 繼承 JavaScript 類中的靜態屬性繼承JavaScript
- 深入理解javascript中的繼承機制(1)JavaScript繼承
- JavaScript的繼承JavaScript繼承
- 聊聊JS中的繼承JS繼承
- JS中的繼承(上)JS繼承
- JS中的繼承(下)JS繼承
- Solidity中的繼承Solid繼承
- C++中的繼承C++繼承
- C++中公有繼承、保護繼承、私有繼承的區別C++繼承
- Java面試題:Java中的集合及其繼承關係Java面試題繼承
- 物件導向-繼承中的面試題:程式碼塊物件繼承面試題
- Javascript 中實現物件原型繼承的三種方式JavaScript物件原型繼承
- Javascript繼承4:潔淨的繼承者—-原型式繼承JavaScript繼承原型
- javascript繼承的方式JavaScript繼承
- javascript的superclass繼承JavaScript繼承
- JS中繼承的實現JS中繼繼承
- C#中的繼承(一)C#繼承
- C#中的繼承(二)C#繼承
- C#中類的繼承C#繼承
- java中繼承Java中繼繼承
- ES6中的類繼承和ES5中的繼承模式詳解繼承模式