widget.js中的構(gòu)造函數(shù)代碼this.handlers ={};需要去除。要在window.js的Window構(gòu)造函數(shù)中把this.handlers ={};補(bǔ)上。
抽取widget抽象類(lèi):widget.js中的構(gòu)造函數(shù)
?function?Widget(){ ??????this.handlers?={}; }
,和window.js里的
function?Window(){ ????this.handlers?={}; }
這個(gè)this.handlers ={};可以去除也只能去除一個(gè)【或者兩個(gè)都保存,保存的話(huà)引用的是window自己的handles】。而且應(yīng)該要去除Widget里的代碼
從面向?qū)ο蟮慕嵌葋?lái)說(shuō):對(duì)象的主要用途就是本身的屬性,方法,其實(shí)方法也是xxxObj.xxfun(),也可以理解為一種屬性。就是老師說(shuō)的字典,從這節(jié)的代碼來(lái)看,主要的作用是抽取handles這個(gè)obj放置在widget中,【PS:handles里面放的是各個(gè)類(lèi)型的事件數(shù)組】。源代碼中抽取了widget.js,然后再window.js中$.extends({},new widget.Widget(),{xxx:XXX})中就會(huì)把后面兩個(gè)對(duì)象的屬性和方法都掛載到了第一個(gè)對(duì)象{}上了。這時(shí)候,其實(shí)可以widget.js下的
function?Widget(){ ???this.handlers?={}; }
里的this.handlers ={};注釋掉。因?yàn)閒unction Window(){}構(gòu)造函數(shù)中已經(jīng)包含了這個(gè)定義了
function?Window(){??? ?????XXXX..; ????this.handlers?=?{}; }
而main.js中實(shí)例化對(duì)象 var win = new w.Window();new的過(guò)程中自然就擁有了Window構(gòu)造函數(shù)中的handles對(duì)象。實(shí)例win當(dāng)然可以正確引用到handle。而且,這樣引用的handler是自己實(shí)例中的handle,搜索樹(shù)會(huì)比較短。效率比較高。如果去除window構(gòu)造函數(shù)的this.handlers = {};這里引用的是window.js中
$.extends({},new?widget.Widget(),{xxx:XXX})
new new widget.Widget()產(chǎn)生的handles了?!緋s:注意new widget.Widget()之后就產(chǎn)生了一個(gè)對(duì)象,包含了{(lán)key:val}這里就包含了handle:{}這樣的key,val了】。
這時(shí)候(就是去除Window構(gòu)造函數(shù)的this.handlers?=?{};不去除widget.js的語(yǔ)句)那么搜索的時(shí)候搜索的是Window構(gòu)造函數(shù)原型鏈上的handler實(shí)例。所有的window對(duì)象都共享了這個(gè)prototype上的handle實(shí)例,所以會(huì)有bug。假設(shè)一個(gè)場(chǎng)景(index.html上初始化兩個(gè)按鈕,一個(gè)綁定了很多事件,一個(gè)不綁定)那么先點(diǎn)擊綁定事件的按鈕,彈出窗口(這個(gè)時(shí)候的窗口實(shí)例已經(jīng)綁定了多個(gè)事件),然后關(guān)閉窗口,再點(diǎn)擊不綁定事件的按鈕,那么同樣會(huì)彈出多個(gè)事件,因?yàn)楣蚕砹诉@個(gè)原型對(duì)象的handler實(shí)例。
簡(jiǎn)單的說(shuō)。 Window.prototype= $.extend({},new widget.Widget(), {xxxx}這句代碼執(zhí)行后,如果 Window構(gòu)造函數(shù)中去除this.handlers = {};,那么他找的是Window原型樹(shù)的handle;如果去除了widget構(gòu)造函數(shù)的this.handlers = {};那么找的是自己的handlers。
-----------------------------------------------------------------------------------------------------------------------
貼上主要代碼
main.js,已經(jīng)將jquery-ui下載到本地了。
/** ?*?Created?by?Administrator?on?2015/7/21. ?*/ require.config({ ????paths:{ ????????jquery:'jquery-2.1.1', ????????jqueryUI:?'jquery-ui' ????} }); require(['jquery','window'],function($,w){ ????$(function(){ ???????$("#btna").on('click',function(){ ???????????var?win?=?new??w.Window(); ???????????win.alert({ ???????????????width:300, ???????????????height:150, ???????????????y:50, ???????????????content:'hello', ???????????????title:'title', ???????????????hasCloseBtn:true, ???????????????skinClassName:'window_skin_a', ???????????????textAlertBtn:'hello', ???????????????dragHandle:'.window_header' ???????????}).on("alert",function(){ ????????????????alert("first?alert"); ????????????}).on('alert',function(){ ???????????????alert('second?alert'); ???????????}).on('alert',function(){ ???????????????alert("third?alsert"); ???????????}).on('close',function(){ ???????????????alert("second?close"); ???????????}) ???????}); ????????$("#btnb").on('click',function(){ ????????????var?win?=?new??w.Window(); ????????????win.alert({ ????????????????width:300, ????????????????height:150, ????????????????y:50, ????????????????content:'hello', ????????????????title:'title', ????????????????hasCloseBtn:true, ????????????????skinClassName:'window_skin_a', ????????????????textAlertBtn:'hello', ????????????????dragHandle:'.window_header' ????????????}); ????????}); ????}) })
widget.js
/** ?*?Created?by?Administrator?on?15-7-25. ?*/ define(function(){ ????function?Widget(){ ???????//?this.handlers?=?{}; ????} ????Widget.prototype?=?{ ????????on:function(type?,handler){ ????????????if(typeof?this.handlers[type]=='undefined'){ ????????????????this.handlers[type]?=[]; ????????????} ????????????this.handlers[type].push(handler); ????????????return?this; ????????}, ????????fire:function(type,data){ ????????????if(this.handlers[type]?instanceof??Array){ ????????????????var?handles=?this.handlers[type]; ????????????????for(var?i=?0,len=this.handlers[type].length;i<len;i++){ ????????????????????handles[i](data); ????????????????} ????????????} ????????} ????} ????return?{ ????????Widget:Widget//這里不能加(),不然就跑方法了。 ????} });
window.js
define(['widget','jquery','jqueryUI'],function(widget,$,$UI){ ????function?Window(){ ????????this.cfg={ ????????????width:500, ????????????height:300, ????????????content:'', ????????????handler4AlertBtn:null, ????????????handler4CloseBtn:null, ????????????hasMask:true, ????????????title:'system?title', ????????????text4AlertBtn:'sure', ????????????skinClassName:'', ????????????hasCloseBtn:false, ????????????isDraggable:true, ????????????dragHandle:null ????????}; ????????this.handlers?=?{}; ????}; ????Window.prototype=?$.extend({},new?widget.Widget(),?{ ????????alert:function(cfg){ ????????????var?CFG?=?$.extend(this.cfg,cfg); ????????????var?that?=?this; ????????????var?boundingBox?=?$('<div?class="window_boundingBox">'?+ ????????????????'<div?class="window_header">'+CFG.title+'</div>'?+ ????????????????'<div?class="window_body">'+CFG.content+'</div>'?+ ????????????????'<div?class="window_footer"><input?type="button"?class="window_alertBtn"?value="'+CFG.text4AlertBtn+'"/></div>'?+ ????????????????'</div>'); ????????????var?mask?=?null; ????????????if(CFG.hasMask){ ????????????????mask?=?$('<div?class="window_mask"></div>'); ????????????????mask.appendTo("body"); ????????????} ????????????if(CFG.isDraggable){ ????????????????if(CFG.dragHandle){ ????????????????????boundingBox.draggable({handle:CFG.dragHandle}); ????????????????}else{ ????????????????????boundingBox.draggable(); ????????????????} ????????????} ????????????boundingBox.appendTo("body"); ????????????if(CFG.skinClassName!==""){ ????????????????boundingBox.addClass(CFG.skinClassName); ????????????} ????????????if(CFG.hasCloseBtn){ ????????????????var?closeBtn?=?$('<span?class="window_closeBtn">X</span>'); ????????????????boundingBox.find(".window_header").append(closeBtn); ????????????????closeBtn.on("click",function(){ ????????????????????//?CFG.handler4CloseBtn&&CFG.handler4CloseBtn(); ????????????????????that.fire("close"); ????????????????????boundingBox.remove(); ????????????????????mask&&?mask.remove(); ????????????????}); ????????????} ????????????if(CFG.handler4CloseBtn){ ????????????????this.on('close',CFG.handler4AlertBtn); ????????????} ????????????if(CFG.handler4AlertBtn){ ????????????????this.on('alert',CFG.handler4CloseBtn); ????????????} ????????????var?btn?=?boundingBox.find(".window_footer?.window_alertBtn"); ????????????btn.on("click",function(){ ???????????????//?CFG.handler4AlertBtn&&CFG.handler4AlertBtn(); ????????????????that.fire("alert"); ????????????????boundingBox.remove(); ????????????????mask&&?mask.remove(); ????????????}); ????????????boundingBox.css({ ????????????????width:CFG.width+"px", ????????????????height:CFG.height+"px", ????????????????left:(CFG.x||(window.innerWidth-CFG.width)/2)+'px', ????????????????top:(CFG.y||(window.innerHeight-CFG.height)/2)+'px' ????????????}); ????????????return?this; ????????}, ????????prompt:function(){ ????????????console.log("prompt"); ????????}, ????????confirm:function(){ ????????????console.log("confirm"); ????????} ????}); ????return?{Window:Window}; })
index.html
<!DOCTYPE?html> <html> <head> ????<meta?charset="UTF-8"> ????<title></title> ????<link?href="css/base.css"?type="text/css"?rel="stylesheet"/> ????<link?href="css/window.css"?type="text/css"?rel="stylesheet"/> ????<script?src="js/require.js"?data-main="js/main.js"></script> </head> <body> ????<input?type="button"?value="alert"?id="btna"/> ????<input?type="button"?value="alert"?id="btnb"/> </body> </html>
2016-12-29
這個(gè)最佳的解決方案不是把父類(lèi)的this.handlers?={};移除 放入到windows
因?yàn)楝F(xiàn)在只有這么一個(gè)屬性。所以你可以這么做。如果有上百個(gè)。你要每個(gè)子類(lèi)都這么寫(xiě)嗎?那繼承就沒(méi)意義了
在子類(lèi)中以子類(lèi)作用域調(diào)用父類(lèi)構(gòu)造來(lái)解決這個(gè)問(wèn)題
子類(lèi)可以加入:
widget.Widget.call(this);
2016-08-10
之前就看過(guò)不甚理解,現(xiàn)在看完高程上的原型章節(jié)再回過(guò)頭來(lái)看樓主的說(shuō)法,加深不少印象,謝謝
2016-01-01
我也同意你的說(shuō)法