Feeds:
文章
留言

Archive for 八月 15th, 2007

(轉貼)Hi Ne Ni 我在這裡

原始連結:http://www.im.tv/vlog/personal/909360/2281226

耶和華我的主啊
求你使我放下心中、放下心中所愛
耶和華我的主啊
求你使我打碎心中、心中偶像
直到我在敬拜中獻上自己為祭
無怨無悔、永不回頭
直到我在祭壇那裡得著命定
無怨無悔、我在這裡

Hi- Ne- Ni、Hi -Ne- Ni
燒我差我,我在這裡。
Hi- Ne- Ni、Hi- Ne- Ni
燒我差我
Hi –Ne- Ni

為這世界黑暗的角落,我在這裡
為那不曾被安慰的靈魂,我在這裡
Hi- Ne-Ni

 
最近作什麼事情都懶洋洋,服事上也是如此,原本寫完文章想去睡覺,恰好看到"夏美~~なつみ"留言,所以又連上 I’m Vlog 看有什麼新音樂,再一次看到"獻上感恩的心"那篇寫的唐蒙恩自傳,很受感動,也讓我想了一下自己未來的道路。接著又看到"Hi Ne Ni 我在這裡"這首歌,他的歌詞真是讓我感動
 
"求你使我放下心中、放下心中所愛….求你使我打碎心中、心中偶像。直到我在敬拜中獻上自己為祭…直到我在祭壇那裡得著命定…"
,也許這就是此刻我需要對神的禱告~

Read Full Post »

MSN SpaceGoogle DocGoogle Blog
Chui-Wen Chiu
2007.08.16

Peter[1] 提出一種用於函數式編程的設計模式稱為"Lazy Function Definition"。首天他提出一個問題:

"撰寫一個 foo 函數,並回傳第一次呼叫 foo 的時間。"

針對這個問題,他提出下面四種不同的解法:

解法#1: 傳統解法-全域變數

var t; // 紀錄第一次呼叫 foo 的時間
function foo() {
if (t) { // 假如已經有存放時間,則直接回傳
return t;
}

t = new Date(); // 紀錄第一次呼叫時間
return t;
}

上述解法有兩個問題:

1. 需要一個額外的全域變數 t,該變數有可能在呼叫 foo 時被修改

2. 程式碼在執行階段無法達到最佳效率。因為每次呼叫都需要進行條件評估。雖然上述範例的條件式損耗很廉價,但是真實情況的條件式可能是多層次的 if-else-else-… 結構。

解法 #2: Module Pattern

利用 Cornford and Crockford 所提出的 Module Pattern[2] 可以解決解法#1 的第一個問題,透過 closure 技法將全域變數封裝成只有 foo 內的程式可存取,如下:

var foo = (function() {
var t; // 封裝在 foo 內的變數
return function() {
if (t) {
// 假如已經有存放時間,則直接回傳
return t;
}
t = new Date();
// 紀錄第一次呼叫時間
return t;
}
})();

這種解法仍有解法#1的第2個問題存在,仍需重複進行條件式評估。

解法 #3: 函數即物件-使用物件屬性保存狀態

function foo() {
if (foo.t) {
// 假如已經有存放時間,則直接回傳
  return foo.t;
}
foo.t = new Date();
// 紀錄第一次呼叫時間
return foo.t;
}

這個解法比 Module Pattern 更為簡潔,直接透過物件屬性存放資料,而不需要在產生一個額外的 Function Object。所以也能避免全域變數的問題。但這種解法仍有解法#1的第2個問題存在,仍需重複進行條件式評估。

解法 #4: Lazy Function Definition

var foo = function() {
var t = new Date();
foo = function() { // 改寫原先的函數定義
return t; // Closure t
};
return foo(); // 套用新的 foo 函數回傳值
};

當 foo 第一次被呼叫時,會先實體化一個 Date 物件並重新指定將 Date 物件 Closure 的 foo 函數,透過重新的指定可以改寫原來的函數定義,因為 Date 物件已經被 Closure,所以會一直存在。透過此一解法可以避免解法#1的兩個問題。

因此上述原來的 foo 函數定義可以想像成初始化內部 foo。簡單的說,第一次呼叫 foo 的函數定義如上程式,但之後的程式碼定義則是如下:
function foo() {
    return t; // Closure t
};

上述可透過下面的程式碼進行測試:

var foo = function() {   
    var t = new Date();
    alert(1);
    foo = function() {
        return t;
    };
    alert(2)
    return foo();
};
alert( foo() ); // 出現 1, 2, 日期
alert( foo() ); // 出現 日期

應用:判斷不同瀏覽器的頁面捲動

var getScrollY = function() {


if (typeof window.pageYOffset == 'number') {

getScrollY = function() {
return window.pageYOffset;
};

} else if ((typeof document.compatMode == 'string') &&
(document.compatMode.indexOf('CSS') >= 0) &&
(document.documentElement) &&
(typeof document.documentElement.scrollTop == 'number')) {

getScrollY = function() {
return document.documentElement.scrollTop;
};

} else if ((document.body) &&
(typeof document.body.scrollTop == 'number')) {

getScrollY = function() {
return document.body.scrollTop;
}

} else {

getScrollY = function() {
return NaN;
};

}

return getScrollY();
}

透過 "Lazy Function Definition" 只需要在第一次花費條件式評估,對於重複呼叫的函數特別能夠改善效率。

補充

Firefox/Safari/Opera 的 getter methods[3] 能夠在屬性上模擬 "lazy definition" 如下:

this.__defineGetter__("foo", function() {
var t = new Date();
this.__defineGetter__("foo", function() {
return t;
});
return t;
});

// To the user, foo appears as a plain old
// non-function valued property of the global object.
console.log(this.foo);
setTimeout(function(){console.log(this.foo);}, 3000);

參考資料
[1] Peter, "Lazy Function Definition Pattern"
[2] Eric Miraglia, "A JavaScript Module Pattern"
[3] "Core JavaScript 1.5 Guide:Creating New Objects:Defining Getters and Setters"

Read Full Post »