<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="/main.xsl"?>
<b:blog xmlns="http://www.w3.org/1999/xhtml" xmlns:b="http://blog.othree.net"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://blog.othree.net http://blog.othree.net/blooog.xsd">
	<b:blogTitle>O3noBLOG</b:blogTitle>
	<b:blogDescription></b:blogDescription>
	<b:entries>
		<b:entriesMeta>
			<b:listType>m</b:listType>
			<b:listData listID="2009-12">December 2009</b:listData>

			<b:previous>
				<b:mTitle>September 2009</b:mTitle>
				<b:mDate>2009/09</b:mDate>
			</b:previous>


			<b:next>
				<b:mTitle>January 2010</b:mTitle>
				<b:mDate>2010/01</b:mDate>				
			</b:next>

		</b:entriesMeta>

		<b:entry entryID="000606" baseName="basic-javascript-auto-unit-test">
			<b:author>
				<b:authorName>othree</b:authorName>
				<b:authorEmail>othree@gmail.com</b:authorEmail>
				<b:authorUrl></b:authorUrl>
			</b:author>
			<b:datetime>
				<b:date>2009-12-31</b:date>
				<b:time>10:18:41</b:time>
			</b:datetime>
			<b:category>vim</b:category>
			<b:title>簡單的 javascript 自動單元測試</b:title>
			<b:content>
				<b:summary>前幾天弄完 JSLint.vim 後，就對 server side javascript 產生了一些興趣，還抓了 v8 引擎 來用，於是就想到之前想弄很久的自動單元測試，想說要跑 QUnit ，不過 QUnit 雖然獨立於 jQuery 了，但還是要在瀏覽器環境下才能執行，純 javascript engine 還少了 DOM 和 BOM，就是說它需要 document, window 這些物件，找了一下發現 John Resig 有弄 env.js 這個專案，就是要在 js shell 裡面做出瀏覽器的環境，不過問題是目前只能跑在 Rhino 下，因為他是 java based ，可以在 javascript 裡面寫...</b:summary>
				<b:mainContent><p>前幾天弄完 <a href="http://github.com/hallettj/jslint.vim"><span class="caps">JSL</span>int.vim</a> 後，就對 server side javascript 產生了一些興趣，還抓了 <a href="http://code.google.com/p/v8/">v8 引擎</a> 來用，於是就想到之前想弄很久的自動單元測試，想說要跑 <a href="http://docs.jquery.com/QUnit">QUnit</a> ，不過 QUnit 雖然獨立於 jQuery 了，但還是要在瀏覽器環境下才能執行，純 javascript engine 還少了 <span class="caps">DOM </span>和 <span class="caps">BOM</span>，就是說它需要 document, window 這些物件，找了一下發現 John Resig 有弄 <a href="http://ejohn.org/blog/bringing-the-browser-to-the-server/">env.js</a> 這個專案，就是要在 js shell 裡面做出瀏覽器的環境，不過問題是目前只能跑在 <a href="http://www.mozilla.org/rhino/">Rhino</a> 下，因為他是 java based ，可以在 javascript 裡面寫 Java ，所以可以做很多壞事，但是其他的 js shell 沒辦法這樣跑， John Resig 好像有想要 port 成 python + v8 的版本，不過不知道有沒有成功，因為也 <a href="http://groups.google.com/group/envjs/browse_thread/thread/132617236878676b#">沒放出</a> 。</p></b:mainContent>
				<b:extendContent><p>剛好最近有點紅的 <a href="http://nodejs.org/">node.js</a> ，似乎可以拿來做一樣的事情（要做 http request、開檔案、DOM），於是也調查了一下，結果缺少了重要的 <span class="caps">DOM </span>，這樣也跑不起 Qunit，傷心難過之餘只好把方向改成尋找簡單的 JavaScript Unit Test Framework，希望能找到不會存取到 <span class="caps">BOM </span>和 <span class="caps">DOM </span>的版本，結果找到 <a href="http://github.com/jeresig/env-js/blob/master/test/testrunner.js">這個</a> ，雖然沒完全符合需求，不過裡面要改的地方很少，所以改了一下就拿來用了（還不知道授權所以不敢丟出來），把幾個要用到 jQuery, <span class="caps">DOM </span>的地方註解掉，還有 log 改成有錯誤才輸出，然後 ~/.vimrc 加上：</p>



<pre><code>function Jsunit ()
    let ut = 'unit.test.js'
    let fn = expand('&lt;afile&gt;:t')
    if fn != ut
        let cwd = expand('&lt;afile&gt;:p:h')
        if filereadable(cwd.'/unit.test.js')
            let has_error = 0
            let cmd = 'js '. ut
            let output = system(cmd)
            for error in split(output, &quot;\n&quot;)
                let has_error = 1
                caddexpr expand(&quot;%&quot;) . fn . &quot;:0:0:&quot; . error
            endfor
            if has_error == 1
                copen
            else
                echo 'Unit  : All OK.'
            endif
        endif
    endif
endfunction

autocmd FileWritePost,BufWritePost *.js :call Jsunit()
</code></pre>



<p>存檔的時候會自動找 unit.test.js ，如果存在的話就會執行它，unit.test.js 裡面長得像這樣：</p>



<pre><code>load('testrunner.js');
load('lib.js');

test('all', function () {
    ok(libFunc(true) == 530, 'send true');
    isObj(libFunc(false), {a:'1'}, 'send false');
});
</code></pre>



<p>不過這個 testrunner 不能做任何和 html 文件、瀏覽器有關的測試，只能做很核心部份的測試。</p></b:extendContent>
			</b:content>

			<b:comments commentCount="3"></b:comments>


			<b:trackbacks trackbackCount="0"></b:trackbacks>

		</b:entry>

		<b:entry entryID="000605" baseName="closure-compiler-osx">
			<b:author>
				<b:authorName>othree</b:authorName>
				<b:authorEmail>othree@gmail.com</b:authorEmail>
				<b:authorUrl></b:authorUrl>
			</b:author>
			<b:datetime>
				<b:date>2009-12-29</b:date>
				<b:time>23:16:50</b:time>
			</b:datetime>
			<b:category>unix</b:category>
			<b:title>closure-compiler on OSX</b:title>
			<b:content>
				<b:summary>Google 的 Closure Cmpiler 要 Java 1.6 ，蘋果雖然有提供 1.6 的 更新 ，不過在終端機下直接打 java 還是 1.5 版，至於 1.6 版則是放在 /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Commands/java 如果要跑 closure-compiler 建立shell script 時 java 執行檔要改用這個。...</b:summary>
				<b:mainContent><p>Google 的 <a href="http://code.google.com/intl/en/closure/compiler/">Closure Cmpiler</a> 要 Java 1.6 ，蘋果雖然有提供 1.6 的 <a href="http://www.apple.com/downloads/macosx/apple/application_updates/javaformacosx105update1.html">更新</a> ，不過在終端機下直接打 java 還是 1.5 版，至於 1.6 版則是放在</p>



<pre><code>/System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Commands/java</code></pre>



<p>如果要跑 closure-compiler 建立shell script 時 java 執行檔要改用這個。</p></b:mainContent>
				<b:extendContent></b:extendContent>
			</b:content>

			<b:comments commentCount="2"></b:comments>


			<b:trackbacks trackbackCount="0"></b:trackbacks>

		</b:entry>

		<b:entry entryID="000603" baseName="foo-eq-foo-or-default">
			<b:author>
				<b:authorName>othree</b:authorName>
				<b:authorEmail>othree@gmail.com</b:authorEmail>
				<b:authorUrl></b:authorUrl>
			</b:author>
			<b:datetime>
				<b:date>2009-12-29</b:date>
				<b:time>12:42:23</b:time>
			</b:datetime>
			<b:category>script</b:category>
			<b:title>var foo = foo || {};</b:title>
			<b:content>
				<b:summary>foo = foo || {}; 這樣的寫法大家一定不陌生，如果 ab 有值的話就繼續用，不然就讓他成為空物件。通常會用到的地方有兩種，函式設定參數預設值，或是跨檔案的公用函式庫，這種時候會把變數放在 global scope 下，也就是全域變數，要宣告全域變數的話不用 var，直接變數名稱就可以了，就像上面那段 code，不過實際上，這樣寫是會出錯的，沒寫 var 的話，第二個 foo 會跑出 foo 尚未定義的錯誤，所以寫成標題那樣是比較沒問題的，不過有時候，程式碼會全部包在一個 function scope 裡面，避免安全的問題，但是在這個 scope 裡面用 var 宣告變數的話，變數又不會是全域的，這時其實加上 window 就可以了： (function () { foo = window.foo || {}; })(); 也可以用 if 判斷：...</b:summary>
				<b:mainContent><pre><code>foo = foo || {};</code></pre>



<p>這樣的寫法大家一定不陌生，如果 ab 有值的話就繼續用，不然就讓他成為空物件。通常會用到的地方有兩種，函式設定參數預設值，或是跨檔案的公用函式庫，這種時候會把變數放在 global scope 下，也就是全域變數，要宣告全域變數的話不用 var，直接變數名稱就可以了，就像上面那段 code，不過實際上，這樣寫是會出錯的，沒寫 var 的話，第二個 foo 會跑出 foo 尚未定義的錯誤，所以寫成標題那樣是比較沒問題的，不過有時候，程式碼會全部包在一個 function scope 裡面，避免安全的問題，但是在這個 scope 裡面用 var 宣告變數的話，變數又不會是全域的，這時其實加上 window 就可以了：</p>



<pre><code>(function () {
foo = window.foo || {};
})();</code></pre>



<p>也可以用 if 判斷：</p>



<pre><code>(function () {
if (! window.foo ) { window.foo = {} }
})();</code></pre>



<p>最後我還發現一件趣事，大家可以猜猜看下面的 code 會不會有錯誤：</p>



<pre><code>(function () {
foo = undefined;
foo = foo || {};
})()</code></pre></b:mainContent>
				<b:extendContent></b:extendContent>
			</b:content>

			<b:comments commentCount="3"></b:comments>


			<b:trackbacks trackbackCount="0"></b:trackbacks>

		</b:entry>

		<b:entry entryID="000602" baseName="spidermonkey-utf-8">
			<b:author>
				<b:authorName>othree</b:authorName>
				<b:authorEmail>othree@gmail.com</b:authorEmail>
				<b:authorUrl></b:authorUrl>
			</b:author>
			<b:datetime>
				<b:date>2009-12-27</b:date>
				<b:time>16:01:39</b:time>
			</b:datetime>
			<b:category>unix</b:category>
			<b:title>spidermonkey 的 UTF-8 支援</b:title>
			<b:content>
				<b:summary>JSLint 其實是用 javascript 寫的 javascript 語法檢查工具， jslint.vim 並沒有把它轉成 vim script ，而是呼叫 JS 引擎來跑 JSLint ，最好找的 JS 引擎就是 mozilla 的 spidermonkey ，很多 linux 有包好的套件，FreeBSD 也有 port ，不過實際上用的時候發現有個問題，就是不支援 UTF-8 字串，結果就是在 JSLint 的字元檢查時會把一些中文當成不安全字元，例如：「下」。 其實要 spidermonkey 支援 UTF-8 字串也不難，FreeBSD 的話在裝 port 時加個參數就可以了，OSX 的話把 MacPorts...</b:summary>
				<b:mainContent><p><a href="http://www.jslint.com/"><span class="caps">JSL</span>int</a> 其實是用 javascript 寫的 javascript 語法檢查工具， <a href="http://github.com/hallettj/jslint.vim">jslint.vim</a> 並沒有把它轉成 vim script ，而是呼叫 JS 引擎來跑 <span class="caps">JSL</span>int ，最好找的 JS 引擎就是 mozilla 的 <a href="http://www.mozilla.org/js/spidermonkey/">spidermonkey</a> ，很多 linux 有包好的套件，FreeBSD 也有 <a href="http://www.freebsd.org/cgi/cvsweb.cgi/ports/lang/spidermonkey/">port</a> ，不過實際上用的時候發現有個問題，就是不支援 <span class="caps">UTF</span>-8 字串，結果就是在 <span class="caps">JSL</span>int 的字元檢查時會把一些中文當成不安全字元，例如：「下」。</p>

<p>其實要 spidermonkey 支援 <span class="caps">UTF</span>-8 字串也不難，FreeBSD 的話在裝 port 時加個參數就可以了，OSX 的話把 <a href="http://www.macports.org/">MacPorts</a> 更新到新版的再裝就可以了，Linux 的話就沒辦法用套件安裝，要自己抓來編， 1.7 的話要去修改 Makefile 讓 <span class="caps">CFLAGS </span>加上 "-DJS_C_STRINGS_ARE_UTF8" 這個參數，或是參考 <a href="http://www.mongodb.org/display/DOCS/Building+Spider+Monkey">mongoDB</a> 的作法，如果是 1.8 版的話有內建支援，不用修改 makefile，但是以後要執行的 js 檔案裡面都要先呼叫 <a href="https://developer.mozilla.org/En/SpiderMonkey/JSAPI_Reference/JS_CStringsAreUTF8">JS_CStringsAreUTF8</a> 這個函式，以 jslint.vim 來說就要加到 ~/.vim/plugin/jslint/runjslint.js 這個檔案。</p>

<p>其實要解決 <span class="caps">UTF</span>-8 問題還有其他方法，就是換其他的 JS 引擎，像是 <a href="http://code.google.com/p/v8/">Google V8</a> ， 要用 V8 的話 <a href="http://code.google.com/apis/v8/build.html">編譯</a> 時要編 developer shell ，產生的執行檔檔名叫 <strong>d8</strong> ，弄個鏈結讓 <strong>js</strong> 這個指令可以執行就可以了，V8 直接支援 <span class="caps">UTF</span>-8 ，弄起來就可以用了，不用再去改其他東西，理論上速度應該也比較快吧，JSLint 都跑很快，無從比較XD。</p></b:mainContent>
				<b:extendContent></b:extendContent>
			</b:content>

			<b:comments commentCount="0"></b:comments>


			<b:trackbacks trackbackCount="0"></b:trackbacks>

		</b:entry>

		<b:entry entryID="000601" baseName="javascript-on-vim">
			<b:author>
				<b:authorName>othree</b:authorName>
				<b:authorEmail>othree@gmail.com</b:authorEmail>
				<b:authorUrl></b:authorUrl>
			</b:author>
			<b:datetime>
				<b:date>2009-12-26</b:date>
				<b:time>20:10:45</b:time>
			</b:datetime>
			<b:category>vim</b:category>
			<b:title>javascript on vim</b:title>
			<b:content>
				<b:summary>因為現在主要都是在寫 javascript 為主，所以這兩天調整 Vim 主要目標都是為了 javascript，這篇整理一下使用的 plugin 和相關設定，不過在開始前，請先把 Vim 升級到 7.2，套件沒有的話自己編譯也可以。 syntax/indent Vim 雖然有內建支援 javascript 的縮排和語法標籤，不過另外都有人維護比較完整的版本，而且不只一種，我沒詳細比較，只是挑看起來比較有在維護的： JavaScript syntax : Better JavaScrirpt syntax support Javascript Indentation : Indentation for Javascript 照說明把檔案放到正確的位置即可，另外雖然有 jQuery 的 syntax ，不過我安裝後發現會和 The NERD Commenter 衝突，而且看一下內容覺得也沒做的很好，就沒用了。縮排的部份也有人是用外部程式來處理，詳細可以 vim-taiwan 上的...</b:summary>
				<b:mainContent><p>因為現在主要都是在寫 javascript 為主，所以這兩天調整 <a href="http://www.vim.org">Vim</a> 主要目標都是為了 javascript，這篇整理一下使用的 plugin 和相關設定，不過在開始前，請先把 Vim 升級到 7.2，套件沒有的話自己編譯也可以。</p>

<h4>syntax/indent</h4>

<p>Vim 雖然有內建支援 javascript 的縮排和語法標籤，不過另外都有人維護比較完整的版本，而且不只一種，我沒詳細比較，只是挑看起來比較有在維護的：</p>


<ul>
<li><a href="http://www.vim.org/scripts/script.php?script_id=1491">JavaScript syntax : Better JavaScrirpt syntax support</a></li>
<li><a href="http://www.vim.org/scripts/script.php?script_id=1840">Javascript Indentation : Indentation for Javascript</a></li>
</ul>



<p>照說明把檔案放到正確的位置即可，另外雖然有 <a href="http://www.vim.org/scripts/script.php?script_id=2416">jQuery 的 syntax</a> ，不過我安裝後發現會和 <a href="http://www.vim.org/scripts/script.php?script_id=1218">The <span class="caps">NERD</span> Commenter</a> 衝突，而且看一下內容覺得也沒做的很好，就沒用了。縮排的部份也有人是用外部程式來處理，詳細可以 <a href="http://groups.google.com/group/vim-taiwan">vim-taiwan</a> 上的 <a href="http://groups.google.com/group/vim-taiwan/browse_thread/thread/a371c30000e3138e">討論</a> ，我目前是還沒覺得有需求。</p></b:mainContent>
				<b:extendContent><h4>自動完成</h4>

<p>這部份就比較麻煩了，在自動完成我使用了 <a href="http://www.vim.org/scripts/script.php?script_id=2540">snipMate</a> （ <a href="http://blog.othree.net/log/2008/03/23/auto-complete-on-vim/">以前</a> 用 <a href="http://www.vim.org/scripts/script.php?script_id=1318">snippetsEmu</a> ，不過都沒更新了，而且內建的 snippets 少很多），還有 <a href="http://www.vim.org/scripts/script.php?script_id=1879">autocomplpop</a> ，兩者安裝都很簡單，就解到 .vim 目錄下，或是用 c9s 大大寫的 <a href="http://github.com/c9s/Vimana">Vimana</a> ，snipMate 別忘了先 <a href="http://groups.google.com/group/vim-taiwan/browse_thread/thread/55c11ab0438dfeb9">hack 一下</a> 讓它支援 autocomplpop ，autocomplpop 雖然新版已經有幫不少檔案格式設定好預設的行為了，包括 html 和 css，但是卻不包含 javascript，所以還要自己設定一下，在 vimrc 裡面加上以下的設定：</p>



<pre><code>let g:acp_enableAtStartup = 1
let g:acp_completeOption = '.,w,b,u,t,i,k'
let g:acp_behaviorSnipmateLength = 1
let g:acp_behaviorKeywordCommand = &quot;\&lt;C-n&gt;&quot;

let jsbehavs = { 'javascript': [] }
    call add(jsbehavs.javascript, {
        \   'command'      : &quot;\&lt;C-x&gt;\&lt;C-u&gt;&quot;,
        \   'completefunc' : 'acp#completeSnipmate',
        \   'meets'        : 'acp#meetsForSnipmate',
        \   'onPopupClose' : 'acp#onPopupCloseSnipmate',
        \   'repeat'       : 0,
    \})
    call add(jsbehavs.javascript, {
        \   'command' : g:acp_behaviorKeywordCommand,
        \   'meets'   : 'acp#meetsForKeyword',
        \   'repeat'  : 0,
        \ })
    call add(jsbehavs.javascript, {
        \    'command'  : &quot;\&lt;C-x&gt;\&lt;C-o&gt;&quot;,
        \    'meets'   : 'acp#meetsForKeyword',
        \    'repeat'   : 0,
    \})

let g:acp_behavior = {}
call extend(g:acp_behavior, jsbehavs, 'keep')
</code></pre>



<p>這樣編輯 javascript 時應該就會做正確的跑出自動完成的候選選項，包括 snipMate、關鍵字自動完成、和 omni 自動完成（好像有翻成全補完的），順便提一下，Vim 7.2 大部分檔案格式不用去設定 omnifunc ，幾乎都會指到自己的預設函式，不過 html 卻沒有，還要自己加下面這行到 vimrc ：</p>



<pre><code>autocmd FileType html set omnifunc=htmlcomplete#CompleteTags</code></pre>



<p>而且最好依照我 <a href="http://blog.othree.net/log/2009/12/25/bug-of-html-complete/">上一篇的建議</a> 修改一下。</p>

<h4>code 檢查</h4>

<p>再來是設定讓 <a href="http://www.jslint.com/">jslint</a> 檢查 javascript 程式碼，用的是 <a href="http://github.com/hallettj/jslint.vim">jslint.vim</a> ，要記得先安裝 <a href="http://www.mozilla.org/js/spidermonkey/">spidermonkey</a> ，然後照說明把檔案移動到 ~/.vim 裡面，這樣就可以執行 :JSLint 來檢查程式碼了，不過一開始一定會發現它對所有的全域變數都發出錯誤訊息，這時可以加上一些設定參數放到 ~/.jslintrc ，我的設定檔內容（其實就是 jslint.vim 提供的範例）：</p>



<pre><code>/*jslint browser: true*/
/*global jQuery $ */
</code></pre>



<p>第一行是說這些 code 是網路用的，用瀏覽器來執行，所以在這種環境下會出現的全域變數就不會被當成錯誤，第二行則是你自己定義會使用到的全域變數，這個範例是加上了 jQuery 的兩個全域變數，這些設定也可以加在 js 檔案裡面，其他的設定參數請看 <a href="http://www.jslint.com/lint.html">官方說明</a> 。不過每次都要執行 :JSLint 也是蠻麻煩的，所以可以設一下快速鍵，另外也可以設定存檔時自動檢查：</p>



<pre><code>map &lt;F12&gt; :JSLintLight&lt;CR&gt;
map &lt;F11&gt; :JSLint&lt;CR&gt;

autocmd FileWritePost,BufWritePost *.js :JSLint</code></pre>



<h4>壓縮</h4>

<p>最後就是壓縮了， <a href="http://blog.othree.net/log/2009/09/08/vim-js-yuicompressor/">以前有寫過個 function</a> ，因應 <a href="http://code.google.com/p/closure-compiler/">closure-compiler</a> 的出現和建議，現在有作些修改：</p>



<pre><code>function Yuic ()
    let cwd = expand('&lt;afile&gt;:p:h')
    let nam = expand('&lt;afile&gt;:t:r')
    let ext = expand('&lt;afile&gt;:e')
    if -1 == match(nam, &quot;[\._]src$&quot;)
        let minfname = nam.&quot;.min.&quot;.ext
    else
        let minfname = substitute(nam, &quot;[\._]src$&quot;, &quot;&quot;, &quot;g&quot;).&quot;.&quot;.ext
    endif
    if filewritable(cwd.'/'.minfname)
        if ext == 'js' &amp;&amp; executable('closure-compiler')
            cal system( 'closure-compiler --js '.cwd.'/'.nam.'.'.ext.' &gt; '.cwd.'/'.minfname.' &amp;')
        elseif executable('yuicompressor')
            cal system( 'yuicompressor '.cwd.'/'.nam.'.'.ext.' &gt; '.cwd.'/'.minfname.' &amp;')
        endif
    endif
endfunction

autocmd FileWritePost,BufWritePost *.js :call Yuic()
autocmd FileWritePost,BufWritePost *.css :call Yuic()
</code></pre>



<p>至於怎麼裝 <a href="http://developer.yahoo.com/yui/compressor/">yuicompressor</a> 和 <a href="http://code.google.com/p/closure-compiler/">closure-compiler</a> 就因系統而異了。</p>

<h4>其他</h4>

<p>其他還有兩個不是針對 javascript 的 plugin ，不過寫程式時蠻有用的，分別是 <a href="http://www.vim.org/scripts/script.php?script_id=1218">The <span class="caps">NERD</span> Commenter</a> 和 <a href="http://www.vim.org/scripts/script.php?script_id=294">Align</a> ，The <span class="caps">NERD</span> Commenter 是快速註解用，Align 則是對齊用，例如一連串的變數初值指定，可以用 :Align = 來把等號左右兩邊的程式碼對齊，美觀不少。</p></b:extendContent>
			</b:content>

			<b:comments commentCount="0"></b:comments>


			<b:trackbacks trackbackCount="0"></b:trackbacks>

		</b:entry>

		<b:entry entryID="000599" baseName="bug-of-html-complete">
			<b:author>
				<b:authorName>othree</b:authorName>
				<b:authorEmail>othree@gmail.com</b:authorEmail>
				<b:authorUrl></b:authorUrl>
			</b:author>
			<b:datetime>
				<b:date>2009-12-25</b:date>
				<b:time>23:58:29</b:time>
			</b:datetime>
			<b:category>vim</b:category>
			<b:title>htmlcomplete#CompleteTags 的 bug</b:title>
			<b:content>
				<b:summary>今天又在玩 vim 自動完成時發現的，網路上也有找到一點點情報，不過資料實在很少，我花了不少時間測試找出會發生問題的狀況，這個 bug 是在使用 autocomplpop 時，游標放到 class=" or id=" 這兩個字串後會有錯誤訊息 （line 304, E121: Undefined variable :classlines）。網路上找到有人 回報給 acp.vim 作者 ，日本那邊也有人 hack acp.vim 來避開這個問題 ，不過其實問題不在 autocomplpop，而是 vim 內的 htmlcomplete 的問題，這個 function 位置在 $VIMRUNTIME/autoload/htmlcomplete.vim ，上次更新是 2006 年了，之後回報 bug 會不會有人修還不知道XD。...</b:summary>
				<b:mainContent><p>今天又在玩 vim 自動完成時發現的，網路上也有找到一點點情報，不過資料實在很少，我花了不少時間測試找出會發生問題的狀況，這個 bug 是在使用 <a href="http://www.vim.org/scripts/script.php?script_id=1879">autocomplpop</a> 時，游標放到 class="  or id="  這兩個字串後會有錯誤訊息 （line 304, <span class="caps">E121</span>: Undefined variable :classlines）。網路上找到有人 <a href="http://74.125.153.132/search?q=cache%3Ahttp%3A%2F%2Fblog.mvp.org.cn%2F">回報給 acp.vim 作者</a> ，日本那邊也有人 <a href="http://likealunatic.jp/2009/09/29_acpvim.php">hack acp.vim 來避開這個問題</a>  ，不過其實問題不在 autocomplpop，而是 vim 內的 htmlcomplete 的問題，這個 function 位置在 $VIMRUNTIME/autoload/htmlcomplete.vim ，上次更新是 2006 年了，之後回報 bug 會不會有人修還不知道XD。</p></b:mainContent>
				<b:extendContent><p>這個錯誤訊息的發生條件其實很特別，首先 html 的 omnifunc 要設成 htmlcomplete#CompleteTags，就是說你的 vimrc 裡面應該會有一行長成</p>



<pre><code>autocmd FileType html set omnifunc=htmlcomplete#CompleteTags</code></pre>



<p>再來你正在編輯的 html 文件裡面要有 &lt;link rel="stylesheet" /&gt; 這種外連 <span class="caps">CSS </span>檔案的標籤，而關鍵是 href 指到的位置沒有一個可以用的檔案（不存在、無權限讀取都可），然後接下來你在 class=" 或是 id=" 的位置裡面執行了 omni complete (&lt;C-x&gt;, &lt;C-o&gt;) ，當然如果有裝 <a href="http://www.vim.org/scripts/script.php?script_id=1879">autocomplpop</a> 的話，這時就會自動幫你跑（2.7 版以後），錯誤訊息也就會自動冒出。</p>

<p>問題發生的原因是，這個 html 自動完成函式會去檢查你的 <span class="caps">CSS </span>，包括外連的檔案，去裡面把 class name, id name 抽出送回作自動完成的選項，不過他有一個動作應該是要檔案可讀才要跑的，卻放到 if 的外面，所以只要把它移過去就好了，錯誤那行 code 是 310 行：</p>



<pre><code>308        endif
309    &quot; We gathered classes definitions from all external files
310    let classes += classlines
</code></pre>



<p>把它移到 308 行的 endif 前面就好了：</p>



<pre><code>308        &quot; We gathered classes definitions from all external files
309        let classes += classlines
310    endif
</code></pre></b:extendContent>
			</b:content>

			<b:comments commentCount="1"></b:comments>


			<b:trackbacks trackbackCount="0"></b:trackbacks>

		</b:entry>

		<b:entry entryID="000598" baseName="zen-coding-on-vim">
			<b:author>
				<b:authorName>othree</b:authorName>
				<b:authorEmail>othree@gmail.com</b:authorEmail>
				<b:authorUrl></b:authorUrl>
			</b:author>
			<b:datetime>
				<b:date>2009-12-25</b:date>
				<b:time>11:18:41</b:time>
			</b:datetime>
			<b:category>vim</b:category>
			<b:title>Zen Coding on vim</b:title>
			<b:content>
				<b:summary>前兩天試了一下，還蠻厲害的，不過不知道是不是我現在的設定有點亂，所以沒辦法 tab 觸發自動完成，一定要按 Ctrl + E，另外就是目前只支援 HTML 的樣子，我看原始碼發現判斷檔案格式的函式直接回傳 "HTML"，不過這也還好，因為 CSS 有其他自動完成可以用，zen-coding 在 CSS 處理上沒特別強，但是 HTML 要到這樣厲害目前沒其他方案，下面記錄一下安裝方法。 先到 這串討論 抓最下面的 zencoding.vim 和 zencoding_vim.py 兩個檔案，放到 ~/.vim/plugin/ 裡，再來到 zen-coding 下載頁 抓 Zen Coding for TextMate v0.3.1.zip, TextMate.Zen.HTML.1.3.1.zip, TextMate.Zen.CSS.1.3.1.zip 三個檔案一樣解開放到 ~/.vim/plugin/ 裡面，這樣就可以了，測試方法就是隨便打個 css selector...</b:summary>
				<b:mainContent><p>前兩天試了一下，還蠻厲害的，不過不知道是不是我現在的設定有點亂，所以沒辦法 tab 觸發自動完成，一定要按 Ctrl + E，另外就是目前只支援 <span class="caps">HTML </span>的樣子，我看原始碼發現判斷檔案格式的函式直接回傳 "HTML"，不過這也還好，因為 <span class="caps">CSS </span>有其他自動完成可以用，zen-coding 在 <span class="caps">CSS </span>處理上沒特別強，但是 <span class="caps">HTML </span>要到這樣厲害目前沒其他方案，下面記錄一下安裝方法。</p>

<p>先到 <a href="http://code.google.com/p/zen-coding/issues/detail?id=16">這串討論</a> 抓最下面的 	zencoding.vim 和 zencoding_vim.py 兩個檔案，放到 ~/.vim/plugin/ 裡，再來到 <a href="http://code.google.com/p/zen-coding/downloads/list">zen-coding 下載頁</a> 抓 Zen Coding for TextMate v0.3.1.zip, TextMate.Zen.HTML.1.3.1.zip, TextMate.Zen.CSS.1.3.1.zip 三個檔案一樣解開放到 ~/.vim/plugin/ 裡面，這樣就可以了，測試方法就是隨便打個 css selector 然後按 Ctrl+E ，另外記得 selector 裡面不要有空白，這個 plugin 其實是用 Vim 跑 python ，所以 Vim 要先支援執行 Python Script ，我的就是裝完就可以，所以沒對這部份下去研究，如果有人跑不起來可以看看是不是這方面的問題。</p></b:mainContent>
				<b:extendContent></b:extendContent>
			</b:content>

			<b:comments commentCount="0"></b:comments>


			<b:trackbacks trackbackCount="0"></b:trackbacks>

		</b:entry>

		<b:entry entryID="000597" baseName="string-and-string-object">
			<b:author>
				<b:authorName>othree</b:authorName>
				<b:authorEmail>othree@gmail.com</b:authorEmail>
				<b:authorUrl></b:authorUrl>
			</b:author>
			<b:datetime>
				<b:date>2009-12-21</b:date>
				<b:time>11:05:15</b:time>
			</b:datetime>
			<b:category>script</b:category>
			<b:title>String and String Object</b:title>
			<b:content>
				<b:summary>JavaScript 中，基本的資料型態有數值、字串、布林三種，而這些資料的指派都有兩種方法，一種是直接指派值，另一種是用建構函式，以字串為例： var sv = &quot;1234567890&quot;; var so = new String(&quot;1234567890&quot;); 以前我一直以為兩種是等價的，不過在看 Efficient JavaScript 這篇文章時才發現兩者不是完全相等，在使用字串的 method 如 .charAt() 時，第一種字串值要先轉換成第二字串物件，然後才執行 .charAt() ，當需要大量執行字串的 method 時，用第二個方法來宣告字串變數理論上會比較快，不過我實際測試之後才注意到文章該段最後有說到這是 Opera 才有特別做最佳化的，測試用的code如下： var s = &quot;1234567890&quot;; //var s = new String(&quot;1234567890&quot;); var start = (new Date()).getTime(); for(...</b:summary>
				<b:mainContent><p>JavaScript 中，基本的資料型態有數值、字串、布林三種，而這些資料的指派都有兩種方法，一種是直接指派值，另一種是用建構函式，以字串為例：</p>



<pre><code>var sv = &quot;1234567890&quot;;
var so = new String(&quot;1234567890&quot;);</code></pre>



<p>以前我一直以為兩種是等價的，不過在看 <a href="http://dev.opera.com/articles/view/efficient-javascript/">Efficient JavaScript</a> 這篇文章時才發現兩者不是完全相等，在使用字串的 method 如 .charAt() 時，第一種字串值要先轉換成第二字串物件，然後才執行 .charAt() ，當需要大量執行字串的 method 時，用第二個方法來宣告字串變數理論上會比較快，不過我實際測試之後才注意到文章該段最後有說到這是 Opera 才有特別做最佳化的，測試用的code如下：</p>



<pre><code>var s = &quot;1234567890&quot;;
//var s = new String(&quot;1234567890&quot;);

var start = (new Date()).getTime();
for( var j = 0; j &lt; 10000; j++ ) {
  for( var i = 0; i &lt; s.length; i++ ) {
    s.charAt(i);
  }
}
var end = (new Date()).getTime();
alert(end-start);</code></pre>



<p>結果如下：</p>

<style type="text/css">
#content table {
  margin:1em 290px 1em 4em;
}
#content table th, #content table td {
  padding: 4px;
  margin: 1em;
}
</style>

<table>
        <tr>
            <th></th>
            <th>Opera</th>
            <th>Firefox</th>
            <th>IE</th>
        </tr>
        <tr>
            <th>"blah"</th>
            <td>234</td>
            <td>313</td>
            <td>344</td>
        </tr>
        <tr>
            <th>new String()</th>
            <td>156</td>
            <td>381</td>
            <td>266</td>
        </tr>
        <tr>
            <td colspan="4" style="text-align: right;">unit: micro seconds</td>
        </tr>
</table>

<p>可以發現 Opera 用 new String() 時有比較快， IE 雖然也有，不過我在某些電腦上測試結果是和 Firefox 差不多，沒列出來的 safari 其實表現也和 Firefox 差不多，至於 Google Chrome 在編譯的時候有最佳化過，結果都是超快，無法作為參考。所以結論是，還是繼續用普通的方法就好了XD。</p></b:mainContent>
				<b:extendContent></b:extendContent>
			</b:content>

			<b:comments commentCount="0"></b:comments>


			<b:trackbacks trackbackCount="0"></b:trackbacks>

		</b:entry>

		<b:entry entryID="000596" baseName="javascript-trivials">
			<b:author>
				<b:authorName>othree</b:authorName>
				<b:authorEmail>othree@gmail.com</b:authorEmail>
				<b:authorUrl></b:authorUrl>
			</b:author>
			<b:datetime>
				<b:date>2009-12-08</b:date>
				<b:time>17:20:53</b:time>
			</b:datetime>
			<b:category>script</b:category>
			<b:title>JavaScript 二三事</b:title>
			<b:content>
				<b:summary>好久沒寫 blog 了，來記錄一下最近和 JavaScript 有關的消息，首先是新書， High Performance JavaScript ，是除了 JavaScript Ninja 外我最近比較期待的新書，不過兩本都是明年才會出，JavaScript Ninja 是 John Resig 寫的，目標讀者是開發 JavaScript Framework 的開發者，所以內容相當深，我有先買預覽的電子版，裡面的 code 就常常看到暈頭， High Performance 那本則是 YUI 的開發者之一 Zakas Nicholas 寫的，之前也寫過不少書，不過我都沒看過就是，目前期待主要是書名的關係。 第二個則是 Loading JavaScript as strings 這篇文章，提到如果先把 js 程式碼先用字串形式讀進來，再用 eval() 來執行速度反而會比直接邊讀邊執行還要快，這項技巧可以用在...</b:summary>
				<b:mainContent><p>好久沒寫 blog 了，來記錄一下最近和 JavaScript 有關的消息，首先是新書， <a href="http://www.amazon.com/dp/059680279X/">High Performance JavaScript</a> ，是除了 <a href="http://jsninja.com/">JavaScript Ninja</a> 外我最近比較期待的新書，不過兩本都是明年才會出，JavaScript Ninja 是 <a href="http://ejohn.org/">John Resig</a> 寫的，目標讀者是開發 JavaScript Framework 的開發者，所以內容相當深，我有先買預覽的電子版，裡面的 code 就常常看到暈頭， High Performance 那本則是 <span class="caps">YUI </span>的開發者之一 <a href="http://www.nczonline.net/">Zakas Nicholas</a> 寫的，之前也寫過不少書，不過我都沒看過就是，目前期待主要是書名的關係。</p>

<p>第二個則是 <a href="http://www.stevesouders.com/blog/2009/12/07/downloading-javascript-as-strings/">Loading JavaScript as strings</a> 這篇文章，提到如果先把 js 程式碼先用字串形式讀進來，再用 eval() 來執行速度反而會比直接邊讀邊執行還要快，這項技巧可以用在 js 量大的 web application，對於之後才要用的 code 就用這種方法讀，讓頁面的生成可以快一點，詳細的內容在 12/8 的 <a href="http://en.oreilly.com/velocityfall09#faster-load-times"><span class="caps">O'R</span>eilly Velocity Online Conference</a> 會介紹並 demo ，換算成台灣時間好像是週三凌晨一點多開始。</p>

<p>最後一個不是新東西，其實是 <a href="http://code.google.com/speed/articles/optimizing-javascript.html">Google 的文章</a> ，裡面有講到會造成 memory leak 的原因，第一種是 IE 的 event function 可能會造成記憶體浪費（其實原因和下面的很像），解法是自己寫一個 event dispatcher ，像是 jQuery 就是這樣，第二種就是把資料附加在 <span class="caps">DOM </span>元件上，例如：</p>



<pre><code>var node = document.getElementById('getMe');
node.myData = 123;
</code></pre>



<p>像這樣可以把資料付在 <span class="caps">DOM </span>node 物件上，再某些情況下很有用，但是如果這些附加的資料包含其他 <span class="caps">DOM </span>node 的話，就會造成 memory leak ，建議的處理方法是完全不用這種特性，至於 jQuery 則是有個 <a href="http://docs.jquery.com/Data">data</a> 可以用，用法就像是 key, value 的資料型態。</p></b:mainContent>
				<b:extendContent></b:extendContent>
			</b:content>

			<b:comments commentCount="0"></b:comments>


			<b:trackbacks trackbackCount="0"></b:trackbacks>

		</b:entry>

	</b:entries>
</b:blog>
