2012年10月30日 星期二

[宅] javascript筆記(8) - 全域變數&匿名函數

最近在PTT ajax版看到一篇非常不錯的筆記,正好把之前雜亂無章的理解給重新整理了一遍。
原文:http://disp.cc/b/11-4CrK (Knuckles@PTT)

使用全域變數時,由於要往上查找全域,造成效能低落,所以應盡量避免大量使用。
文中作者提到匿名變數的方法:
(function(x){ /*...*/ })(x);
自己寫lib時也曾用這個方法來寫。雖然在匿名函式外看不到裡面所定義的function和變數,但是可以在匿名函式內綁定function和外部觸發事件。也可以將匿名函式裡特定物件設為全域變數,由於scope的關係,外面看的到這個object,這個object也看得到匿名函式裡的其他function和變數。我們以ember.js開頭的一小段程式碼來做了解:
(function() {
  ...
  /**
  @class Ember
  */
  if ('undefined' === typeof Ember) {
    Ember = {};

    if ('undefined' !== typeof window) {
      window.Em = window.Ember = Em = Ember;
    }
  }
  ...
})();
當一個全域變數被定義時,等於是加入到window這個object底下。所以Ember={}跟window.Ember={}是一樣的。
而Ember這個object可能有很多function,例如Ember.deprecate,就可以在全域被看到。但如果Ember.deprecate需要使用一些varible或function,這些東西都必須放在Ember所被定義的匿名函式裡。

從Ember的寫法也能看出來,當include一個lib進來的時候,通常會定義一個特定名稱的Object再將相關的變數及函式都塞在這個Object底下,避免一不小心就重複命名了。

2012年10月29日 星期一

[宅] 宅男臥軌日記(6) - %Q, %q, %W, %w, %x, %r, %s

%Q( )

能將括弧中的內容轉成雙引號框成的字串,
而%Q後面未必要用括弧,也可以是!、[ ]、+等符號,例如:
%Q! !、%Q[ ]、%Q+ +

%q( )

功能跟大寫Q差不多,只是將內容換成單引號框成的字串。

※Notice: 在Ruby中定義字串時最好使用雙引號,因為只有在雙引號中才能使用#{var}來嵌入程式碼

%W( )

將括弧中的內容轉換成雙引號的string array,看下面的程式碼會更容易理解
>> %W(#{foo} Bar Bar\ with\ space)
=> ["Foo", "Bar", "Bar with space"]

%w( )

和大寫W是差不多的,只是將雙引號變單引號


%r( )

正規表示式,如下:
>> %r(/home/#{foo})
=> "/\\/home\\/Foo/"

%s( )

用於符號(symbol)
>> %s(foo)
=> :foo
>> %s(foo bar)
=> :"foo bar"
>> %s(#{foo} bar)
=> :"\#{foo} bar"

[宅] 宅男臥軌日記(5) - 資料表關聯方法: includes & joins

用一行程式碼大家應該就能明白:
user = User.includes(:authorizations).where("authorizations.provider" => 'facebook' , "authorizations.uid" => uid).first

includes跟joins功能挺像,引用ihower大大的部落格內的說法:
透過joins抓出來的event物件是沒有包括其關連物件的。如果需要其關連物件的資料,會使用includes。(出處:http://ihower.tw/rails3/activerecord-relationships.html)
但有一個差別在於includes所找到的model內的readonly屬性會是false,而joins所回傳的將是true。這造成了很大的影響:"用joins所找到的model不能被修改",所以當試圖修改model的值時,會回傳ActiveRecord::ReadOnlyRecord error.

2012年10月28日 星期日

[宅] 宅男臥軌日記(4) - class及instance的method定義

在定義class中的method時,要注意究竟是給instance使用還是class

當以如下方式定義method時,代表這個method是要給class的instance使用
class User
  def say_hello
    puts "Hello"
  end
end
所以當執行User.say_hello時就會發生找不到method的情況,但在以下情形會是正常的:
user = User.new
user.say_hello
=>"Hello"

所以如果一個method希望能被class所使用,必須以以下方式定義:
class User
  def User.say_hello
    puts "Hello"
  end
end
或是
class User
  def self.say_hello
    puts "Hello"
  end
end
當然也可以用extend從module中mixin進來

[宅] 宅男臥軌日記(3) - load或require路徑

在ROR中,若想load或require其他module進來,要將module放在哪哩?
我們可以看看config/application.rb中的設定:
# Custom directories with classes and modules you want to be autoloadable.
    config.autoload_paths += %W(#{config.root}/lib)
上面這一段就是指定module所在的資料夾,其中config.root是指config/的母目錄。所以這樣的設定之下,我們就要將module放在lib/底下,在class中引用module時,ROR就會知道要到lib/底下找。

要注意的是檔名如果有多字都是小寫,字和字之間用底線區隔,像這樣:
omniauth_callbacks.rb

裡面的module得要這樣命名:
module OmniauthCallbacks

2012年10月27日 星期六

[宅] 宅男臥軌日記(2) - ruby中的include, extend及require

include vs. extend

在ruby的世界中,class只能單一繼承,而為了保有彈性,ruby提供了module的概念。
module是一個method的集合,可讓class去混入(mixin)一個module來取得這些method,而mixin的過程可用include或extend來達到。
但是include和extend的差別在哪?我們可以從以下的程式碼得知:

module Foo
  def foo
    puts 'heyyyyoooo!'
  end
end


class Bar
  include Foo
end

Bar.new.foo # heyyyyoooo!
Bar.foo # NoMethodError: undefined method ‘foo’ for Bar:Class


class Baz
  extend Foo
end

Baz.foo # heyyyyoooo!
Baz.new.foo # NoMethodError: undefined method ‘foo’ for #<Baz:0x1e708>

簡而言之,include是讓這個class所產生的instance繼承module中的method,有點javascript中function.prototype的味道。
extend則是讓這個class具有module中的method,卻不會繼承給instance。


require

在講require之前必須先提到load,load的作用在於將不同檔案的module給mix進來,概念上類似於C的include。而require的作用就類似於load,只是在require只會mix一次,當發現之前已經mix過同一個檔案時,require就會回傳false。
require相對load會少掉不必要的mix動作,但在module時常被更新的狀態下,最好使用load來確保自己抓到的檔案是最新的。

2012年10月26日 星期五

[宅] 菜鳥出槌筆記 - 本地化設置錯誤

今天要執行mongo指令時,一直出現以下錯誤訊息:

terminate called after throwing an instance of 'std::runtime_error'

  what():  locale::facet::_S_create_c_locale name not valid

Aborted (core dumped)

上網查了一下發現是本地設定的問題,所以在mongo指令之前加上"LC_ALL=C"就可以成功執行了
LC_ALL=C mongo

[宅] node.js開發筆記(2) - 以express-vhost來建立虛擬主機 & 背景執行node.js

為了在同一個主機上搭載不同網域的網站,在npm上survey了一下相關套件,最後找到了express-vhost
npm install express-vhost
express-vhost是express的middle-ware,可以透過resiter將特定的網域綁定指定function,來達到以網域做分流的功能。詳情請看:https://github.com/vast-eng/express-vhost

我們希望node能夠在背景執行,而且即使登出主機也能繼續提供服務。
這時我們就要使用forever,他能夠讓你的js檔在背景執行,以下是安裝及啟動方法:
npm install -g forever//記得要設定為全域
sudo forever start server.js//若要以80port開啟服務,記得要以root權限執行

比較要注意的是,利用forever來執行js檔是沒辦法讓你看到console.log的,所以在啟動之前最好用node指令執行一次,確定服務正常再使用forever來開啟sever。尤其是你的server預設listen 80port時,忘了加sudo又沒有相關提示可能會讓你白白debug老半天還找不出原因。

話說其實node最好不要listen 80port,而是用其他伺服器程式來轉接給他,詳細原因可能下一篇再解釋。

2012年10月25日 星期四

[宅] node.js開發筆記(1) - 從安裝到express

最近開始使用node來開發一個vhost 應用~
因為之前是玩的時候是使用windows的環境,這次改在Ubuntu上開發,重新安裝的過程中也順便以筆記整理一下。

<step1> 安裝相關需求
因為這個環境空空如也,非常的乾淨,所以事先必須把一些基本的需求給建立起來
sudo apt-get install python-software-properties
sudo apt-get install make
sudo apt-get install g++
sudo apt-get install git
以上都搞定後就可以從github上下載下來並安裝了:
git clone https://github.com/joyent/node.git
cd node
git checkout v0.6.7
./configure
make
sudo make install
這樣就裝好了~

<step2>安裝npm
npm之於node就好比gem之於ROR,
gem之於ROR就好比apt-get之於Ubuntu....科科

咳,總之npm是node的套件安裝工具,
比較常用到的指令不外乎
npm install -g {你要裝的套件} //-g是代表這個套件可被全域使用,可以不用加
npm search {你要查的關鍵字}
npm list //列出你已安裝的套件

在安裝套件後,npm會把套件的module放在當下資料夾的"node_modules"資料夾中,
在執行node時就可以require該module,前提是執行的js檔所在的資料夾下要有"node_modules"資料夾且裡面那些module才行。
不過照理來說,我安裝的全域套件不用特別塞在裡面就找得到了,事實證明是不行啊~Orz
鳩竟是怎麼回事還得再查查~

<step3>用npm安裝express
express必裝!!!怎麼裝請看下面:
sudo npm install -g express
當要全域安裝時記得加sudo,不然會失敗

<step4>啟動server
我們要使用express的API來設定特定routing的response,將以下程式碼寫入"server.js":
// create server.
    var express = require('express'),
        app = express(),
        port = 1337; 

    app.listen(port);

    // normal style
    app.get('/', function(req, res){
        res.send('hello world');
    });
執行:
node server.js

就可以在localhost:1337上看到"hello world",代表server正常的運行囉~


2012年10月10日 星期三

[宅] coffeescript第一課 - "原來不能這樣寫"

為了開發node以及導入同伴的python開發經驗,從今天開始接觸coffeesscript,來體驗他簡短程式碼並最佳化成javascript的能力。

一開始當然是要體驗一下他和javascript的不同啦,
首先是scope的習慣,在javascript中我們會習慣用大括號來圈起範圍,而在coffeescipt中我們使用縮排。
再來,在javascript中很常見的 for( i in obj)在coffeescript中是會有問題的,因為他會把這段程式轉化為:

for (_i = 0, _len = obj.length; _i < _len; _i++) {
}

而object預設根本沒有length,而這段程式碼很明顯就是為了array寫的,運用在array上當然也沒問題。那要loop物件中的attr該怎麼辦呢?我們只需要改成 for( i of obj)即可,而因為coffeescript具有List comprehension的特性,讓他能用以 下的方式來寫loop:

alert item for item of v

而不用

for( item of v){
     alert(v[item])
}

超快的,對吧?