2015年11月2日 星期一

Javascript的變量聲明提昇

最近學到了JavaScript的作用域與變量聲明提昇的觀念,
深感與C語言及Java有很大的不同,
如果不是一開始就學JavaScript的人非常可能會把以前的觀念代入而遭遇匪夷所思的錯誤,
所以特地在此做個紀錄。

在JavaScript中,有兩個跟C語言及Java非常不同的特性,

  1. 變量的作用域不為塊級作用域(block-level scope),而且支持函數作用域(function-level scope)。
  2. 在作用域裡會有變量聲明提昇的現象。
下面做個說明:

1.變量的作用域不為塊級作用域(block-level scope),而且支持函數作用域(function-level scope)

在C語言及Java中,只要在括弧( "()" 及 "{}") 中宣告的變數都屬於區域中的區域變數,例如以下程式碼:

int x = 1;

if (true) {

     int x = 2;

     println(x);  //2

}

println(x);       //1

很顯然地應該輸出為 2和1 ,因為大括弧{}中的int x=2;跟外面的int x=1 無關,兩次println(x)的x是不一樣的。
但是在JavaScript中,變數不是使用塊級作用域的,而是函數作用域的,例如以下的程式碼:

var x = 1;

if (true) {

    var x = 2;

    alert(x);    //2

}

alert(x);        //2

結果會是兩次的alert(x)都會顯示2,這是因為在if的大括弧{}裡的var x=2; 的x就是 外層的var x=1;,兩個x並沒有被當成是不同的x,所以內外層的alert(x)的x都是一樣的x。

因為JavaScript支持函數作用域,所以如果用函數來圍往同名變數的宣告的話,就可以區分內外的同名變數,如以下程式碼:

var x = 1;

function myFun(){

     var x = 2;

     alert(x);               //2

}

myFun();

alert(x);                   / /1


就會先顯示2再顯示1,因為此時myFun()裡的x與外層的x是不同的x變數。


2.在作用域裡會有變量聲明提昇的現象

另外一個JavaScript中獨特的特性是變量聲明提昇,以下兩種宣告情形會變提昇至作用域的頂端,即先被執行:
         
            一、以var宣告變數的動作。
            二、函數的無等號宣告 (如: function myFun(){} 這種,其實就等於 var myFun = function(){})

例如以下程式碼:

function sum() {   
    try{
       alert(sum.arguments.length);   //sum為undefined ,出錯
       var sum = 0;
       alert(sum);
    }catch(error){
       alert(error);
    }
}
sum(1,2); 

會補捉到TypeError: Cannot read property 'arguments' of undefined的錯誤,這是因為變量聲明提昇的作用,在提昇之後,其實真正的程式碼執行狀況長得就像下面這樣:

function sum() {   
    try{
       var sum;                                     //變數的宣告被提至作用域頂端
       alert(sum.arguments.length);     //sum為undefined ,出錯
       sum = 0;
       alert(sum);
    }catch(error){
       alert(error);
    }
}
sum(1,2); 

此時就很容易看出Error發生的原因,因為在sum()中,先宣告了一個sum屬性但未賦予其值,是undefined的,所以在alert(sum.arguments.length)中的sum是undefined的,當然就沒有arguments等屬性了。

再看一個例子,現在使用function的非等號式宣告:

var x = 1;
function myFun(){<
     x = 2;
     return;
     function x(){};
}
myFun();
alert(x);

答案是輸出1,因為被變數聲明提昇後的程式碼長得像這樣:

var x = 1;
function myFun(){
     var x;
     x = 2;
     return;
     x = function){};
}
myFun();
alert(x);

所以myFun()跟本沒有影響到外層的var x = 1的x而輸出原來的1了。

參考資料:

  1. JavaScript Scoping and Hoisting
  2. 翻譯 - JavaScript中的作用域與變量聲明提升

2015年10月24日 星期六

自製jQuery的PlugIn(twinkle演示範例)

JQuery提供外掛(Plug-In)能力,可以讓使用者設計自己所需的功能,跟自己做一個客製化類別(Class)不一樣,外掛就相當於是jQuery物件能夠使用的功能,能夠用selector的方式直接得到jQuery物件然然後使用,就像顯示物件是 $("selector").show();一樣,我們也可以自己寫一個外掛來用,例如$("selector").myPlugInFun();

以下為在寫JQuery的Plug-In時,常使用的其中一種寫法(只是舉例,寫法因人而異):

(function($){

    //這裡可設制function或變數

    $.fn.extend({

           //這裡可設制function或變數

           myPlugInFun1 : function(options){

                                         //這裡可設制function或變數,跟Java或C很不一樣的是,

                                         //JavaScript的function也算一種Object,所以可以在function裡設

                                         //function屬性

                                         var defaultOptions1 = {

                                               option1 : "option1" ,

                                               option2 : "option2"

                                         };

                                          return this.each(function(){

                                              $.extend(defaultOptions,options);

                                              //..........Do something

                                          });

                                      } ,

           myPlugInFun2 : function(options){

                                            ...以此類推

                                      }

    });

})(jQuery);


下面我們來寫一個簡單的jQuery Plug-In,叫做twinkle(),其作用是讓選取的jQuery物件可以依自訂(當然也可以預設)的次數及間隔時間閃爍,且也可以設定執行完後的callback function及擁有串接的特性,相關的說明註解都在程式碼中,直接看程式碼:

2015年10月13日 星期二

在xml中儲存tag類型符號,使用

在XML中,任何Tag型式的東西都會被當成正規的XML結構節點,例如

<message><someText>myText</someText></message>

但是如果我們想要儲存在XML中的內容有Tag型式的東西,但又不希望被XML當成節點呢?例如我們想把一個網頁的html儲起來,內容像這樣:

<html>

<head></head>

<body><p>someText</p></body>

</html>


如果把上述的html直接寫進XML中就會出問題,這時我們需要用<![CDATA[...]]>標籤來告訴XML其包住的內容不要用XML的方式解析,像如下這樣:

<message>

      <someHtml>

      <![CDATA[<html><head></head><body><p>someText</p></body></html>]]>

      </someHtml>

</message>

下面是一些注意事項:
CDATA 區段的內容必須在 XML 內容所允許的字元範圍內;不能用這種方式逸出控制字元和相容性字元。 此外,CDATA 區段內不能出現序列 ]]>,因為這個序列會發出區段結束訊號。 這意味 CDATA 區段不可以是巢狀。 這個序列也出現在部分指令碼中。 在指令碼內,通常可使用 ] ]> 替代 ]]>。
             from CDATA 區段 [XML 標準] 

參考資料:

  1. CDATA 區段 [XML 標準] 
  2. Ian 懶惰蟲筆記: CDATA 區段 - XML 標準

2015年10月11日 星期日

CSS3的動畫

這裡紀錄一下利用CSS做簡單動畫的方法:
在CSS裡,可以利用animation-name屬性來指定動畫,並且利用@keyframes檢設定動畫

下面是一個簡單的例子,設定動畫為一秒,使用myAnim的自訂影格,影格內容分三個時間點(0%,50%和100%),動畫為左移動:
html:
<div class="animClass">我在移動</div>


css:
.animClass {

      animation-name: myAnim;   

      animation-duration: 1s;     

    

    }



@keyframes myAnim {

  0% {

      padding-left: 100%;

  }

  50% {

      padding-left: 0%;

  }

  100% {

      padding-left: 100%;

  }

}


線上實例演示:
http://jsfiddle.net/rd0zsy78/1/

CSS的動畫使用方法就跟平常使用CSS定義的一樣,用CSS選擇器來為選擇的元素定義動畫,包括了動畫名稱(animation-name)、持續時間(animation-duration)、重覆幾次(animation-iteration-count)等屬性可以設定。

接著就要自已定義對應影片名的關鍵影格,設定不同時間點(用百分比算)的CSS變化。

下面的參考資料就有詳細的各種參數資料可查詢。

參考資料

  1. CSS 動畫
  2. 使用 CSS Animation 製作網頁上的動畫(隻要 CSS3,不用 JavaScript!)
  3. CSS參考手冊

2015年10月2日 星期五

使用SvnAnt來在Ant中以程式化方式執行SVN行為

今天來紀錄一下如何在Ant中使用SvnAnt來執行SVN的行為動作。

首先,要先去下載SvnAnt,選擇合適的版本下載解壓縮後,把lib資料夾裡的jar檔全部丟掉Ant的lib中,把path還境變數設好,就可以開始撰寫操作SVN的Ant程式碼了。

以下就展示一個簡單的範例:
作用為向SVN export資料出來。

build.xml:
<?xml version="1.0" ?>
<project name="test" default="svnTestTask">
        <!-- 參數設置 -->
 <property name="dir" value="D:\testSvnDir" />
 <property name="svn_User" value="USER_NAME" />
 <property name="svn_Password" value="PASSWORD" />
        <property name="svn_url" value="SVN_URL" />

        <!-- 主要的Target -->
 <target name="svnTestTask">
  <delete dir="${dir}" />            
  
  <taskdef name="svn" classname="org.tigris.subversion.svnant.SvnTask" />
  <svn javahl="true" username="${svn_User}" password="${svn_Password}" >
   <export srcUrl="${svn_url}" destPath="${dir}" />
                </svn>
 </target>
</project>


 把build.xml放在要執行的資料夾,並且用DOS指令到資料夾中用ant指令即可執行,當然你也可以寫一個bat檔來執行:

test_svnant.bat:
cd d:
ant

在官網中,有蠻詳細的指令使用說明可以參考:
http://subclipse.tigris.org/svnant/svntask.html#update

參考資料:

  1. 【Tomcat】Ant與build.xml
  2. 用ant实现SVN代码更新,部署
  3. 官方說明
  4. ant 自定义 task

2015年9月24日 星期四

特定位置浮動Element效果(jQuery)

今天要介紹的使用jQuery來製作"特定位置浮動Element效果"。

首先先看一下影片演示:

其中的紅色框框,我們希望在卷軸往下拉、越過紅色框框時紅色框框能夠停留在上方,而卷軸往上拉回去時,紅色框框能夠回到原位。

這樣的效果常被用在網站的選單上面,讓使用者瀏覽網站時,能夠一直都看得到選單。

程式實現的邏輯是這樣的:
  1. 先取得紅色框框的位置。
  2. 當卷軸滑動時,計算卷軸是否滑超過等於卷軸的位置。
  3. 如果超過的話,固定紅色框框的位置,將其z-index提高,為了避免下面的元素補上來,先製作一個假的、但透明看不見的紅色框框再固定原紅色框框;否則,不固定紅色框框的位置。將假的紅色框框刪掉。

下面上程式碼:
1. html部份:
Other Content. Other Content. Other Content. Other Content. Other Content.</br>
Other Content. Other Content. Other Content. Other Content. Other Content.</br>
Other Content. Other Content. Other Content. Other Content. Other Content.</br>
Other Content. Other Content. Other Content. Other Content. Other Content.</br>
Other Content. Other Content. Other Content. Other Content. Other Content.</br>
<div class="bar">
This is the div class, top_tab_bar_bg.
</div>
Other Content. Other Content. Other Content. Other Content. Other Content.</br>
Other Content. Other Content. Other Content. Other Content. Other Content.</br>
Other Content. Other Content. Other Content. Other Content. Other Content.</br>
Other Content. Other Content. Other Content. Other Content. Other Content.</br>
Other Content. Other Content. Other Content. Other Content. Other Content.</br>
2. CSS部份:
body{
    height : 1000px;
}

.bar{
    width : 300px;
    border-style:solid;
    background-color: red;
}

3.javascript部份:
 //offset().top 是相對於文檔的偏移量,不會因為滾動卷軸而有變化。
    //CSS裡的top屬性在position為fixed時,是對應到相對於所處螢幕的偏移量
    //,會因滾動卷軸而有變化。
    var barOffsetTop = $(".bar:not(.tempBar)").offset().top;
 var barMarginTop = parseInt($(".bar:not(.tempBar)").css("margin-top"));
 
   $(window).scroll(function() {
     var scrollTopAmount= $(this).scrollTop();     
        //因為bar的position被設成fixed時會使下面的元素跑上來,所以做一個透明的tempBar來填充原來
        //bar的位置
     if (scrollTopAmount >= barOffsetTop){
            //如果卷軸拉超過bar的原始offset.top(),將bar固定住
            //如果沒有tempBar,做一個tempBar
      if ($(".tempBar").length == 0){
       $(".bar").clone().addClass('tempBar').insertAfter(".bar").css({"opacity":"0","z-index":"auto"});
      }      
      $(".bar:not(.tempBar)").css({ "position": "fixed", "top": "-"+barMarginTop+"px" , "z-index" : "999"});
     }else{
            //如果卷軸拉沒有超過bar的原始offset.top(),將bar的css還原,刪除tempBar
      $(".tempBar").remove();
      $(".bar:not(.tempBar)").css({ "position": "static" , "z-index" : "auto"});
     }
   });

線上看成品:
http://jsfiddle.net/a33e97cg/

2015年9月2日 星期三

好用 jQuery 外掛

 各種jQuery外掛庫的搜尋網站:

  1. jQuery plugins

覺得好用的jQuery外掛:

  1. jQuery custom content scroller :為區塊加上滑動的側邊卷軸。
  2. fullPage.js:為網站增加上下滑動(section)及同section左右滑動(slide)的效果。