だれも聞いていないと思って歌え

dance as if no one’s watching, sing as if no one’s listening, and live everyday as if it were your last.

技術書の歩き方勉強会「達人プログラマー」編 に行ってきました

11月21日にSpeeさんで開催された技術書の歩き方「達人プログラマー」編に行ってきました。

『達人プログラマー』とは

原著『Pragmatic Programmer, The: From Journeyman to Master』は1999年に出版され、日本では2000年に翻訳されて出版されました。
しばらく絶版となっていたそうですが、今年の10月25日にオーム社から復刊されました。

この本は、ソフトウェア開発の名著として紹介されていることがあるため、タイトルは知っていました。

企画について

以下、connpassからの引用です。

概要

オーム社さんから復刊された『新装版 達人プログラマー 職人から名匠への道』を勝手に応援する企画です。 古典である『達人プログラマー』を今の私たちはどう読んだらいいか、なにを受け取れるか、自分の仕事/キャリアにどう活かしていけるのかといったことについて、お話しする場にできればと思っています。

こんな方におすすめ

プログラマ・ソフトウェア開発者として成長の手引きが欲しいなと感じている方 会社の先輩などから技術書の古典を「読んどけ」と渡されるけれど、うまく読めなくて困っている方 『達人プログラマー』、なんとなく気になっているけれど手を出せていない方 『達人プログラマー』の復刊を応援/お祝いしたい方

『達人プログラマー』というタイトルは知っていても、古典であるというイメージと、初心者が読んでも理解できなさそう・難しそうという思いから手を出せていませんでした。
また、「プログラマ・ソフトウェア開発者として成長の手引きが欲しいなと感じている方」に当てはまったため参加を決めました。

続きを読む

配列の操作(forEach,map,filter,find,some,every)について

何となくで使うのではなく、しっかりと理解しようと思い改めて整理しました。

Array.prototype.forEach()

forEach は、全ての要素に対して関数を一度ずつ実行する。
mapfilter とは異なり新しい配列は生成しない。

// 配列の要素の合計を計算する
let sum = 0;
const list = [10, 20, 30, 40];
list.forEach(param => {
  sum += param;
});

console.log(sum);
> 100

Array.prototype.forEach() - JavaScript | MDN

Array.prototype.map()

map は、全ての要素に対して関数を一度ずつ実行し、返り値(return)からなる新しい配列を生成する。
filter とは異なり、実行対象となる配列の数(before)と、新たに生成された配列の数(after)は変わらない。
また、生成された配列の値には関数実行時の返り値(return)が格納される。

// 配列の全ての要素に10を乗算した配列を返す
const before = [10, 20, 30, 40];
const after = before.map(param => {
  return param * 10;
});

console.log(before);
> [10, 20, 30, 40]
console.log(after);
> [100, 200, 300, 400]

Array.prototype.map() - JavaScript | MDN

Array.prototype.filter()

filter は、全ての要素に対して関数を一度ずつ実行し、戻り値(return)で true を返した要素からなる新しい配列を生成する。
map とは異なり true を返した要素のみの配列を返し、生成された配列の値には実行時の要素の値が格納される。

// 配列の要素が20で割り切れるものだけを抽出する
const before = [10, 20, 30, 40];
const after = before.filter(param => {
  return ((param % 20) === 0);
});

console.log(after);
> [20, 40]

Array.prototype.filter() - JavaScript | MDN

Array.prototype.find()

find は、 true を返す要素が見つかるまで、要素に対して一度ずつ関数を実行する。
true を返した要素の値を返す。

// 配列の要素が20で割り切れるものだけを抽出する
const before = [10, 20, 30, 40];
const after = before.filter(param => {
  return ((param % 20) === 0);
});

console.log(after);
> 20

Array.prototype.find() - JavaScript | MDN

Array.prototype.some()

some は、 true を返す要素が見つかるまで、要素に対して一度ずつ関数を実行する。
true を返す要素が見つかると、 true を返す。

// 要素に一つでも20以上の値があればtrueを返す
const list = [10, 20, 30, 40];
const retVal = list.some(param => {
 console.log(param);
 return (param >= 20);
});
> 10
> 20

console.log(retVal);
> true

Array.prototype.some() - JavaScript | MDN

Array.prototype.every()

every は、false を返す要素が見つかるまで、要素に対して一度ずつ関数を実行する。
false を返す要素が見つかると、 false を返す。

// 要素に一つでも20以下の値があればfalseを返す
const list = [40, 30, 20, 10];
const retVal = list.every(param => {
 console.log(param);
 return (param > 20);
});
> 40
> 30
> 20

console.log(retVal);
> false

Array.prototype.every() - JavaScript | MDN

スプレッド演算子(spread operator)について

上記では配列に対しての操作を例に出しましたが、スプレッド演算子を使うことで配列以外のオブジェクトも同様に処理することが可能となります。

例えば、下記のようなHTML文書のリスト要素からテキストのみの配列を作成しようとする場合はこのようになります。

<div class="sample">
  <ul>
    <li>list1</li>
    <li>list2</li>
    <li>list3</li>
  </ul>
</div>
const elms = document.querySelectorAll('.sample li');
const retVal = [...elms].map(elm => {
 return elm.textContent;
});

console.log(retVal);
> ["list1", "list2", "list3"]

詳しい使い方は Mozilla Developer Network を参照してください。

document.querySelector と document.querySelectorAll について

仕事でよく使っているけど、ちゃんと理解できていなかったので改めて調べてみました。

document.querySelector と document.querySelectorAll

document.querySelectordocument.querySelectorAll とは W3C によって定義された Selectors API の仕様です。 jQuery のようにセレクターを指定して、要素を取得できるメソッドです。

  • document.querySelector … 指定された CSS セレクタにマッチする文書中の最初の要素を返す。
  • document.querySelectorAll … 指定された CSS セレクタにマッチする文書中の要素の全てのリストを返す。

また、同様に文書中の要素を取得するメソッドとして下記があります。

  • document.getElementById … 指定されたIDを持つ要素を返す。
  • document.getElementsByClassName … 指定されたクラス名を持つ要素のリストを返す。

下記のHTML文書を例に、これらの違いについてまとめます。

<div class="news-box">
  <h2>NEWS</h2>
  <ul>
    <li class="news">news title 1</li>
    <li>topic title 2</li>
    <li class="news">news title 3</li>
  </ul>
</div>
<div class="articles-box">
  <h2>ARTICLES</h2>
  <ul>
    <li class="article">article list 1</li>
    <li>article list 2</li>
  </ul>
</div>

要素を一件だけ取得する

NEWSのnewsクラスではないリストの先頭の取得する場合、以下は同じ結果を取得することができます。 document.querySelector を使わない場合、一行で書く方法が分かりませんでした・・・

const elements = document.getElementsByClassName('news-box')[0].getElementsByTagName('li');
let elm = [];
for(var i = 0; i < elements.length; i++) {
  if(elements[i].className !== 'news') {
    elm.push(elements[i]);
  }
}
const element = elm[0];

> <li class="news">news title 1</li>
document.querySelector('.news-box li:not(.news)');

> <li class="news">news title 1</li>

ただし、単発のIDセレクタを指定する場合は document.getElementById の方が高速になります。

要素のリストを取得する

NEWSのnewsクラスのリストを取得する場合、以下は同じ結果を取得することができます。

document.getElementsByClassName('news-box')[0].getElementsByClassName('news');

> [<li class=​"news">​news title 1​</li>​, <li class=​"news">​news title 3​</li>​]
document.querySelectorAll('.news-box .news');

> [<li class=​"news">​news title 1​</li>​, <li class=​"news">​news title 3​</li>​]

こちらも、単発のクラス名を指定する場合は document.getElementsByClassName の方が高速になります。

引数に配列を指定する

ちなみに、引数には配列が指定可能で、 NEWSのnewsクラスのリスト と ARTICLESのarticleクラスのリスト のみを取得することができます。

document.querySelectorAll(['.news-box li.news', '.articles-box li:article']);

> [<li class=​"news">​news title 1​</li>​, <li class=​"news">​news title 3​</li>​, <li class=​"article">​article list 1​</li>​]

CSS セレクタ

これを知っておくと便利だなと思ったものについてまとめました。

:not()

上記例で使っていますが、引数で指定したセレクターの要素を除外します。

document.querySelectorAll('.news-box li:not(.news)');

> [<li>​topic title 2​</li>​]

:first-child, :last-child

:first-child では最初の子要素を取得します。

document.querySelectorAll('.news-box li:first-child');

> [<li class=​"news">​news title 1​</li>​]

ただし、 document.querySelectorAll('.news-box li:not(.news):first-child')擬似クラスを複数組み合わせて使用することはできません(後述します。)

:last-child は最後の子要素を取得できます。

document.querySelectorAll('.news-box li:last-child');

> [<li class=​"news">​news title 3​</li>​]

:nth-child(), :nth-last-child()

引数には子要素のn番目、偶数(even)、奇数(odd)などが指定可能です。

document.querySelectorAll('.news-box li:nth-child(odd)');

> [<li class=​"news">​news title 1​</li>​, <li class=​"news">​news title 3​</li>​]

:nth-last-child() も同様に、最後の子要素から逆向きに数えてn番目、偶数(even)、奇数(odd)と指定できます。

擬似クラスを複数組み合わせる

上にあげた例と同じになりますが、NEWSのnewsクラスを除外したリストの先頭を取得しようと以下のように記述します。

document.querySelectorAll('.news-box li:not(.news):first-child');

> []

しかし、取得対象の :first-child が除外対象の .news であるため空の配列が返ってきます。 :nth-child() を使うか document.querySelector で先頭の一件のみ取得する必要があります。

また、下記のように :not() を複数繋げて使用することも可能です。

document.querySelectorAll('li:not(.news):not(.article)');

> [<li>​topic title 2​</li>​, <li>​article list 2</li>​]

JavaScript勉強中です。 間違いありましたら指摘お願いします。

参考

Moment.jsで日付を扱う

とあるWebアプリを作ろうとしている中で、JavaScriptでもっと日付を楽に扱いたいと調べていて、 Moment.js というライブラリを知りました。

このMoment.jsについて紹介しているサイトは以前からあるので、最近できたものではないです。 比較的最近の Cybozuさんの記事 を読んだのをきっかけに使ってみることにしました。

現在の日付を扱う

Moment.js を参考にダウンロード、もしくはインストールをしてscriptタグで moment.min.js を読み込みます。

// momentオブジェクトの初期化
var today = moment();

// 日付の出力
console.log(today.format());    // -> 2016-06-05T19:37:38+09:00

// フォーマットを指定して出力
console.log(today.format('LLLL'));  // -> Sunday, June 5, 2016 7:54 PM

// 年月日をそれぞれ出力
console.log("year: ", today.year());    // -> year:  2016
console.log("month: ", today.month());  // -> month:  5
console.log("date: ", today.date());    // -> date:  5

moment().month() は、0から11の数字で帰ってくるため6月の場合は 5 と返ってきます。

日本語で出力する

上の手順と同様に、次は moment-with-locales.min.js をscriptタグで読み込みます。 Dateオブジェクトと比較して、この出力フォーマットの指定方法が一番楽だと感じました。

// locale指定
moment.locale('ja');

// momentオブジェクトの初期化
var today = moment();

// フォーマットを指定して出力
console.log(today.format('LLLL'));  // -> 2016年6月5日午後7時54分 日曜日

特定の日付を設定

日付の設定方法はいくつかあります。 moment() と括弧内で指定を行わなかった場合は現在日時で初期化が行われ、逆に括弧内で年月のみ指定された場合は1日で初期が行われます。そのため、上2つと下2つの結果が異なってきます。

// locale指定
moment.locale('ja');

console.log(moment(new Date(2016, 6 -1)).format('LL'));    // -> 2016年6月1日
console.log(moment({year:2016, month:6 -1}).format('LL')); // -> 2016年6月1日
console.log(moment().year(2016).month(6 -1).format('LL')); // -> 2016年6月5日
console.log(moment().set('year',2016).set('month',6 -1).format('LL')); // -> 2016年6月5日

最後に

すべての使い方を把握した訳ではないけれど、便利そうだなと思ったものをいくつか。 これら以外にも多くの関数が用意されている上に、タイムゾーンを扱うこともできるようです(タイムゾーンについては今回触れなかったので省略)。

// locale指定
moment.locale('ja');

// 指定した年月の日数を取得
console.log(moment(new Date(2016, 2 -1)).daysInMonth());  // -> 29

// 1月1日からの経過日数を取得
console.log(moment(new Date(2016, 6 -1, 5)).dayOfYear());  // -> 157

// 1月1日からの何週目か取得
console.log(moment(new Date(2016, 6 -1, 5)).weeksInYear());  // -> 53

X-UA-Compatibleについて調べてみた

今更ながらBootstrapの勉強を始めました。現在最新のBootstrap3です(4はαリリースのため)。 公式サイトを参考にしていて、Basic templateに書かれているmetaタグが見慣れないものだったので、調べてみました。

<meta http-equiv="X-UA-Compatible" content="IE=edge">

Getting started · Bootstrap

http-equiv

Mozillaの開発者向けの解説ページによると次のように記載されています。

プラグマディレクティブ、つまりどのように Web ページを提供するかについて、通常 Web サーバから与えられる情報です。 meta 要素 - HTML | MDN

では、 X-UA-Compatible は何かというと、Internet Explorerでどのバージョンのモードでレンダリングを行うか(ドキュメントモード)を指定することができるプラグマです。 IE=edge と指定することで、使用しているIEで利用可能なモードの中から、最高のモードを使用するように指示ができます。Internet Explorer 8 の場合はIE8モードに相当し、Internet Explorer 10 の場合はIE10モードに相当します。

ただし、 Internet Explorer 11 以降ではドキュメントモードの指定は推奨されず、Microsoft Edge では無視されるようになっているそうです。

新しい記事ではないですが、 X-UA-Compatible が何かを理解するためにこちらも参考にしました。