2015/06/04 このエントリーをはてなブックマークに追加 はてなブックマーク - JavaエンジニアのためのJavaScript資料を目指して色々

JavaエンジニアのためのJavaScript資料を目指して色々

カテゴリ: , ,








プログラマの中には何故かJavaScriptを避けたがる人がいるように思います。

フロントエンドのマルチブラウザ環境や
変化の早さ、テストの難しさなどを敬遠しているのかなと思っています。

[JavaFX] Why, Where, and How JavaFX Makes Sense

だけど、個人的には言語だけ見るとそんな必要もないなと思うのです。
JavaScriptは素直で便利なやつだと思ってます。


そこで、今回はJavaエンジニアに贈るJavaScriptについて、
という気持ちを込めて記事を書きます笑








なんちゃってJavaScript使いなので、正しくない部分もあると思います。
また、ブラウザ上での操作を想定しています。
「普段Javaやってる僕がJavaScriptを調べてみた」ぐらいの内容と思ってください。


僕がどのぐらい普段JavaScript書いているかというと、
たまにajax処理とかUIの描画操作とかイベントハンドリングとかを
JavaScriptでやってcallbackヘルに悩ませられるレベルです。





  • ECMAScript
  • エクマスクリプトと読むらしい。
    JavaScriptの標準仕様とされています。
    現在はECMAScript5が最新。ECMAScript6策定中。
    ECMAScript4は放棄されたので、古い環境(具体的にはIE8とか…)
    だとECMAScript 3っぽいです。で、僕の知識もECMAScript 3ぐらい。。

    http://ja.wikipedia.org/wiki/ECMAScript
    http://kangax.github.io/compat-table/es5/


  • ブラウザのWeb API DOM
  • documentやconsoleといったオブジェクトはDOMの仕様に則って、
    ブラウザが提供しているAPIということだと思っています。
    それをJavaScriptから使っている、ということ。多分。

  • JavaScriptにはクラスが無い。

  • JavaScriptはクラスベースのオブジェクト指向ではないです。
    オブジェクトが色んなものを構築しているシンプルな言語だと思います。
    (クラス構文を用意する流れは各所であります)


Javaのやり方がJavaScriptで出来ないっていうのは根本的に違っていて、
JavaとクラスとJavaにおけるオブジェクト指向のことは忘れて
頭をクリアにして学んだほうが良いように思います。


それを踏まえて、Javaを普段使っているような人は
Javaだったらこういう手法でこういう目的があるけど
JavaScriptだとやり方わかんないなってなると思うので、
つらつら書いて整理してみることにします。





Javaで言うところのjava.langパッケージみたいな。どっからでもつかえるやつ。
各種類ごとに見ていきます。


とりあえずここらへん抑えておけばいいだろう、っていう
僕のお得意な発想です。


汎用コンストラクタ



  • Array
  • Boolean
  • Date
  • Function
  • Iterator
  • Number
  • Object
  • RegExp
  • String
  • Proxy
  • ParallelArray


よく使うのはObject、Array、Dateとかですかね…。
ただ、Dateに関してはブラウザの日時(クライアント側の日時)なので、
システム日付とか呼ばれるものを利用する場合には
サーバー側から取得する必要があります。


非コンストラクタ関数

  • encodeURI
  • eval
  • isNaN
  • parseFloat
  • parseInt
  • uneval


このあたりもよく使う関数ですね。


2015/06/07追記


evalを使うことはあまり推奨されていません。
文字列を関数として実行するものなので、悪意のあるインジェクションとか
気にしないとダメってことですね。


https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/eval

その他

  • Infinity
  • Intl
  • JSON
  • Math
  • NaN
  • undefined
  • null


JSONとかはECMAScript 5からです。。。


2015/06/07追記

ECMAScript 5なんですが、ブラウザによってはJSONをサポートしているものもあります。
ECMAScript 5 compatibility table

もろもろ詳しくは下記参照ということで。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects




このあたりを覚えておくと良いと思います。
JavaScriptというよりはWebのAPIなところですが。。

  • window
  • ブラウザウィンドウの情報を持つ
  • (window.)document
  • DOM操作のための情報をもつ
  • console
  • ログ出力用のオブジェクト
  • (window.)parent
  • 親ウィンドウの情報をもつ
  • (window.)opener
  • ウィンドウを開いたウィンドウの情報を持つ




このあたりも、説明するまでもないかなぁという感じです。
  • (window.)alert
  • ウィンドウアラート表示
  • (window.)open
  • 別ウィンドウ表示
  • (window.)close
  • ウィンドウを閉じる
  • (window.)confirm
  • 承認ウィンドウ表示
  • (window.)document.createElement
  • DOMエレメント作成
  • (window.)document.getElementById
  • idでDOMエレメント取得
  • (window.)document.getElementsByName
  • nameでDOMエレメント取得
  • (window.)document.getElementsByTagName
  • tag名でDOMエレメント取得
  • (window.)document.getElementsByClassName
  • class名でDOMエレメント取得
  • console.dir
  • 対象を階層化してコンソールに出力
  • console.log
  • コンソールに一般タイプのログを出力
  • console.time
  • 時間計測用出力(開始)
  • console.timeEnd
  • 時間計測用出力(終了)
https://developer.mozilla.org/ja/docs/Web/API/Window https://developer.mozilla.org/ja/docs/Web/API/console




続いて、イディオム的なところを見ていきます。



オブジェクトの中身とか見たい時とかよく使います。僕は。
JavaScriptのオブジェクトは連想配列みたいに
キーバリュー構造になっているというのが重要ですね。
何入ってのかな~ってよくループして眺めます。



for(var key in obj ) {
    console.log("key=" + key + ": value=" + key[obj]);
}


2015/06/07追記


・ブラウザのデベロッパーコンソールとか使えばオブジェクトの中身は見えるがな
・console.dirというものがあってだな…
・hasOwnPropertyは使おう

というコメントをもらいました。仰るとおりですね(^^;

ということで、全然for - inのループを使う例としては良くないものでした。。。

console.dirはオブジェクトの中身を階層構造で一気に見れるので
keyとvalueもざっと見れるもののようです。

hasOwnPropertyを使わないとプロトタイプの親のプロパティも全てループしてしまう
ので、セオリーに反すると。なるほど。



サンプルコードもコメントでいただいてます。

var objA = { a: 1, b: 2 };
var objB = Object.create(objA);
objB.c = 3;

for(x in objB){
    console.log(x);
} // c, a, b

for(x in objB){
    if(objB.hasOwnProperty(x)){
        console.log(x);
    }
} // c

// Object #keys#forEachを使う
var m = {a: 1, b: 2};
Object.keys(m).forEach(k => console.log(k + ", " + m[k]));





JavaScriptの関数の実体はFunctionというオブジェクトです。
ただ、それを表現する方法、呼び方がいっぱいあるだけです。多分。

2015/06/07追記


関数の書き方に関しては主に巻き上げが起こるか、起こらないかが
重要なポイントのようです。
http://bonsaiden.github.io/JavaScript-Garden/ja/#function.general


関数文


よくある関数ですね。

function addFuncSentence(a, b) { return a + b };



関数式


変数に代入される関数を関数式と言うっぽいです。

var addFunc = function (a, b) { return a + b };
addFunc(1, 1) // => 2


無名関数


名前を持たないfunctionのことです。Javaでいう無名クラスに近いかなぁ。



(function(a, b) { return a + b; })(1 , 1); // => 2


メソッド


メソッドとは言いますが、オブジェクトのプロパティとして
関数を持つ場合にメソッドと呼びます。

var calculator = {
    add : function(a, b) { return a + b; }
}

calculator.add(1, 1) // =>  2


クラスという概念は無い。全てオブジェクトです。 (ECMAScript 6ではクラス構文を作る流れもありますが、これまでの歴史としてはありません)

こういう書き方もできます。
var calculator = new Object();
calculator.add = function(a, b) { return a + b; };
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions_and_function_scope



注意すべきなのは
==と===
基本的に===を使う方が思った挙動をしてくれる。
後は必要に応じてかなぁ。


https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators



このスライドが素晴らしいです。


http://www.slideshare.net/yuka2py/javascript-23768378




  • クラス継承

  • JavaScriptにはない。プロトタイプチェーンでの継承が使える。

// 関数オブジェクトの生成
var Greeter  = function(){};
// プロトタイプ属性の利用
Greeter.prototype.greet = function(){ console.log("hello")};
var greeter = new Greeter();
greeter.greet(); // => hello
// 関数オブジェクトの生成
var AnotherGreeter = function(){};
// プロトタイプ属性の注入
AnotherGreeter.prototype = new Greeter();
var another = new AnotherGreeter();
another.greet(); // => hello

うーん。書いててやっぱりプロトタイプの仕組みはよくわかってないです。
もっと勉強せねば。


  • オーバーライド
  • JavaScriptにはない。プロトタイプチェーンなどが使える。
// (上のつづき)
another.greet(); // => hello
another.greet = function() {console.log("another"); };
// インスタンスに対しての関数が優先される
another.greet(); // => another


2015/06/07追記


これだとこのanotherってオブジェクトに対して関数の上書きを行うだけなので、
オーバーライドというのには微妙で、あんまりやる手法でもないそうです(^^;


  • オーバーロード
  • JavaScriptにはない。argumentsとかで頑張るぐらいです。 だったら、元から関数名変えたり設計変えたりした方が良いなぁって なると思います。


    2015/06/07追記

    コメント引用しておきます。。
    オーバーロードはふたつパターンがあると思います。引数の数違いと変数の型違い。
    前者は arguments で凌ぐか call とか apply 呼び出しをする関数をクッションしてやるとかします。
    後者の場合はダックタイピング的な感じでやっちゃえばいいですね :)
    




  • Enum
  • JavaScriptにはない。ただ、配列で疑似的なものは作れます。


var DIRECTION = {
    NORTH : 1,
    SOUTH : 2,
    WEST : 3,
    EAST : 4
};
  • アクセス修飾子
  • JavaScriptにはない。get/setキーワードとクロージャで頑張るぐらい。
  • Getter/Setter
  • getキーワードとsetキーワードがあります
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/get
https://developer.mozilla.org/ja/docs/JavaScript/Reference/Operators/set

※サポートされていない場合 (特にIE6-8において) 、スクリプトはシンタックスエラーを引き起こします。


  • リフレクション
  • 関数オブジェクトの受け渡しが出来るのであまり使うことは無いと思います。
    ただ、やるとすれば、evalとargumentsなどを使うとそれらしいことは出来ます。
    ※ECMAScript 6ではReflectやProxy Handlerというものが実験段階ですが考案されています。

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Reflect https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Proxy/handler

  • lamdaとか

  • 現状無いです。ECMAScript 6でアロー関数っていうのが提供されるかもしれないみたいですね。

  • mapとかfilterとか

  • ECMAScript 5からはあります。ECMAScript 6からはアロー関数が入ってさらに書きやすそうですね。

// ES 5
[1, 2, 3].map(function (i) { return i * i });
 // ES 6
[for (i of [1, 2, 3]) i * i];
// ES 5
[1,4,2,3,-8].filter(function(i) { return i < 3 });
// ES 6
[for (i of [1,4,2,3,-8]) if (i < 3) i];
(https://www.xenophy.com/javascript/8447より引用)


    2015/06/07追記


    >map/filter に関しては現状 underscore or lo-dash を使うのがモダンでないブラウザにも対応していてベター感あります。


    おおぉ、こんなものが。ECMAScript5な現状ではこれが良さそうですね。いい情報もらった。

    lodash
    prototype JavaScript Framework



  • Javadocのようなもの

  • JSDoc,YUIdoc,docco,doxx,とかいうものがあるらしいです。
    Javaエンジニアなら断然JSDocが環境構築、記法的に楽な気がします。

    http://qiita.com/opengl-8080/items/a36679f7926f4cac0a81






Javaの人からみたJavaScriptというテーマで今回は考えてみました。
見てみると色々便利そうですよね。

プロトタイプチェーンとクロージャ、
関数渡しなどを使えば柔軟なプログラミングが出来る
シンプルな言語です。

ほとんどJavaScriptの基礎的な部分の紹介に費やしてしまった。
Javaエンジニア向けとして書けたのは「Javaのアレどうやるの?」
の部分ぐらいですかね。
もっとジャヴァジャヴァさせたかったのになぁ。。


それと型システムや静的・動的型付けなどについても
調査及び言及できればと思ってたのですが、
それはまた今度ってことで(^^;
あと、jsライブラリの話もしたかったなぁ。。



結論としては、
・グローバルオブジェクト
・グローバル関数
・オブジェクトの種類
・funtionの使い方
を覚えればそんなに難しいものではない!!

(もちろん、言語の世界は広く、どれもこれも極めるのはムズいですけどね。)

5 件のコメント:

あやぴー さんのコメント...

幾つか気になったので。
想定が分からないですけど FireFox と firebugs (そうでなくても最近のモダンなブラウザのコンソール)ならループ使って回さなくてもオブジェクトの中身を参照できます。
あと、 console.dir とか使うとわざわざループ使わなくても key, value の組み合わせで表示してくれます。
console.log 以外にも沢山ログ出力用関数が用意されています。
https://developer.mozilla.org/ja/docs/Tools/Web_Console

それと for - in だとプロトタイプの親の値まで巻き込むので推奨されてないか / hasOwnProperty を一緒に使うのが定石です。
var objA = { a: 1, b: 2 };
var objB = Object.create(objA);
objB.c = 3;

for(x in objB){
console.log(x);
} // c, a, b

for(x in objB){
if(objB.hasOwnProperty(x)){
console.log(x);
}
} // c

あるいは次のように書くのがベターそうです。
var m = {a: 1, b: 2};
Object.keys(m).forEach(
k => console.log(k + ", " + m[k]));

JSON は確かに ES5 ですけど IE8 だと使えるとかあるので、この辺参照した方がいいと思います。
http://kangax.github.io/compat-table/es5/

関数( function )についてもこれは明確に違いがあるのでこの辺参照。主に巻上げが起こるか否かですね。
http://bonsaiden.github.io/JavaScript-Garden/ja/#function.general

匿名関数は lambda でしょうね。

equal と strict equal の違いは知っておいた方がいいですが、ほとんどの場合でその違いを意識せずに strict equal を使っていいというのは◎です。

オーバーライドの例は危険だと思っていて、その例だと「オブジェクト」に対してなので全てのオブジェクトのメソッドを上書きするわけではないので注意ですね(あと、あんまやんないです(笑))。

オーバーロードはふたつパターンがあると思います。引数の数違いと変数の型違い。
前者は arguments で凌ぐか call とか apply 呼び出しをする関数をクッションしてやるとかします。
後者の場合はダックタイピング的な感じでやっちゃえばいいですね :)

get/set に触れるならついでに defineProperty 周りも知っておくといい気がします。あまり積極的に使っている例は見たことない気がしますが…。

アロー演算子は根本的に匿名関数のシンタックスシュガーだと捉えてよかったと思うので、 lambda と言えば lambda ですけど、それを lambda と言うなら匿名関数は lambda でいいと思います(少なくとも JS 界隈だと匿名関数 ≒ lambda だと思われている気が)。

map/filter に関しては現状 underscore or lo-dash を使うのがモダンでないブラウザにも対応していてベター感あります。

長々と失礼しました :P

yy_yank(やんく) さんのコメント...

>あやぴーさん

色々ひどくてすみません笑


> FireFox と firebugs (そうでなくても最近のモダンなブラウザのコンソール)ならループ使って回さなくてもオブジェクトの中身を参照できます
確かにわざわざログとして出力するほどでもないですね(><)

> console.dir とか使うとわざわざループ使わなくても key, value の組み合わせで表示してくれます
>console.log 以外にも沢山ログ出力用関数が用意されています
>https://developer.mozilla.org/ja/docs/Tools/Web_Console

console.dir…!存在は知ってはいたのですが、全然ピンときてませんでした。なるほど!

>それと for - in だとプロトタイプの親の値まで巻き込むので推奨されてないか / hasOwnProperty を一緒に使うのが定石です。

なるほど、親含めて全部出力しちゃいますね。そのセオリー全然知らなかったんで勉強になりました。

>Object.keys(m).forEach(
>k => console.log(k + ", " + m[k]));

ES5からなんですかね?色々便利になってますねー。

>JSON は確かに ES5 ですけど IE8 だと使えるとかあるので、この辺参照した方がいいと思います。
>http://kangax.github.io/compat-table/es5/

あ、そうですね。ブラウザのバージョンによってはというのは
全然説明不足でしたね(^^;

>関数( function )についてもこれは明確に違いがあるのでこの辺参照。主に巻上げが起こるか否かですね。
>http://bonsaiden.github.io/JavaScript-Garden/ja/#function.general

うぅ、functionの説明になってませんでしたね。。。

>オーバーライドの例は危険だと思っていて、その例だと「オブジェクト」に対してなので全てのオブジェクトのメソッドを上書きするわけではないので注意ですね(あと、あんまやんないです(笑))。

あ、確かに笑
プロトタイプを意識したJavaScriptって今までそこまで触れてきていなくて、
もっと勉強したいところではあります!

>オーバーロードはふたつパターンがあると思います。引数の数違いと変数の型違い。
>前者は arguments で凌ぐか call とか apply 呼び出しをする関数をクッションしてやるとかします。
>後者の場合はダックタイピング的な感じでやっちゃえばいいですね :)

はい、これに関しては頭の中では分かっていたというかアバウトな認識はありました。
が、それを書く技量がなかったです。すみません(><)


>get/set に触れるならついでに defineProperty 周りも知っておくといい気がします。

definePropertyなんてものがあるんですねー!

>map/filter に関しては現状 underscore or lo-dash を使うのがモダンでないブラウザにも対応していてベター感あります。

なるほどー!そうなんですね。便利そうですね、覚えておきます!

あやぴー さんのコメント...

Object.keys(m).forEach(k => console.log(k + ", " + m[k]));
これは ES6 から使えるアローを使っているので、そこだけ function で書き直せば ES5 でいけますね。

さらにどうでもいいですが、 for-in は Array に対しても使うことが出来ますが、これはプロパティを巻き込むという別の理由があるのでやっちゃいけないことです。
他にもハマりどころが沢山あるので下記のドキュメントは全部目を通しておくといいかと思います。
http://bonsaiden.github.io/JavaScript-Garden/ja/

ES6 が出るとまた状況も変わると思いますが、現状は Babel とか使わないと ES6 なコードあまり書けないの(結局ブラウザの対応がまばらだし ES5 に全部倒すのが安全なので Babel みたいなトランスパイラが必要ぽい)でパーフェクト JavaScript あたりを読みましょう :)

あと、関数のところらへんで高階関数とかに触れておくといいのかなーというか、 JS ってやっぱり関数を返す関数とか関数を引数に取るとかそういうのがあるから楽しいので( Lisp 脳)その辺も是非勉強して Lisper になってください(違

匿名 さんのコメント...

グローバルオブジェクトについてですが
Array
Boolean
Date
Function
Iterator ←Fx独自
Number
Object
RegExp
String
Proxy ←ES6
ParallelArray ←Fx独自&廃止
+
Symbol,Mapやらなんやら ←ES6
JSON ←ES仕様からは分離されたが基本的にES5に付随するもの
Intl ←ES仕様からは分離されたが基本的にES6に付随するもの
グローバルのparseIntなど数学系関数 → ES6でNumber下に改良されたものが新設されそちらを推奨
uneval ←Fx独自
オブジェクトのkeyの列挙 → ES5のObject.keysが推奨

yy_yank(やんく) さんのコメント...

>匿名さん

色々ご指摘ありがとうございますー!(><)
いやぁ、全然そのあたり整理できていませんでした。
整理して学び直そうと思います!

そして、この記事にまとめられそうであれば分かる形で追記します…。