2014年3月2日 星期日

使用 bind 建立 Curry 函式

保留重複參數的函式,不必每次傳遞


// 一個簡單字串組合函式
function profile(pro, place, name) {
    return 'My name is ' + name + ', I am a ' + pro + ' from ' + place;
}
// 在 profile 上使用 bind 建立 Curry 函式, 也就是建立一個具有所需引數固定子集的代理函式
 
// 新增組合字串方法, 前面兩個參數是固定的, 因為沒有使用到 this, 所以不設定接收者 
var dancer = profile.bind(null, 'dancer', 'Taipei');
dancer('Ian'); // "My name is Ian, I am a dancer from Taipei"
dancer('Joe'); // "My name is Joe, I am a dancer from Taipei"
 
var names = ['Peter', 'Terry', 'Alice'];
var writers = names.map(profile.bind(null, 'writer', 'Tainan'));
console.log(writers);

writers 顯示 :
["My name is Peter, I am a writer from Tainan", "My name is Terry, I am a writer from Tainan", "My name is Alice, I am a writer from Tainan"]

2014年3月1日 星期六

call 和 apply 的用法

call :
theFunction.call(objOfThis, arg1, arg2, ...)

apply :
theFunction.apply(objOfThis, arrayOfArgs)

objOfThis(接收者)如果沒提供參數, 則 global 就會被當成接收者

function theFunction(name, profession) {
    console.log("My name is " + name + " and I am a " + profession + ".");
}
theFunction("Ian", "programmer");
theFunction.apply(undefined, ["Terry", "dancer"]);
theFunction.call(undefined, "Peter", "writer");

顯示 :
My name is Ian and I am a programmer.
My name is Terry and I am a dancer.
My name is Peter and I am a writer.

call 方法使用在高階函示中

// 建立一個 Table 建構式, 可存放 key-value
function Table(name) {
    this.name = name;
    this.entries = [];
    this.addEntry = function (key, value) {
        this.entries.push({ key: key, value: value });
    };
    // f : 傳入一個方法當 callback, thisArg : 傳入一個物件當接收者
    this.forEach = function (f, thisArg) {
        var entries = this.entries; // 本身的值 (呼叫 forEach 的物件)
        for (var i = 0, n = entries.length; i < n; i++) {
            var entry = entries[i];
            f.call(thisArg, entry.key, entry.value, i);
        }
    };
}
// 實例一個 Table 然後加入一些資料
var tab1 = new Table('tab1');
tab1.addEntry(1, 'apple');
tab1.addEntry(2, 'ball');
tab1.addEntry(3, 'city');
// 再實例一個 Table
var tab2 = new Table('tab2');
// 將tab1的資料複製到tab2
tab1.forEach(tab2.addEntry, tab2);

閉包 Closures - 高階函式 Higher-order functions

高階函示 : 
1. 把其他函式當作引數 (callback function / 回呼函式, 即呼叫時傳入她, 然後她再呼叫回來)
2. 會回傳函式

  • 使用標準程式庫原本的方法

var nums = [1,3,5,7,9,8,6,4,2];
nums.sort(function(x,y){
  if(x<y) return -1;
  if(x>y) return 1;
  return 0;
});
console.log('nums = ' + nums);
 
var names = ['Ian','Peter','Kevin'];
names = names.map(function(name){
    return name.toUpperCase();
});
console.log('names = ' + names);

顯示 :
nums = 1,2,3,4,5,6,7,8,9
names = IAN,PETER,KEVIN


  • 自訂高階函式

// 依照條件建立字串
function buildString(n, callback) {
    var result = '';
    for (var i = 0; i < n; i++) {
        result += callback(i);
    }
    return result;
}
 
// 建立 a~z
var aIndex = 'a'.charCodeAt(0); // 97
var alphabet = buildString(26, function (i) {
    // 這個 callback function 會被執行 26 次, i 接收到的是在 for 迴圈內丟給 callback function 的值, 所以會得到 0 ~ 25
    return String.fromCharCode(aIndex + i);
});
console.log('alphabet = ' + alphabet);
 
// 建立 1~9
var digits = buildString(9, function (i) { return i + 1; });
console.log('digits = ' + digits);
 
// 建立4個亂數
var random = buildString(4, function () {
    return Math.floor(Math.random() * 10);
});
console.log('random = ' + random);

顯示 :
alphabet = abcdefghijklmnopqrstuvwxyz
digits = 123456789
random = 7406



2014年2月28日 星期五

閉包 Closures

function diySandwich(ingredient) {
    // 回傳之後, 內層 function 能夠參考定義那些在外層 function 中的變數 ingredient
    return { // 回傳一個物件, 含有三個 closures : make / getIngredient / changeIngredient
        make: function (filling) { return ingredient + ' and ' + filling; },
        getIngredient: function () { return ingredient; },
        changeIngredient: function (newIngredient) { ingredient = newIngredient; } // 更新外層變數的值
    };
}

執行結果 :
var mySandwich = diySandwich('ham');
undefined
mySandwich.getIngredient();
"ham"
mySandwich.make('honey');
"ham and honey"
mySandwich.changeIngredient('turkey');
undefined
mySandwich.getIngredient();
"turkey"
mySandwich.make('chili');
"turkey and chili"


2014年2月13日 星期四

資料輸出到頁面可顯示斷行

存檔到資料庫的文字有斷行, 要在頁面顯示出來來時

使用 @razor
@Html.Raw(Model.Message.Replace("\r\n""<br />").Trim())

使用CSS white-space property (最好的方法, 可以避免 Cross-site scripting (XSS) 漏洞)
<p style="white-space: pre-line">@Model.Message</p>

2014年2月5日 星期三

分割字串

split string column into multiple records



電影資料表有三個字串欄位分別記錄男演員/女演員/導演, 欄位的字串是由不同資料組成, 現在想要把字串分割成單筆資料 :
















DECLARE @videoId nvarchar(max) = 'M00000000007105' --電影編號

DECLARE @temp TABLE
(
  RoleType VARCHAR(Max),
  ColumnB VARCHAR(Max),
  ID INT IDENTITY(1,1)
)

-- 放置 Video 資料表的演員欄位字串
INSERT INTO @temp (RoleType,ColumnB) VALUES ('Actor',(select Actors from Video where ID=@videoId))
INSERT INTO @temp (RoleType,ColumnB) VALUES ('Actress',(select Actresses from Video where ID=@videoId))
INSERT INTO @temp (RoleType,ColumnB) VALUES ('Director',(select Directors from Video where ID=@videoId))
--select * from @temp

DECLARE @idx INT, @cnt INT
SET @idx = 1 -- 給迴圈使用的初始值
SELECT @cnt = COUNT(*) FROM @temp -- 筆數

DECLARE @SplitStr nvarchar(Max), --   暫時放置ColumnB : 演員們的姓名
        @SplitChar nvarchar(Max), -- 分割的字元
        @Columns VARCHAR(Max) --  暫時放置RoleType : 演員腳色有三種 (Actor / Actress / Director)

SET @SplitChar = ';'

DECLARE @actorInVideo table
(
    RoleType nvarchar(50),
    Name nvarchar(50)
)
-- 逐一跑每個row
WHILE @idx <= @cnt BEGIN
        SELECT @SplitStr = ColumnB,@Columns = RoleType FROM @temp WHERE id = @idx

         Declare @Count int =-- 巢狀迴圈的初始值
        
         -- 利用CHARINDEX函數,可抓取字串中指定字串的起始位置
         -- 利用SUBSTRING函數 ( expression , start , length ) : 可截取字符串expression,從 start 個字符開始,到Length 結束
         While (Charindex(@SplitChar,@SplitStr)>0) Begin -- 表示有分割字元存在, 這裡設定的是分號
            Insert Into @actorInVideo (RoleType,Name)
                Select @Columns,ltrim(rtrim(Substring(@SplitStr,1,Charindex(@SplitChar,@SplitStr)-1))) -- 擷取第一個分割字元前面的文字

            Set @SplitStr = Substring(@SplitStr,Charindex(@SplitChar,@SplitStr)+1,len(@SplitStr)) -- 擷取第一個分割字元後面的所有文字
            Set @Count = @Count + 1
        End

        Insert Into @actorInVideo (RoleType,Name) Select @Columns,ltrim(rtrim(@SplitStr)) -- 剩下沒有分割字元的字串

        SET @idx = @idx + 1 -- 下一個 row
end
select * from @actorInVideo