JavaScriptのslice(0)はRubyのObject#dup相当のイディオム

CoffeeScriptのサンプルとして、doccoのソースコードを眺めていたら、以下のような謎のslice(0)があった。

# Run the script.
# For each source file passed in as an argument, generate the documentation.
sources = process.ARGV.sort()
if sources.length
  ensure_directory 'docs', ->
    fs.writeFile 'docs/docco.css', docco_styles
    files = sources.slice(0)
    next_file = -> generate_documentation files.shift(), next_file if files.length
    next_file()

arr.slice(0)は、イデックスがゼロのところから残り全部を切り出すということで、これは単にオブジェクトを複製しているだけらしい。破壊的操作をしたくないケースや、配列っぽいけど配列じゃないargumentsなどのオブジェクトを配列に変換するなどの目的で使われる。RubyのArray#sliceはArray#[]なので、引数が1つだと、1要素だけ引っ張ってくるので動作が違う。

jQueryには、こんなのがある。

if ( !all ) {
	namespaces = event.type.split(".");
	event.type = namespaces.shift();
	namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)");
}

sort()が破壊的だから、その前に複製している。そうか、JavaScriptのarray.sort()は破壊的なのか……。と思って、MDNのArray.prototype.sort()の解説を見たら、こう書いてあった。

If compareFunction is not supplied, elements are sorted by converting them to strings and comparing strings in lexicographic ("dictionary" or "telephone book," not numerical) order. For example, "80" comes before "9" in lexicographic order, but in a numeric sort 9 comes before 80.

比較関数を渡さないと、文字列に変換して辞書順オーダーでソート! まじか。

$ node
> a = [1, 8, 12]
> a.sort()
[ 1, 12, 8 ]
> a
[ 1, 12, 8 ]

オー、ノー……。

$ coffee
coffee> a = [12,8,1]
[ 12, 8, 1 ]
coffee> a.sort((a,b) -> a - b)
[ 1, 8, 12 ]

なるほどなぁ。