對(duì)javascript繼承的理解
由于javascript原生是不支持類的(ES6已經(jīng)支持class與extends),更不用談繼承、多態(tài)了,為了模擬出一些其它面向?qū)ο缶幊陶Z(yǔ)言的這些特性,有好多大牛寫了給出了實(shí)現(xiàn)方式,看了John Resig的《Simple JavaScript Inheritance》這篇文章,深深被折服了,原來(lái)短短幾十行javascript也可以這么強(qiáng)大、優(yōu)雅,下面以我的理解方式來(lái)解讀下。
主要實(shí)現(xiàn)了繼承、訪問(wèn)父類的重名方法(這里的實(shí)現(xiàn)方式太妙了),但遺憾的是不能實(shí)現(xiàn)成員變量/函數(shù)的隱藏。
(function(){ //設(shè)置標(biāo)志位,是new A()過(guò)程中還是 B=A.extends({/* */})過(guò)程中; var initializing = false, //fnTest 可取結(jié)果為倆正則對(duì)象 /\b_super\b/與 /.*/ //當(dāng)正則的test方法參數(shù)支持自動(dòng)調(diào)用toString()方法時(shí)取前面那個(gè) fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/; // 創(chuàng)建一個(gè)全局的 Class對(duì)象 this.Class = function(){}; // 創(chuàng)建繼承函數(shù) Class.extend = function(prop) { //此處把_super指向父類的prototype,屬性繼承時(shí)需要用其判斷父、子是否有同名方法 var _super = this.prototype; //開(kāi)始B=A.extends({/* */}); initializing = true; //實(shí)例化父類,并把父類的實(shí)例方法及屬性給prototype var prototype = new this(); initializing = false; //結(jié)束B(niǎo)=A.extends({/* */}); // 遍歷用戶傳入的用于構(gòu)建子類的對(duì)象 //處理的地方包括: //1、屬性直接存到prototype上 //2、方法中沒(méi)通過(guò)this._super()調(diào)用父類中的同名方法,則直接把該方法存到prototype上 //3、方法中有通過(guò)this._super()調(diào)用父類中的同名方法,則把如下過(guò)程包裹成一個(gè)函數(shù)存到prototype上: // 把this._super指向父類的同名方法,然后再調(diào)用子類的該方法并返回執(zhí)行結(jié)果 for (var name in prop) { // 循環(huán)體中看起來(lái)略微復(fù)雜,是整個(gè)代碼的精華所在 //簡(jiǎn)化下此過(guò)程就是 v = a && b && c ? d : e; 等同于 v = (a && b && c) ? d : e //該過(guò)程中主要運(yùn)用的就是邏輯運(yùn)算中的短路運(yùn)算 a,b,c全為true則v=d,否則v=e //a中判斷prop[name]是否是函數(shù),b中判斷父類中是否也有同名的name函數(shù),c主要判斷name函數(shù)中是否有調(diào)用父類的同名方法(即調(diào)用了this._super()) //d就是a,b,c同時(shí)滿足的時(shí)候,也就是說(shuō):name是函數(shù),且name函數(shù)存在與父類中,且子類的name函數(shù)需要調(diào)用了父類的同名函數(shù) //若a,b,c中有一項(xiàng)不滿足則直接把prop[name]給prototype[name] prototype[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ? (function(name, fn){ //首先,先決條件決定了prototype[name]是個(gè)函數(shù),所以先包裹一個(gè)函數(shù)返回 return function() { //作者這里備份,然后調(diào)用fn后又還原this._super //由于return的是一個(gè)function,具有延時(shí)調(diào)用的作用 所以在子類調(diào)用fn時(shí)this始終指向子類本身 //而這里的_super是父類的_super,與this._super并無(wú)關(guān)系,所以備份應(yīng)該是多余的 //var tmp = this._super; //this._super指向與fn(即prop[name])同名的父類方法,方便fn內(nèi)部調(diào)用 //這里是實(shí)現(xiàn)子類中通過(guò)this._super()調(diào)用父類同名函數(shù)的關(guān)鍵 this._super = _super[name]; //此時(shí)再調(diào)用子類,子類里面的this._super已經(jīng)指向了父類同名的函數(shù),即_super[name] var ret = fn.apply(this, arguments); //this._super = tmp; //返回執(zhí)行結(jié)果 return ret; }; })(name, prop[name]) : prop[name]; } //此“Class”與外頭那個(gè)“Class”是兩個(gè)東西 //這個(gè)Class實(shí)為子類的構(gòu)造函數(shù) function Class() { //不是A.extends({/* */})過(guò)程中 if ( !initializing && this.init ) this.init.apply(this, arguments); } //前面處理好的prototype綁定給子類的prototype Class.prototype = prototype; //修正構(gòu)造函數(shù) Class.prototype.constructor = Class; //賦予子類可被繼續(xù)繼承的功能 Class.extend = arguments.callee; return Class; }; })();
如果想更深入了解js繼承,請(qǐng)繼續(xù)往下查看文章
相關(guān)文章
javascript 同時(shí)在IE和FireFox獲取KeyCode的代碼
以前一直在IE8中測(cè)試網(wǎng)站,后來(lái)寫的一部分含有Ajax的代碼出現(xiàn)了故障,不得已下載了Firefox以及它的插件Firebug,才發(fā)現(xiàn),F(xiàn)F不支持windows.event事件。于是換了一種思路。2010-02-02JS控制網(wǎng)頁(yè)動(dòng)態(tài)生成任意行列數(shù)表格的方法
這篇文章主要介紹了JS控制網(wǎng)頁(yè)動(dòng)態(tài)生成任意行列數(shù)表格的方法,實(shí)例分析了javascript操作表格節(jié)點(diǎn)控制dom元素添加的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-03-03Javascript實(shí)現(xiàn)秒表計(jì)時(shí)游戲
這篇文章主要為大家詳細(xì)介紹了Javascript實(shí)現(xiàn)秒表計(jì)時(shí)游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05javascript 函數(shù)的暫停和恢復(fù)實(shí)例詳解
這篇文章主要介紹了javascript 函數(shù)的暫停和恢復(fù),結(jié)合實(shí)例形式詳細(xì)分析了javascript 函數(shù)的暫停和恢復(fù)相關(guān)原理、實(shí)現(xiàn)方法及操作注意事項(xiàng),需要的朋友可以參考下2020-04-04