Comments

zsh feature:(oh my zsh —> agnoster themeplate)

  1. 只要按tab鍵即可快速顯示該層資料夾,並可用鍵盤去做選擇
  2. 可自定義快捷鍵

    ex. git commit -am ‘update’可去自行設成 git ac ‘update’

  3. 常用語法打錯會有防錯機制

    ex. ls打成sl他會自動判定成ls

  4. 明確的顏色顯示該專案是否有東西更新(需要commit),以及現在的分支是master還是其他分支

Install steps:

  1. sudo apt-get install zsh
  2. curl -L https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh | sudo sh
  3. vim ~/.zshrc 改這行:ZSH_THEME=“agnoster”
  4. 若不喜歡中間的pwd路徑的話 去 vim ~/.oh-my-zsh,把

    # Dir: current working directory

    prompt_dir() { prompt_segment blue black ‘%~’ } 的’%~‘改成’%c’

  5. 其他參照: https://gist.github.com/agnoster/3712874

  6. 文字亂碼部分: https://gist.github.com/qrush/1595572

  7. 遇到的ubuntu上亂碼問題: https://github.com/robbyrussell/oh-my-zsh/issues/1906

    cd ~/.oh-my-zsh/themes/ git checkout d6a36b1 agnoster.zsh-theme

Comments

淺談Hammer.js

首先,先提一下為何用Hammer.js的原因:

1.他把在Html5裡的gesture和touch事件與原來傳統mouse事件做結合
2.有針對各手指去做追蹤
3.多功能的event事件

最後,結合以上….只需要2KB,實在沒有不用它的道理!

關於第一點,我們來看看他的lib (hammer.js)

在line 556開始,我們可以看到它把mouse event 與其他事件綁在一起

//line 561.562
case 'mousedown':
case 'touchstart':

//line 585.586
case 'mousemove':
case 'touchmove':

//line 609~612
case 'mouseup':
case 'mouseout':
case 'touchcancel':
case 'touchend':

簡單來講,這樣的好處就是,今天只要寫一行 event 就可以把用滑鼠的user與用觸控板的user發生的行為考慮進去

第二點,對於個別手指的追

//line 561.562
case 'mousedown':
case 'touchstart':

//line 585.586
case 'mousemove':
case 'touchmove':

這兩行在處理的第一件事情,就是去做計算各手指,如下:

count = countFingers(event);

//來追蹤一下countFingers在做什麼事情

function countFingers( event )
{
    return event.touches ? event.touches.length : 1;
}

但是請注意它的註解

// there is a bug on android (until v4?) that touches is always 1,
// so no multitouch is supported, e.g. no, zoom and rotation...

這點我在於android 2.7的確是array為1 ,因此我建議,每次在取個手指的行為時,盡量用迴圈去偵測它(從0開始)

接下來,每個事件可以取用的行為資料也不一樣,舉例來說:

//line 561開始
case 'mousedown':
case 'touchstart':

triggerEvent("dragend", {
    originalEvent   : event,
    direction       : _direction,
    distance        : _distance,
    angle           : _angle
});
//可取的資料就是direction , distance , angle

其他同理可看出,整理如下

1.mousedown , touchstart部分:
    direction : 上下左右  其他方向不行
    distance : 距離 (單位象素.有浮點數)
    angle :角度

2.mousemove , touchmove':
    無

3.mouseup , mouseout , touchcancel , touchend :
    這邊判斷式稍多,主要是先偵測他之前的行為是什麼?(drag? or transform?)
    之後呈現:
        position : X.Y 座標

至於,在View端的簡單範例寫法如下,:

(function ($) {
    var $sw = $('#swipeme'),
        $output = $('#output');

    $sw.on('hold tap swipe doubletap transformstart transform transformend dragstart drag dragend swipe release', function (event) {
        event.preventDefault();

        $output.prepend("Type: " + event.type + ", Fingers: " + event.touches.length + ", Direction: " + event.direction + ", distance: "+ event.distance +"<br/>");
    });
    //上述你可以加進想要呈現的data
    // this is how you unbind an event
    /*$sw.on('swipe', function (event) {
        event.preventDefault();

        $sw.off('tap');
    });*/
}(jQuery));

有人會問,為何要寫”event.preventDefault();“?

因為我們在使用觸控螢幕時,有些手勢是該平板預設的放大縮小行為,可是這個行為在瀏覽器上我們不打算這樣做,用這個語法可以防止這種現象。

Comments

不用this (oo)的寫法:

var yoyo ={

    a:function(){
        //blabla...
    }
    b:function(){
        //blabla...
    }

}
yoyo.a();

用this (oo)的寫法:

var hihi = function (){
    this.a = function(){
        console.log('a');
    }
    this.b = function (){
        console.log('b');
    }
}
var hihi2 = new hihi;  //注意  這邊寫 new hihi(); 也可以
hihi2.a();   // a

prototype 繼承演示

var hihi = function (){
    this.a = function(){
        //blabla
    }
    this.b = function (){
        //blabla
    }
}

今天若想繼承上列,再加個hihi內個下列類別:

var yoyo = function(){
    this.c = function (){
        console.log('c');
    }
}

要先

yoyo.prototype = new hihi;
var show = new yoyo; 

show.a(); // a  
show.c(); // c

網路上看過一些繼承.洗掉問題

var ccc = function (){};
ccc.prototype.yoyo = function(){
    console.log('123')
}
ccc.prototype.titi = function(){
    console.log('456');
}
//ccc.prototype={};//因為這個已經把東西洗掉,所以其他人沒得繼承
var eee = new ccc();
var fff = new ccc();
eee.yoyo = function(){
    console.log('777');
}
ccc.prototype={};  //因為先前已經繼承過了,所以東西還在
eee.yoyo();
fff.yoyo();

再來,想來聊聊效能問題,網路上有人寫了這篇測試文

http://jsperf.com/prototype-operator-performance

他比較了三種方法:

A: 正是我上述提到的this(OO)寫法
B: 與我上述提到的繼承部分,額外加類別進prototype方法
C: 一般的prototype寫法

有興趣可以看這作者blog的比較文

http://fred-zone.blogspot.tw/2012/04/javascript-class.html

直接提結論:

單純比較 呼叫方法(Call Method) ,不使用 Prototype 略勝一疇
比較建立實例(Instance) 的速度,使用 Prototype 快過其他實作近 20 倍,且B方法速度也快過其他方式
Comments

Let’s talk about Array and Object on data access application (by javascript).

——Array

Basic operating: Read a array:

var user = ['blue','tony','chen'];
console.log(user[0]);//'blue'

Add a element into a array:

var aaa = new Array();
aaa.push('123');
aaa.push('456'); 
console.log(aaa)// ['123','456']

Object

Basic operating: Read a Object:

var info = { user:'blue'};
console.log(info.user);//'blue';

add a Object:

var info ={}
info.user = 'blue';
console.log(info);//{user:'blue'}

If you have a complete data and you want to merge into a one line,you can do that:

//combine with array and object

var alldata = [
    {user:'blue',sex:'male'},
    {user:'Tony',sex:'male'}
]

//Read
console.log(alldata[0].user) // 'blue'
//etc...

If you have a complex data ,you will be confused about these complex code.So, you can use “break point” tools to read this data.There are lots of tools support “breakpoint”:

google chrome

https://developers.google.com/chrome-developer-tools/docs/scripts-breakpoints

visual studio

http://msdn.microsoft.com/en-us/library/02ckd1z7.aspx

Have Fun!

Comments

RequireJS

在進入RequireJS之前,我想先帶各位了解requireJS的優點,以及為何我們要用requireJS?

1.可以”快速”且”清楚”了解這個function引用了哪些外部呼叫js

首先,假如我們有很多很多的function在同一頁中,且這些function都彼此間互相引用或者是大量引用外部呼叫的js文件時,這對於後續維護非常麻煩(特別是每次修function要去打開一堆相關的外部呼叫文件找),因此requireJS的function架構上,可以讓我們快速了解引用了哪些外部文件,例如:

require(["jquery.alpha","jquery.beta"], function(aaa,bbb) {
    //your code
});

有此式我們可以得知這個function引用了jquery.alpha和jquery.beta兩個外部js檔.

2.可以讓你直覺且客觀的減少定義到全局變量 這部份就是指javascript很基本的全局和區域觀念,不多說.

3.實作:

[html端] head引用:

<script data-main="scripts/main" src="scripts/require-jquery.js"></script>

請注意此main是指main.js,他的路徑必須在 scripts/ 之下,而其他爾後要引用的js檔也盡量都放在 scripts/ 之下,這樣之後若引用出某文件時,可以不用再調整絕對路徑.

body引用:

require(["jquery.alpha","jquery.beta"], function(a,b) {
     b.addit();
     a.alpha(h1);
});

請注意,引用進來的一個外部js必須要給他一個namespase(比如說jquery.alpha的namespace就是a)而若今天想引用外部文件(jquery.alpha)的某一function叫做addit(),則寫a.addit();

[js端] js端可以define也可以reqiure文件,一般而言外部js內常寫define,如下(請注意看我註解的部份):

define(function () {
   function tools(str) {
      console.log(str);
    };

  return {
    alpha: function (str) {
      console.log(str);
      tools(str)  //這時候call的tools function是有作用的
      yoyo(str)   //請注意!這時候call的yoyo是沒有作用的
    }
    yoyo: function (str){
        console.log(str);
    }
  }
});

也就是說,在return以上的function是可以在同一個return內部同一function裡相互間call,但是寫在其他地方的function則無法call,基於這個原因,我的建議是,這部份盡量採取把”執行”和”call”分開架構格式,像是:

define(function () {
   function tools(str) {
      console.log(str);
    };
    //以上寫執行內容

  return {
    tools: function (str) {
      tools(str);
    }
    //以上負責call function
  }
});

首先define到return之間,把它想像成專放負責”執行”的程式,而return以下的就是專門放”call” functions,這樣可以很清楚的分類架構.

補充幾點:

若你在html端上有設定onclick事件(DOM 0級的),像是:

<button id="thisbtn" onclick="hihi();">yoyo</button>

請注意這時候的hihi function一定要在require外面,他才會被導向此function,像是:

function yoyhihi(){
        alert('yoyo');
};
require(["jquery.alpha","jquery.beta"], function(a,b) {
    //不能放這裡面,他會抓不到       
});

這樣的話代碼變成很難控管,所以盡量不要用DOM 0級方法寫,用addEventListner去做監聽event方法較佳!

4.結論

根據上述初步學習requireJS的調用架構,我們可以有一些心得,RequireJS可以讓你快速看出程式來源.方便修改,不過相對的代價就是,在建立function時會比直接寫還要花較多的時間,因此:

1.如果你的專案前端的js function非常的少.很輕量那麼我建議不要用RequireJS,這會大大降低開發速度

2.如果你的專案前端js系統非常複雜,日後維護已經達到找文件都非常耗時時,就用它吧!

至於專案的大小區別,最好的方式就是一開始盡量評估準確!

Comments

onclick event and addEventListner(“click”,fuc(),boolin) The major difference of them is their DOM type.“Onclick event” is DOM 0,and addEventListner(“click”,fuc(),boolin) is DOM 2.

DOM 0 means it controls a single event, and DOM 2 controls a multiple events,

Most of using javascript to build app platforms have forbidden operating DOM 0.Like as winJS,you can see following code:

<Button id="yourid" onclick="yourcodename();" value="hihi">

<script>
    function yourcodename(){
        //your code
    }
</script>

Above call behavior is not used on winJS,we must change DOM 0 type to DOM 2 type:

<Button id="yourid" value="hihi">
<div id="showfn">
</div>
<script>
    var listnerbtn = document.getElementById('yourid');
    listnerbtn.addEventListner('click', ,false)
    function show(){
        var addhtmltagcontent = '';
        addhtmltagcontent += '<div>I am Blue Chen!</div>';
        document.getElementById('showfn').innerHTML= addhtmltagcontent ;
    }
</script>

Above code will be used!However, if you want to call a function which is bringing a variable:

<Button id="yourid" onclick="yourcodename(str)" value="hihi">
                                          ^^^^

You can do that:

<Button id="yourid" value="hihi">
<div id="buttonidvariable" style="display:none">
    document.write(str);
</div>
<script>
    var listnerbtn = document.getElementById('yourid');
    listnerbtn.addEventListner('click', getvalue,false)
    function getvalue(){
        var getstrvalue = document.getElementById('buttonidvariable').innerHTML
        doyouwanttodofn(getstrvalue );
    }
    function doyouwanttodofn(){
        //your code
    }
</script>

Enjoy it!

Comments

About count format.

In America, most of people are used to using “1,000.00” format.However,this format is not written in the database directly.In today’s common MVC framework. They have some similar attempts to prevent this format write in the database.But these attempts often build in back-end.Standing on the user’s view,if you type this format and sent this page. You will see an error page after few second and you will type it again…The phenomenon is not a good UI.So, I suggest we should do validation on the front-end and solve this problem.

View

We have four form to type in.First form is Estimated Price. Second form is Estimated shipping.Third form is Estimated Tax.Fourth form is Total cost which is combine above (three) form’ value.When we type one of three forms ,the “Total cost” form will replace its value.

Validate code(javascript)

1.capture form value

var EstimatedPrice =document.getElementById("EstimatedPrice").value,
    EstimatedShipping =document.getElementById("EstimatedShipping").value,
    EstimatedTax=document.getElementById("EstimatedTax").value; 

hint! the type of this value is Number. We have to change the type to “String”.

var RegEstimatedPrice = EstimatedPrice.toString(),
    RegEstimatedTax= EstimatedTax.toString(),
    RegEstimatedShipping= EstimatedShipping.toString();

After change the type to string, we can use “replace” function to exclude “,”

RegEstimatedPrice = RegEstimatedPrice.replace(',','');
RegEstimatedTax = RegEstimatedTax.replace(',','');
RegEstimatedShipping = RegEstimatedShipping.replace(',','');

We want to check the content of string,don’t allow non-number context.(Using the regular expression)

var score = [RegEstimatedPrice ,RegEstimatedTax,RegEstimatedShipping],
    regexCheck = /^-?\d+\.?\d*?$/;

var checktotal =0;
if (score[0].match(regexCheck)==null || score[1].match(regexCheck)==null ||score[2].match(regexCheck)==null){ 
        checktotal=1;
}

If the string pass above validation, we change its type(string to Number).why? See follow.

RegEstimatedPrice = Number(RegEstimatedPrice);
RegEstimatedTax = Number(RegEstimatedTax);
RegEstimatedShipping = Number(RegEstimatedShipping);

Follow function will be excute when the type of variable is number .

var total = RegEstimatedTax+RegEstimatedShipping+RegEstimatedPrice;

2.Currency

currency = '';

if(document.getElementById("Currency").value == "CAD")
    currency = "$";     
else if(document.getElementById("Currency").value == "EUR")
    currency = "&euro;";        
else if(document.getElementById("Currency").value == "GBP")
    currency = "&pound;";
else if(document.getElementById("Currency").value == "JPY")
    currency = "&yen;";     
else
    currency = "$";

3.total count

if(checktotal==0){
    document.getElementById("id_total_amt").innerHTML= "<b>"+currency+""+total.toFixed(2)+"</b>";
    document.getElementById('needprice_estimate').value = total;
}
else{
    document.getElementById("id_total_amt").innerHTML=currency+"NaN";
    document.getElementById('needprice_estimate').value = currency+"0.00";
}
Comments


最近跟許多正在創業的朋友聊聊一些工作上的事情,常常聽到的都是再抱怨bug太多做不完或者是工程師工作進度緩慢

小弟不才 不敢說能提出有多強心劑的解藥,不過工作至今對於專案管理心得最多。首先,關於program規劃部分,我想這部份就不用多說,每家都有每家的作法,有了良好的program架構,還要有良好的製作執行力.

我記得剛進公司時,測試了許多家的專案管理軟體;個人最推薦JIRA,請務必善用他的各項追蹤方法,不過我覺得他們最好用的地方在於可擴充性高,可以針對公司的專案進度審核程序去做設計,這部份的詳情我以後會慢慢分享,畢竟,打這篇文章想談點非程式上的事情.

目前我身為工程師,最容易發現的狀況就是:

在執行專案製作時,做到一半突然發現比想像中還要困難,而且解決的時間往往超過一開始預估的時間,這時候好笑的地方就來了,大家往往都是去專案管理那邊調時間(不調你的PM會不爽)這樣的結果只會讓進度落後的原因沒有改善,這才是問題的根本.

我認為這問題僅僅有專案管理軟體在控制進度還不夠,事實上要改善的話必須要有個無形的推手去推動工程師,我相信很多公司都有寫程式的績效獎金(或者是福利),而這些獎金通常是建立在工程師有完成專案的前提才有,在這制度作為輔助的情形下,我設計一個方法可以增加工程師的效率和增加團隊合作的機會。

假設一位工程師對於某個專案的完成預計時間是2天,公司要設計一個專案死限,比如說就是4天,假設那個工程師在四天內沒有把專案完成,那麼即使他多花了幾天的時間完成了,這個專案結案人上面他仍然不能寫上自己名字(也就是這份績效不能算他的)

這聽起來很不人道,會這麼做是在於,若遇到大的專案(在預估之前看起來不是,可是執行的時候發現比想像中大)若都是一位工程師自己在蠻幹,其他人則無法隨時進來幫忙,沒有有效利用團隊合作.

如果他想要讓這份績效算他的,當然有其他辦法,請他在第四天的死限之前,要把自己的專案未完成的部份切割出來另開專案,也就是說把大專案分成小專案(他仍可以在自己的專案上簽字結算)讓其他人隨時可以接手幫忙做,這樣的作法不僅可以讓工程師拿到該他拿的,也可以促進團隊間的效率.

以上的作法歡迎各位一起討論!

Comments

BACKBONE.js

Before learning BACKBONE.js, we should know what extended javascript lib will be included in BACKBONE.js project.

1.JQuery 2.UNDERSCORE.js

BACKBONE.js brings the conception of MVC into front-end. The major difference between BACKBONE.js MVC and Back-end MVC is the word of C. Generally,back-end C mean ‘controller’,but BACKBONE.js C mean ‘Collection’.

BACKBONE.JS core:

1.Router

var url  = Backbone.Router.Extend({
    routes:{
      '/isdate': 'getPost',
      '*actions': 'errorPage'
    },

    getPost: function(id){
      alert(id)
    },
    errorPage: function(actions){
      alert('sorry we can not find'+actions+'page');
    }
});

2.Model

When you are recieving a data from front-end and you want to build(or modify) this data to storage(or database).Of course, before you building this data into database, you must give this data some limitations and write in Model.

var Todo = Backbone.Model.extend({

    // Default attributes for the todo item.
    //設定預設值
    defaults: function() {
      return {
        title: "empty todo...",
        order: Todos.nextOrder(),
        done: false
      };
    },

    // Ensure that each todo created has `title`.
    //設定每一筆資料都不能為空,限制title不為空
    initialize: function() {
      if(!this.get("title")) {
        this.set({
          "title": this.defaults().title
        });
      }
    },

    // Toggle the `done` state of this todo item.
    //這邊比較難理解,等等看view就會知道
    toggle: function() {
      this.save({
        done: !this.get("done")
      });
    }
});

3.Collection

Like back-end controller, BACKBONE.js collection do parsing on database.However,BACKBONE.js collection can deal with all model or single model.It very convenient for coder to do more combination on front-end.

var TodoList = Backbone.Collection.extend({
    model: Todo,

    // Save all of the todo items under the `"todos-backbone"` namespace.
    localStorage: new Backbone.LocalStorage("todos-backbone"),


    // Filter down the list of all todo items that are finished.
    //從LocalStorage獲取已經完成的
    done: function() {
        return this.filter(function(todo) {
            return todo.get('done');
        });
    },
    //補充filter函數就是做搜尋符合字串者就提出來
    //http://documentcloud.github.com/underscore/#filter


    //在資料表中獲取未完成數據
    remaining: function() {
        return this.without.apply(this, this.done());
    },
    //without 即是把符合字串者的排除掉
    //http://documentcloud.github.com/underscore/#without
    //apply即傳入函數的意思,這是javascript 原生語法


    //獲得下一組的排序序號
    nextOrder: function() {
        if(!this.length) return 1; 
        return this.last().get('order') + 1;
    },

    // 讓資料依據order來排列
    comparator: function(todo) {
        return todo.get('order');
    }
    //comparator為backbone的内置函数,作用就是collection中數據排序的依據
    //function(model){
    //  return todo.get('JSON中排序的依據');
    //}
    //http://documentcloud.github.com/backbone/#Collection-comparator

});
var Todos = new TodoList;
//這個意思是只創建一個全局的todo  collection

4.View In the demo,its view divid into two parts.

Part1.

This view acting on every todo item

var TodoView = Backbone.View.extend({

    //... is a list tag.
    tagName: "li",
    //作用:  把<script type="text/template">標籤的html碼放在這之中

    // Cache the template function for a single item.
    template: _.template($('#item-template').html()),
    //抓取id 為item-template 的<script type="text/template">裡面的html碼

    // The DOM events specific to an item.
    events: {
        "click .toggle": "toggleDone",
        "dblclick .view": "edit",
        "click a.destroy": "clear",
        "keypress .edit": "updateOnEnter",
        "blur .edit": "close"
        // blur 指的是輸入域失去焦點時就動作
        //請參考jquery http://www.w3school.com.cn/jquery/event_blur.asp
    },
    //above all 可以參考這個BACKBONE api說明
    //http://documentcloud.github.com/backbone/#View-extend


    // The TodoView listens for changes to its model, re-rendering. Since there's
    // a one-to-one correspondence between a **Todo** and a **TodoView** in this
    // app, we set a direct reference on the model for convenience.
    //初始化
    initialize: function() {
        this.model.on('change', this.render, this);
        //http://documentcloud.github.com/backbone/#Model-changed
        this.model.on('destroy', this.remove, this);
        //http://documentcloud.github.com/backbone/#Model-destroy
    },

    // Re-render the titles of the todo item.
    render: function() {
        this.$el.html(this.template(this.model.toJSON()));
        this.$el.toggleClass('done', this.model.get('done'));
        //$el 是召喚jQuery 
        this.input = this.$('.edit');
        return this;
    },

    // Toggle the `"done"` state of the model.
    toggleDone: function() {
        this.model.toggle();
    },
    //*******************************
    // 回到Model的toggle function
    //*******************************


    // Switch this view into `"editing"` mode, displaying the input field.
    edit: function() {
        this.$el.addClass("editing");
        this.input.focus();
        //在textfield裡面出現可以打字狀態
    },

    // Close the `"editing"` mode, saving changes to the todo.
    close: function() {
        var value = this.input.val();
        if(!value) {
            this.clear();
        } else {
            this.model.save({
            title: value
            });
            this.$el.removeClass("editing");
        }
    },

    // If you hit `enter`, we're through editing the item.
    updateOnEnter: function(e) {
        if(e.keyCode == 13) this.close();
    },

    // Remove the item, destroy the model.
    clear: function() {
        this.model.destroy();
    }

  });

part2.

var AppView = Backbone.View.extend({

    // Instead of generating a new element, bind to the existing skeleton of
    // the App already present in the HTML.
    el: $("#todoapp"),
    //把下面事件綁定在todoapp裡面

    // Our template for the line of statistics at the bottom of the app.
    statsTemplate: _.template($('#stats-template').html()),

    // Delegated events for creating new items, and clearing completed ones.
    events: {
        "keypress #new-todo": "createOnEnter",
        "click #clear-completed": "clearCompleted",
        "click #toggle-all": "toggleAllComplete"
    },

    // At initialization we bind to the relevant events on the `Todos`
    // collection, when items are added or changed. Kick things off by
    // loading any preexisting todos that might be saved in *localStorage*.
    initialize: function() {

        this.input = this.$("#new-todo");
        this.allCheckbox = this.$("#toggle-all")[0];

        Todos.on('add', this.addOne, this);
        Todos.on('reset', this.addAll, this);
        Todos.on('all', this.render, this);

        this.footer = this.$('footer');
        this.main = $('#main');

        Todos.fetch();
        //讓你知道目前從local storage取出的最新狀態
    },

    // Re-rendering the App just means refreshing the statistics -- the rest
    // of the app doesn't change.
    render: function() {
        var done = Todos.done().length;
        var remaining = Todos.remaining().length;

        if(Todos.length) {
            this.main.show();
            this.footer.show();
            this.footer.html(this.statsTemplate({
                done: done,  //傳值到html
                remaining: remaining //傳值到html
            }));
        } else {
            this.main.hide();
            this.footer.hide();
            //如果都沒有的話main 和footer div都會消失
        }
        this.allCheckbox.checked = !remaining;
    },

    // Add a single todo item to the list by creating a view for it, and
    // appending its element to the `<ul>`.
    addOne: function(todo) {
        var view = new TodoView({
            model: todo
        });

        //新增一個上面提的TodoView 
        this.$("#todo-list").append(view.render().el);
    },

    // Add all items in the **Todos** collection at once.
    //把Todos中的所有数据渲染到页面,页面加载的时候用到  
    addAll: function() {
        Todos.each(this.addOne);
    },

    // If you hit return in the main input field, create new **Todo** model,
    // persisting it to *localStorage*.
    createOnEnter: function(e) {
        if(e.keyCode != 13) return;
        if(!this.input.val()) return;

        Todos.create({
            title: this.input.val()
        });
        this.input.val('');
    },

    // Clear all done todo items, destroying their models.
    clearCompleted: function() {
        _.invoke(Todos.done(), 'destroy');
        return false;
    },

    toggleAllComplete: function() {
        var done = this.allCheckbox.checked;
        Todos.each(function(todo) {
            todo.save({
                'done': done
            });
        });
    }

});
// Finally, we kick things off by creating the **App**.
var App = new AppView;
//別忘了要創建出這個view

Front-end layout:

  1. Template:
Comments

About Javascript Patterns , you can see this github:

http://shichuan.github.com/javascript-patterns/

Issue1:Function Declarations

在談談這個主題之前,我想要先了解js架構:

function a(){
    alert('123');
}
console.log(a);

這時候如果把console.log(a)這行搬到第一行時,也就是如下:

console.log(a);
function a(){
    alert('123');
}

他仍輸出一樣的結果,原因是js在讀取時會先把所有funciton先讀,然後再讀其他的東西.

不夠清楚?

在舉個例子,如果今天出現如下狀況:

console.log(a.toString());
function a(){
    alert('123');
}
function a(){
    alert('567');
}

則出來的結果是:

function a(){
    alert('456');
}
[Finished in 0.1s]

也就是說 如果遇到兩個都是相同命名的function時,後面的會覆蓋掉前面的同名function.

OK,直接切入這個主體,先看看這個程式碼:

function getData() {
}

這個程式碼本身來說是沒有問題的,但是原因在於js開發者必須要盡量把所有定義的東西用object去定義,這是一個良好的習慣,因為這樣可以幫助開發者去理解和使用他,本主題有討論兩種改善方式:

第一種:

var getData = function () {
            };

第二種:

var getData = function getData() {
        };

第二種的最大好處是在於,可以讓getData function 可以去做內部call迴圈,比如說:

var a = function a(){
    console.log('123'+a);
};
a();

結果為:

123function a(){
    console.log('123'+a);
}

但是,有件奇怪的事情來了,如果我有個代碼如下:

console.log(a.toString());
var a = function a(){
    alert('123');
};

竟然出現錯誤!若改成:

var a = function a(){
    alert('123');
};
console.log(a.toString());

則成功,這樣的例子可以說明,js在讀取時事先把function先讀完,而已經被定義過的object不會先讀取.

Issue2:Conditionals

  • pattern and antipattern of using if else

https://github.com/shichuan/javascript-patterns/blob/master/general-patterns/conditionals.html

先來看第一個程式碼:

if (type === 'foo' || type === 'bar') {
}

=== 其實就是”格式符合”且”內容物完全一樣”則就是true 不符合則就是false

console.log(1 === 1) 結果就是true 因為兩邊都是number

console.log(“1” === 1) 結果就是false 因為前者是string 後者為number

console.log(“1” === “2”) 結果就是false,雖然都是string,但是string 的1與2不同

作者建議的寫法一:

if (/^(foo|bar)$/.test(type)) {
        }

這部份就是regex test,詳情我建議看這網站,很詳細

http://blog.roodo.com/rocksaying/archives/2670695.html

這個作法其實就是直接轉成machine language,好處是在簡短的句子比對效能很快,但是他的時間複雜度為O(N),所以在長句子的比較會不見得比第一種或第二種快,可以參考這個demo:

http://jsbin.com/uzuxi4/4/edit

不過我覺得這個在解讀程式上時真的有點難懂,在寫時還是要考慮一下你的partner看不看的懂

作者建議寫法二:

if (({foo:1, bar:1})[type]) {
        }

其實這個就是最簡單的hash table search,他的時間複雜度平均為O(1),在分析超長子句時在理論來說較上述來的好,以上相關的討論可以參考這個,非常的詳細:

http://stackoverflow.com/questions/3945092/why-the-third-option-is-better-than-regex

接下來在line36~97部分在講關於BST(Binary search tree),作者範例很清楚就不多說,line103~114部分,則是建議使用array的形式取代掉多種if else的假設,我認為這個方式對於工程師解讀上是很有幫助的。

另外除了array方式,我也推薦另外一種作法:

var hi = {
    a:function () {
        console.log("123")
    },
    b:function(){
        console.log("456")
    }
}
hi.a()

印出的結果為:

123

這樣的形式也可以幫助工程師能夠理解,而line120~138部分則是盡量使用logical operators可以幫助我們解讀code.

我在參加js討論會,講者tonyQ提過這個有趣的example:

function test(option){
    option = option || {};
    console.log(option.start)
}
test(null);

這個印出來的結果是:

undefined

原因是null不屬於obj,裡面也沒有start參數,當然undefined,若改成:

function test(option){
    //option = option || {};
    option.test = option.test || {};
    console.log(option.test.start)
}
test({test:{start:1}});

則印出的結果是1,這個方法可以幫助我們快速去理解obj內部的解析,值得學習!另外有個議題還蠻有趣的,請看:

console.log(true || false);
console.log(true && false);

以上的結果竟是….

true
false

不難理解,請自行想想 …

Issue3:Access to the Global Object

  • access the global object without hard-coding the identifier window

https://github.com/shichuan/javascript-patterns/blob/master/general-patterns/access-to-global-object.html

這邊是指如何去高效率的調用global object,並且讓他們可以通過ES3, ES5 and ES5-strict.

var global = (function () {
    return this || (1, eval)('this');
}());

效能展示可以看這個:

http://jsperf.com/globalx

我們來看這個例子:

var x = 'outer';
(function() {
  var x = 'inner';
  eval('console.log("direct call: " + x)'); 
  (1,eval)('console.log("indirect call: " + x)'); 
})();

輸出的結果為:

direct call: inner
indirect call: outer

我曾經想過如果把(1,eval)的1改成null or 0 or undefined 結果通通都是這個,至於為何以下的討論串就有行這樣說:

http://stackoverflow.com/questions/9107240/1-evalthis-vs-evalthis-in-javascript

“The expression (1, eval) is just a fancy way to force the eval to be indirect and return the global object.”

Issue4:Single var Pattern

  • use one var statement and declare multiple variables

https://github.com/shichuan/javascript-patterns/blob/master/general-patterns/single-var-pattern.html

一般而言,我們通常會這樣定義變數:

function func() {
    var a = 1,
    var b = 2,

    // function body...
}

這是沒有問題的,但是對於多寫一個var實在沒有額外好處,因此建議這樣寫:

function func() {
    var a = 1,
        b = 2,

    // function body...
}

這樣的好處可以幫助自己去強迫把宣告變數的地方放在同一個,可以幫助理解,也可以幫助自己減少忘記宣告變數的動作, 那如果今天宣告的變數裡面有長字串(或者是包html的話),因為包這些字串每次讀取會增加很多空間,因此也建議類似這種東西要先去做宣告變數,如下:

function updateElement() {
    var el = document.getElementById("result"),
    style = el.style;
    // do something with el and style...
}

Issue 5:Hoisting

– var statements anywhere in a function act as if the variables were declared at the top of the function

https://github.com/shichuan/javascript-patterns/blob/master/general-patterns/hoisting.html

Issue 6:for loops

– optimized for loops

https://github.com/shichuan/javascript-patterns/blob/master/general-patterns/hoisting.html

這是一個很基本的javascript 變數宣告的觀念,首先,看如下代碼:

myname = "global"; // global variable
function func() {
    console.log(myname); // "undefined"
    var myname = "local";
    console.log(myname); // "local"
}
func();

第三行會出現undefined,這是因為在function外宣告的global variable並不會被導進function內變成local variable,因此第三行的console.log因為在他之前沒有宣告local variable,已故呈現undefined

myname = "global"; // global variable
function func() {
    var myname; // same as -> var myname = undefined;
    console.log(myname); // "undefined"
    myname = "local";
    console.log(myname); // "local"
}
func();

這個情況是,他先宣告了某個local variable,但是因為他並沒有定義這個變數,以至於第四行的console.log輸出為undefined.

Issue 7:for-in loops

  • optimized for-in loops

Issue 8:(Not) Augmenting Built-in Prototypes

  • only augment built-in prototypes when certain conditions are met

Issue 9:switch Pattern

– improve the readability and robustness of your switch statements

https://github.com/shichuan/javascript-patterns/blob/master/general-patterns/switch-pattern.html

盡量多使用switch 方式,也請謹守下面switch的格式,break;和default:千萬別忘記打

var inspect_me = 0,
        result = '';
switch (inspect_me) {
    case 0:
        result = "zero";
        break;
    case 1:
        result = "one";
        break;
    default:
        result = "unknown";
}

Issue 10:Implied Typecasting

– avoid implied typecasting

https://github.com/shichuan/javascript-patterns/blob/master/general-patterns/avoiding-implied-typecasting.html

其實這邊在討論javascript中,要注意隱式類型的轉換,比如說0在==比較中代表的是false,而1代表的是true,他的範例如下:

var zero = 0;
if (zero == false) {
    console.log('123');
}

輸出的結果為:123,另外我試個有趣的實驗,代碼:

var zero =[] ;
if (zero == false){
    console.log('23');
}
//Output:23

以上當我設定var zero ={} 或者 ‘’ 或者 []時全部都是一樣的結果,那麼若我試試:

var zero =['123'] ;
if (zero == false){
    console.log('23');
}
//竟然沒有console.log的值!在試試true
if (zero == true){
    console.log('23');
}
//一樣沒有console.log的值!

同樣試過string.object也是一樣,這個小實驗蠻有趣的!

Issue 11:Avoiding eval()

  • avoid using eval()

https://github.com/shichuan/javascript-patterns/blob/master/general-patterns/avoiding-eval.html

避免使用eval();

Issue 12:Number Conversions with parseInt()

  • use the second radix parameter

Issue 13:Minimizing Globals

  • create and access a global variable in a browser environment

https://github.com/shichuan/javascript-patterns/blob/master/general-patterns/minimizing-globals.html

盡量減少宣告global variable,否則很容易經過多種方法就讓他被讀出來

myglobal = "hello"; // antipattern
console.log(myglobal); // "hello"
console.log(window.myglobal); // "hello"
console.log(window["myglobal"]); // "hello"
console.log(this.myglobal); // "hello"

Issue 14:The Problem with Globals

– various problems with globals

https://github.com/shichuan/javascript-patterns/blob/master/general-patterns/globals.html

這是補充issue13

function sum(x, y) {
    // implied global
    result = x + y;
    return result;
}
sum(1,2);
console.log(result);
Copyright © 2013 Mr.Blue Design credit: Blue Chen