// hello world を出力する最初の第一歩的プログラム
console.log("Hello World")
本編では標準出力に出力しているが、 スクリプト言語では簡便に使える標準入出力が JavaScriptでは標準的でない位置づけになっているので、 画面出力の場面ではこの Console.logを使って例を示した。
標準出力に出力するコードは以下のようになる。
// hello world を標準出力に出力する
process.stdout.write("Hello World\n")
// 一行読むだけのプログラム(呼んだ文字列は単に破棄される)
require('readline').createInterface({
input: process.stdin
}).on('line',(line)=>{
process.exit(0)
})
// 一行分 読んだものを書く
require('readline').createInterface({
input: process.stdin
}).on('line',(line)=>{
console.log(line)
process.exit(0)
})
// 一行ずつ 読んでは書く(オウム返し的プログラム)
require('readline').createInterface({
input: process.stdin
}).on('line',(line)=>{
console.log(line)
})
これらの例では、行単位の入力を実現するために readline モジュールを使っている。
こういったモジュールは、名前を(文字列で引数として渡して)指定して require して使うのが標準的な使い方。
このモジュール本体に対して、2つのメソッドw読んでいる。
この例からもわかるように、多くのプログラミング言語では、
入力しなさい
それを出力しなさい
というような流れを、動作指示の形で順次並べていく、 という考え方でプログラムが書かれるのに対して、
JavaScriptでは、
入力(されたことの知らせ)があれば、
こんな形でそれを処理しなさい
という考え方で、イベントに対する応答の形の プログラムを書くことが多い。
なお、上記の2つのメソッド(を含む多くのメソッド)が、 メソッドのレシーバ(であるモジュール本体)を、 評価した値として返す。
// 一行ずつ 読んでは書く(オウム返し的プログラム)
let rl=require('readline')
rl.createInterface({
input: process.stdin
})
rl.on('line',function(line){
console.log(line)
})
この書き換え例では、onメソッドに(第2引数として) 渡す無名関数を、ダブルアロー ‘=>’ を使った記法ではなく 古くから使われてきた function キーワードを 使った記法(名前のある関数を定義する文法に近いもの) を使っている(現在、どちらの記法を使ってもかまわない)。
EOFの検出:
リダイレクトなしの起動(標準入力がターミナルやコマンドプロンプトからの打鍵入力を扱うことになる)場合、その入力終了を伝え る仕組みが用意されていない(Ctrl-Cで止めることはできる)。
// 一行ずつ 読んでは書く(オウム返し的プログラム)
require('readline').createInterface({
input: process.stdin
}).on('line',(line)=>{
console.log(line)
}).on('close',()=>{
console.log('close')
process.exit(0)
})
(これまでに出てきたコードに関連して)
JavaScriptは(よく見かける)Classベースのオブジェクト指向ではなく、prototypeベースのオブジェクト指向のメカニズムで動いている。
ワンライナーが書けるような(Ruby等にある、以下のような)工夫はJavaScriptにはあまり用意されていない。
$_
に代入されたり、Regexp#=~
で $1,$2,… に代入されたり)は持っていない。それ以前に、入力を行う同期関数が標準では用意されていない(ライブラリとしてはあるが)ため、読み込んだもの(関数が値を返して)を変数に代入するという発想でのプログラムは 作られることが少ないようだ。
Ruby, Perl の -e
オプションに相当するものは、node.js にもあり、-e
で与えたコードを評価する。また、-p
オプションだと、評価した後にその値を印字する。
Rubyの -n
-l
オプションに相当するものはない。そもそも、Ruby, Perl, Python 等が、 ファイルに書かれたデータを出発点としてデータ駆動で動作するスクリプトを書くことから出発しているのの対し、JavaScriptは、イベント(ユーザの操作等)駆動でのコードを記述することから出発していて、同じ「スクリプト言語」に属していても、言語の動作原理が違うと考えていい。
また、短くコンパクトにコードを書くという発想も、最近になって CoffeeScript言語から(間接的にRubyから)刺激を受けて その記法がJavaScriptに逆輸入されるようになるまでは、JavaScript界にはなかった。
javascriptでは
a=b=c=100
のような連鎖代入(多重代入)が可能。ただ、JavaScriptでは、事前に(または代入と同時に)var let const 等で変数の宣言をすることが標準になっていて(宣言せずに代入するとグローバル変数が作られる)、多重代入にあたっては宣言にも注意を払うことは必要。例えば、
var a=b=c=100
とすると a だけがローカル変数で、b,c はグローバル変数の扱いになる。
引数の評価順序は、以下のように確認できるだろう。
console.log(console.log(1),console.log(2))
(このサイトによると、ES5の規格で定められているらしい。)
本ページで使った readline モジュールでは、読み込んだ文字列データに行末文字は含まれない(ここは Rubyの gets とは違う)ので、 Rubyで行ったような chop や chomp は必要ない。