jQuery擴充寫法(jQuery extend)

jquery的擴充方式有兩種,一種是靜態的擴充,另一個則是prototype擴充,靜態擴充只是將function、object….等,添加在jquery底下,與沒添加前功能相同,但是prototype則不同,prototype擴充可以將你所抓取的element做處理,以下是一個很典型的做法。

example:
(function($){
    //prototype extend
    $.fn.extend({
        drawRed:function(){
            //
            return this.each(function(){

                //$(this).css("background-color","red");
                this.style.backgroundColor = "red";
            });

        }
    });
    //static extend
    $.extend({
        draw:function(){
            console.log("draw");
        }
    });
})(jQuery);
//
$("div").drawRed();
$.draw();

其中each是一個非常重要的東西,因為使用jquery抓取的element會create一個Array,而這個Array與一般的Array的prototype是分開的,只是擁有相同的prototype attribute,當呼叫到each時,他會將array裡所有存放的資料,都執行過一邊,each傳入的function中,使用this是指向array裡執行到的element,所以若是沒有使用eachjquery所抓取的數個elements,呼叫到drawRed只會執行一次,而且this指向的是Array本身。

jqueryextend傳入參數只有一個物件時,則是擴充jquery本身,若是對jquery的實作方式有興趣,請參考jQuery.fn.initjQuery.fn.extend這兩個function

Android Linux開發環境配置(non-ide)

在開始配置環境之前,你必須先安裝好java,接著下載android sdk和ant

接在配置.bashrc這個檔案(家目錄):
export PATH=${PATH}:<sdk>/tools:<sdk>/platform-tools

 

如果沒配置,將無法使用模擬器,ant可以直接使用或參照以上配置方法,配置好在terminal上打

source .bashrc

接著在terminal打上android將會出現以下視窗,將available packages裡面需要用到的都安裝上去,因為一開始

只提供2.3.3和3.0的模擬器。

安裝好之後接著配置專案,先查看能使用的模擬器版本及id:
android list targets

 

接著create project:
android create project \
--target <target_ID> \
--name <your_project_name> \
--path path/to/your/project \
--activity <your_activity_name> \
--package <your_package_namespace>
example:
android create project \
--target 1 \
--name MyAndroidApp \
--path ./MyAndroidAppProject \
--activity MyAndroidAppActivity \
--package com.example.myandroid

 

專案建立好後,只要在專案的根目錄下,對terminal執行以下指令,就可以產生apk:
ant debug
    or
ant release

查看目前連接的裝置:

adb devices 
 

64位元系統是無法使用adb,需要安裝:

sudo apt-get install ia32-libs
 
###### 接著最後一步就是開啟你的模擬器,在terminal下打指令:
adb -s emulator-5554 install _path/to/your/app_.apk

最後你就會在模擬器上面看到,剛剛安裝到模擬器上面的專案名稱了。

Javascript Object Oriented Concepts

javascript中並沒有class這個關鍵字,而是以function的方式,去配置一個物件,所以function可以直接使用,也可拿來配置物件。接著以下都直接以配置物件的function,稱為class,那麼在class之中,宣告var來當一個private的變數,若是沒宣告則會是一個全域變數,在function裡面的code,當開使去new的時候,裡面的code都會被執行一次,其中this為指向物件本身,換句話說就是一個public的屬性,this與prototype的差異是,this是每個物件自己擁有的,而prototype則是所有class共用的

以下是一個範例:
/**
* @class
* @constructor
*/
function Car(){
    /**
    * @private
    */
    var _name;
    var _speed = 40;

    /**
    * @param {String} name
    */
    this.setName = function(name){
        _name = name;
    }

    /**
    * @param String
    */
    this.getName = function(){
        return _name;
    }

    /**
    * @type int
    */
    this.getSpeed = function(){
        return _speed;
    }

    /**
    *
    */
    this.run = function(){
        console.log("moving:"+_speed+"km/hr");
    }
}

/**
*
*/
Car.prototype.show = function(){
    console.log("name:"+this.getName());
    console.log("speed:"+this.getSpeed()+"km/hr");
}

/**
* @static
*/
Car.powerRun = function(){
    console.log("moving:"+this.getSpeed()+"→100km/hr");
}

var car = new Car();
    car.setName("cloud");
    car.run();
    car.show();
    //moving:40→100km/hr
    Car.powerRun.call(car); 

以上比較值得注意的是,call這個function,主要是把object丟到指定的function上面跑,簡單來說就是把this直接替換成object的名稱,例如:

this.getSpeed();
car.getSpeed();

以上這兩行在範例中執行的,與Car.powerRun.call(car)是畫上等號的,再來call與apply是同樣的功能,差別在於傳值call必須寫成:

functionName.call(object,param1,param2....);

apply的傳遞參數則是一個array

functionName.apply(object,array);

Javascript Closure

以下是一個簡單的closure example:
function doSomething(){
    var x = 100;
    function add(y){
        x = x + y;
        return x;
    }

    return add;
}

var add1 = doSomething();
var add2 = doSomething();
    //110
    console.log(add1(10));
    //120
    console.log(add1(10));
    //115
    console.log(add2(15));
    //130
    console.log(add2(15));

主要是呼叫doSomething這個function時,將會傳回一個內部function,同時這個functionx會參照上層的x變數,此時會將x綁在add function這個scopex就會相當於一個private static變數,當被exportfunction呼叫一次,x變數也會跟著累加,並不會因為呼叫完exportfunction而釋放。另外一個很重要的是,當doSomething被呼叫時,不管他被呼叫次數幾次,每個被export function出來的scope都是不一樣的,換句話說,各自綁定的x變數都是不共用的,而是都擁有各自的記憶體區塊。

jQuery extend

jquery提供的extend,主要是將其他object的屬性,copy到target這個object

jQuery.extend( target, [ object1 ], [ objectN ] );

extend return時,與target是同一個object

相當於以下的code:
for(var name in object)
target[ name ] = object[name];

但是這樣會有一個問題,當object裡的屬性有object或是array時,他並不會配置新的記憶體,而時指向同個記憶體。

</span>
例如:
var object = {key:3,data:{name:"sparrow"}};
var target = {};
    $.extend(target,object);
    //result:sparrow
    console.log(object.data.name);
    target.data["name"] = "peter";
    //result:peter
    console.log(target.data.name);
    console.log(object.data.name);
    

所以這時jquery有提供一個deep參數:

jQuery.extend( [ deep ], target, object1, [ objectN ] )

deep會true時,他會用遞迴的方式,將arrayobject配置一個新的空間,然後將值複製過去。

jquery主要copy source code如下:

// Recurse if we're merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];

} else {
     clone = src &amp;&amp; jQuery.isPlainObject(src) ? src : {};
}    

 // Never move original objects, clone them
     target[ name ] = jQuery.extend( deep, clone, copy );

// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;



泛型(Generic)

在沒使用到泛型之前,有兩個類別擁有相同的功能:
public class IntegerObj {
    private Integer integerObj;
    /**
    * @param {Integer} integerObj
    */
    public void set(Integer integerObj) {
        this.integerObj = integerObj;
    }
    /**
    * @type Integer
    */
    public Integer get() {
        return integerObj;
    }
}
public class StringObj {
    private Integer stringObj;
    /**
    * @param {String} stringObj
    */
    public void set(String stringObj) {
        this.stringObj = stringObj;
    }
    /**
    * @type String
    */
    public String get() {
        return stringObj;
    }
}

以上這兩個class只有member型態上有差異,邏輯上是一模一樣,等於必須對兩種不同型態去各自撰寫一個類別,但同樣的,這些物件的最上層都是繼承Object,可將member成員替換成Object,最後再經由轉型就可以了。但是由於轉型也有轉錯的可能,那麼是不是能在宣告變數時,就先將型態定義好,並且使用同一個class,那麼這時就要使用到泛型了。

以下是個簡單的例子(java):
class CollectionExample<T>{
     private T[] _objects;
     private int _index;
     /**
     *
     */
     CollectionExample(int total){
        _objects =(T[]) new Object[total];
        _index = 0;
     }
     /**
     * @param {T} obj
     */
     public boolean add(T obj){
        boolean result = false;
        if(_index < _objects.length){
            _objects[_index] = obj;
            _index++;
            result = true;
        }
            return result;
     }
     /**
     * @param {int} index
     * @type T
     */
     public T get(int index){
          return _objects[index];
     }
     /**
     * @type int
     */
     public int getLength(){
          return _objects.length;
     }
     /**
     *
     */
     public static void main(String[] args){
      CollectionExample<Integer> collection = new CollectionExample<Integer>(10);
        //
            for(int i=1;i<=collection.getLength();i++)
                collection.add(i);
            for(int i=0;i<collection.getLength();i++)
                System.out.println(collection.get(i));
     }
}

<T>主要是來定義泛型用,T為變數名稱,換句話說他可以是其它文字,最主要用處是拿來替換型態用,例如當你宣告:
//
CollectionExample<Integer> collection = new CollectionExample<Integer>(5);
上面class的變數T,將會取代成Integer。CollectionExample類別提供了add、get和getLength三個method,主要功能是將object儲存起來以及取出。
 
###### 以下是C++的範例: CollectionExample.h
template <class CType>
class CollectionExample{
//
public:
    CollectionExample(int);
    ~CollectionExample();
    void add(CType);
    int getLength();
    CType get(int);
private:
    CType *_objs;
    int _index;
    int _length;
};
/**
* @param {int} total
*/
template <class CType>
CollectionExample<CType>::CollectionExample(int total){
    _objs = new CType[total];
    _length = total;
    _index = 0;
}
/**
*
*/
template <class CType>
CollectionExample<CType>::~CollectionExample() {
    delete [] _objs;
}
/**
* @param {CType} obj 
*/
template <class CType>
void CollectionExample<CType>::add(CType obj){
    if(_index<_length){
        _objs[_index] = obj;
        _index++;
    }
}
/***
* @param {int} index
* @type CType
*/
template <class CType>
CType CollectionExample<CType>::get(int index){
    if(index<_length)
        return _objs[index];
}
/**
* @type int
*/
template <class CType>
int CollectionExample<CType>::getLength(){
    return _length;
}

main.cpp

#include <iostream> 
#include "CollectionExample.h"
using namespace std; 

int main(){
    CollectionExample<int> collection(10);

       for(int i=0;i<collection.getLength();i++)
           collection.add(i);
       for(int i=0;i<collection.getLength();i++)
           cout<<collection.get(i)<<endl;
    return 0;
} 

結果與java相同。

Closure Template

closure template是由google release的工具之一,最主要是為了讓html與程式邏輯分開,方

便程式的維護性,讓程式只要像call method的方式,將直塞入即可得到一個完整的html

以下是一個簡單的範例:
soy:

{namespace examples.simple}

/**

  • @param color
  • @param name
    */
    {template .car}

This car is {$color} color.

Its name is {$name}.

{/template}

soy檔案的定義方式,主要是定義在註解裡,再由template裡的{$color},將值塞入。

soy定義了兩個參數,分別為namecolor,作為為塞入樣板的參數。

(即使無參數傳入時,也必須保留註解。)

 
接著將soy檔轉成js,執行以下指令:
java -jar SoyToJsSrcCompiler.jar –outputPathFormat firstExample.js firstExample.soy

 
javascript的使用方式:

document.write(examples.simple.car({name:"cool car",color:"yellow"}));

要使用template之前必須先載入soyutils.js,接著載入剛剛由soy產生好的firstExample.js,

最後只要對應好template的命名,由js呼叫就可以產生html了。

 
java的使用方式:

import com.google.template.soy.SoyFileSet;
import com.google.template.soy.data.SoyMapData;
import com.google.template.soy.tofu.SoyTofu;
import java.io.File;

public class FirstExample {

public static void main (String[] args) {

SoyFileSet sfs = (new SoyFileSet.Builder()).add(new File(&quot;firstExample.soy&quot;)).build();

SoyTofu tofu = sfs.compileToJavaObj();

System.out.println(tofu.render(&quot;examples.simple.car&quot;, new SoyMapData(&quot;name&quot;,&quot;cool car&quot;,&quot;color&quot;,&quot;yellow&quot;), null));

}

}

以上做法主要是讀取soy檔(與js做法不同),接著將檔案轉成javaobject,最後塞入參數即可產生html

closure template還有很多command可以使用,例如ifforswitch等…,詳情請參考此link

在IE中的userData Behavior

IE中可利用cookieflashstoragebehavior…等將資料儲存在client端。

但在IE6並不支援storage屬性,要儲存較大量的資料只能透過其他方法,若

不想掛載flash…等的情況下,可以透過behavior將資料存在brower

css:
.storeuserData {
    behavior: url(#default#userData);
}

以上是behavior在css的定義方式。 當然你也可透過以下方式以動態方式載入。

object.style.behavior = "url('#default#userData')" 
object.addBehavior("#default#userData")
javascript:
function save(){
   var persist=persistForm.persistInput;
   persist.setAttribute("persist",persist.value);
   persist.save("oXMLBranch");
}
function load(){
   var persist=persistForm.persistInput;
   persist.load("oXMLBranch");
   persist.value=persist.getAttribute("persist");
}

class被定義成behavior:url(#default#userData)時,setAttributegetAttribute

將會對暫存資料操作,不是domattribute,最後只要再設定完attribute後,執行save資料

就會儲存起來了,load則是選擇要讀取,讀完接著就可以取得attribute

以下html對應上方的js code:
<form id="persistForm"><input class="storeuserData" id="persistInput" type="text" />
    <input onclick="load()" type="button" value="Load" />
    <input onclick="save()" type="button" value="Save" />
</form>
換頁保留欄位的方法(換頁時,按上一頁,將會保留欄位資料):
<meta content="history" name="save" />
<style>                                                                                                                                               
.saveHistory {behavior:url(#default#savehistory);}
</style>

這些方法只能運作在IE上。

Factory pattern for javascript

在提到factory pattern之前,讓我們先來理解一些基本的概念。

當javascript的private變數必須以var定義,反之沒加var則為global變數。而由function建立的object,裡面的this將會指向物件本身,同時也是public的屬性。一般prototype與this定義的function有一個很大差異,由this定義的function,每個function都是獨立的,簡單來說都佔由實體空間,而由prototype定義的,則是多個物件共用同一個資源。

以下是一個簡單的factory pattern
/**
* @name Car
* @class
* @constructor
* @see carFactory
*/

/** @namespace */
var carFactory = (function(){
    var _count = 0;

    /**
    * @lends Car
    * @inner
    */
    function Car(){
        //private
        var _color = "black";
        var _doors = "4";

        /**
        * @public
        * @param {String} color
        */
        this.setColor = function(color){
            _color = color;
        }

        /**
        * @type {String}
        */
        this.getColor = function(){
            return _color;
        }

        /**
        * @type int
        */
        this.getDoorTotal = function(){
            return _doors;
        }

    }

    /**
    * Show this car info.
    */
    Car.prototype.show = function(){

        console.log("color:"+this.getColor());
        console.log("door total:"+this.getDoorTotal());
    }

    /**
    * @lends carFactory
    */
    return {
        /**
        * @type Car
        * @memberOf carFactory
        */
        create:function(){
            _count++;
            return new Car();
        },
        /** @memberOf carFactory */
        getCount:function(){
            return _count;
        }
    };
})();

首先我們定義了一個carFactory物件,裡面有個內部class名稱為Car,分別定義了setColor、getColor、getDoorTotal、show四個function。接著再由carFactory的create,將car object export出去,而getCount則是計算了建立car object的total。

最後是實際使用的code:
var car1 = carFactory.create();
    car1.setColor("blue");
    car1.show();
var car2 = carFactory.create();
    car2.setColor("gray");
    car2.show();
var car3 = carFactory.create();
    car3.show();

    console.log("car total:"+carFactory.getCount());

result:

javascript的scope

javascript和其他語言的scope有一個很大的差異。

javascript只有function裡,才能產生scope。

一般的語言特性以java為例:

for(int i =0;i<5;i++){
       //可以看到i變數
       System.out.println(i);
}

//看不到i變數

if(true){
      int i =53;
      //可以看到i變數
      System.out.println(i);
}

//看不到i變數

以上這段程式碼,變數i只存在於迴圈內,當離開回圈則看不到。   javascript example: for loop

for(var i = 0;i<5;i++){

}
//i值會等於5
console.log(i);

if  loop

if(true){
var b = 10;
}
//b會等於10
console.log(b);

在function將產生一個scope:

(function(){
    var a = 5;
     //a = 5;
     console.log(a);
})();

//將會產生錯誤,找不到a變數
console.log(a);

以下是javascript scope參照方式:

var i=3;
(function(){
     //i會等於3
     console.log(i);
})();

當i變數無法在這個scope找到此變數時,將會往上一層去尋找。

var i=3;
(function(){
     //undefined
     console.log(i);
     var i=5;
})();

在同一個scope已經定義了一個變數時,即使定義在印出之後,仍然會找相同scope的變數。