1. 程式人生 > >如何把js的程式碼寫的更加容易維護(一)--面向物件程式設計

如何把js的程式碼寫的更加容易維護(一)--面向物件程式設計

總是頭疼javascript的程式碼寫起來不可維護,那麼看看下面的程式碼:

 1 (function (w, $) {
 2   var app = {
 3     init: function () {
 4       var me = this;
 5       me.render();
 6       me.bind();
 7     },
 8     datas: {
 9       num: 1
10     },
11     render: function () {
12       var me = this;
13       me.test = $('#table td');
14 }, 15 bind: function () { 16 var me = this; 17 me.test.on('click', $.proxy(me['_do'], this)); 18 }, 19 _do: function (e) { 20 var m = $(e.target).text(); 21 var me = this; 22 m = me.datas.num + m; 23 var s = '<input type="text" value="' + m + '">';
24 $(e.target).html(s); 25 } 26 }; 27 28 app.init(); 29 exports = app; 30 })(window, jQuery);

程式碼其實很簡單,其基本思路就是,將資料、函式、事件監聽和回撥都封裝在一個物件中,那麼我們可以簡單的把這個物件理解為一個元件。

封裝的難點:事件監聽和回撥

封裝的難點其實在於事件的監聽和回撥,先看一個簡單的實現:

1     bind: function () {
2       var me = this;
3       me.test.on('click', function
(e) { 4 // 操作 5 }); 6 },

就是以匿名函式的形式寫回調函式,可以滿足需求,但如果有大量的事件需要監聽、繫結回撥函式時,這種方式顯然就不太合理了:bind方法會變得過長而不好維護,那麼以傳入具名函式函式名的方式就可以解決這個問題,但是會遇到回撥函式中的this不是指向app物件而指向觸發元素的問題:

 1     bind: function () {
 2       var me = this;
 3       me.test.on('click', me['_do']);
 4     },
 5     _do: function(e) {
 6         // 這裡的this指向誰?
 7     var targetEle = $(e.target);
 8         // 這裡的this顯然指的是觸發事件的元素,在這裡是一個jQuery物件
 9         var me = this;
10     // 下面這句就會報錯
11     m = me.datas.num + m;
12     }

那麼如何解決上面的問題,答案就是$.proxy(fn, contenxt),這個方法可以改變函式執行時的上下文:

1     bind: function () {
2       var me = this;
3       me.test.on('click', $.proxy(me['_do'], this));
4     },

上面的程式碼使me['_do']被呼叫時,this指向app,那麼在me['_do']中就可以獲取app中的資料,從而解決了上面this的指向問題。

總結
上面的js程式碼實現了一個簡陋的可編輯表格的功能,這段程式碼是京程一燈袁志佳在騰訊視訊公開課上講的程式碼,我貼在這裡來提醒自己:前端javascript的編寫還有許多要學習和挖掘的地方。程式碼中主要用到了jQuery.proxy()這個強大的函式,另外就是這種物件封裝的思想。

存在的問題

雖然$.proxy()解決了this的指向問題,但它也不是完美的。這裡在使用事件委託時就要小心了:

 1     render: function () {
 2       var me = this;
 3       me.document= $(document);
 4     },
 5     bind: function() {
 6       document.on('click', 'ul li', $.proxy(me['_do2'], this));
 7     },
 8     _do2: function(e) {
 9         var eleTarget = $(e.target);
10     }

因為_do2中的this不再指向繫結事件的元素ul li,所以要想在_do2中獲取ul li就有些麻煩,尤其是li中巢狀比較多的子元素時:

1 <ul>
2   <li>
3     <div><span></span>...</div>
4   </li>
5 </ul>

_do2中的eleTarget由於事件冒泡的原因可能是:span、div、li,那麼該如何解決這個問題?很遺憾我沒有想到好的解決方法,提供兩個思路:1,如果li中嵌套了太多的子元素,那麼事件委託在這裡就不是一個好的解決方案了。2,如果巢狀的子元素不多,那麼還可以通過查詢的方法找到ul li,這個也是可行的。當然,如果拋開本文章,單純使用事件委託還是可以的:

1 $(document).on('click', 'ul li', function(e) {
2   var this = $(this); 
3 });

因為這裡的this始終指向ul li,即委託的元素ul li。