twitterこの広告は、90日以上更新していないブログに表示しています。JavaScriptで簡単に構築することを目的としたUIライブラリです(UIフレームワークともたまに呼ばれます)。↓みたいなネイティブなモバイルアプリっぽい画面をサクッと作ることができます。UIの設計開発を行っています。UIに求められるUIライブラリとしての要件とそれを解決するためにどのようなアーキテクチャを取っているのかについて解説します。UIは開発されています。ある特定のフレームワークに依存したUIライブラリを作ると、その他のフレームワークから使ったり素のJavaScriptから使うことが困難になります。AngularJSに依存したUIコンポーネントは他のフレームワークから利用することは基本的にできなくなります。技術的にはできなくも無いでしょうが、それをわざわざやりたいと思う開発者はおそらくいないでしょう。UIライブラリの提供者側にとっても特定のフレームワークに依存するのはリスクがあります。その依存しているフレームワークが使われなくなった場合に、UIライブラリを書き直すことになる可能性があります。UIの1系はAngularJSのdirectiveとして実装されていたので、AngularJSと互換性の無いAngular2が登場した時にdirectiveとして実装されていたすべてのUIコンポーネントを書き直したことがありました。UIでは、特定のフレームワーク依存せず、かつどのフレームワークからでもある程度利用できるように次のような構成を取っています。UIが提供する最もレベルの低いコンポーネント層です。これは主にすべてのUIコンポーネントの見た目を提供します。Componentsという名前のとおり、CSSファイルとして提供されます。ComponentsにJavaScriptで振る舞いを与えます。Elementsを使っているので、素のJavaScriptからでも、フレームワークからでも同じように扱えるように設計されています。Bindings層では、各種フレームワーク用のバインディングを記述します。React.js,とVue2用のバインディングが記述されています。Componentsとして実装されています。CSSだけで実装できるもの、すなわちコンポーネントの見た目はここで実装されています。ComponentsはAdobe製の高速CSSフレームワークであるTopcoatをフォークして開発されたものです。CSSメタ言語としてStylus、CSSコンポーネントのドキュメントの記述にはtopdoc、設計規約としては高速なCSSセレクタを記述することができるBEM+MindBEMdingを採用しています。Components層が提供するCSSのみを使うこともできます。UIのリポジトリのCSSファイルを読み込んで、swtichコンポーネントのタグを記述するとiOSでよく見るSwitchのUIが表示されます。</div></label>リポジトリ的には次の場所に全て記述されています。Components層です。CSSで記述された見た目に対してJavaScriptで振る舞いを追加します。ElementsのAPIを使ってCSSコンポーネントに振る舞いを追加するカスタム要素を定義しています。ドキュメントを見ると現在は約40程度のカスタム要素が定義されています。Elementsを被せたものです。Elementsとして実装すると、そのDOM要素のプロパティやメソッドや属性などの振る舞いを定義することができます。これを使って素のJavaScriptやjQueryなどからでも扱える、かつAngular2やReact.jsやVue.jsなどのフレームワークからでも扱えるコンポーネントを定義することができます。リポジトリ的には次の場所に全て記述されています。Elements以外にも各種JavaScriptのAPIも提供しているのでこの部分をひっくるめてcoreとも呼ばれます。UIのonsenui.jsとonsenui.cssはこのcoreから生成されます。Bindings層この層では、各フレームワークごとのラッパーを定義しています。UIではバインディングと呼ばれています。Vue.jsなどがあります。jQueryや素のJSから利用する場合には、このバインディングは利用しません。開発者は、利用するフレームワークに合わせてこのバインディングも利用します。Componentsを提供していたとしても、そのカスタム要素のプロパティやメソッドにアクセスできなければ意味がありません。各フレームワークごとにコンポーネントの操作をどのように行うかについても流儀が異なります。Elementsが持つメソッドに依る操作をReact.jsのコンポーネントのpropsやstateによって管理する必要があります。AngularJSやAnglar2の場合にはDOM要素が持つメソッドをDirectiveから叩けるようにする必要があります。Bindings層ではこのフレームワークごとに異なる流儀を吸収しながら、カスタム要素に対するインターフェイスを提供しています。フレームワークによってどういうふうに書き方が変わるかというのは次の公式ブログの記事にも書かれています。World!リポジトリ的には次の場所に全て記述されています。bindingsディレクトリ以下にフレームワークごとのnpmパッケージが提供されています。Elementsを使っています。その際のUIライブラリとしての大まかなアーキテクチャについてこの記事では説明しました。読者になる広告を非表示にする2016-06-28「PHPに型推論を実装する〜入門編〜」という題でPHPカンファレンス福岡2016で話してきたPHPカンファレンス福岡2016で型推論器ってどんな感じなのという話をしました。PHPカンファレンス福岡は去年も登壇したんですが今年は弊社もスポンサードしつつの登壇です。参加者や運営スタッフの皆さんの対応含めて心地良い雰囲気だったので、ああ参加して良かったなと自然と思えるような素晴らしいイベントでした。読者になる広告を非表示にする2016-04-17JavaScript(ES2015)でvarやletを使う必要はほぼ無いES2015でvarやletを使う場面はほとんど無いので、まずconstを使う。constだとダメな場合にはletを使う。背景ES2015では、変数を宣言するための文法としてconstとletが導入された。'bar';constは再代入できない変数を宣言できる。letは再代入できる変数を宣言できる。OKあれ、じゃあvarとletは同じなの?っていうとそうではなく、letやconstはvarとは違って、関数スコープよりも細かなブロック単位のスコープを提供する。constやletを使うと、if文やfor文などのブロック中でのみ有効な変数を宣言できる。プロジェクトにES2015を導入すると、「お、varじゃなくてlet使えばええんやな!」と言わんばかりにletだけを使う人を見かけるんだけど、実際にはletもほとんど使う必要なくて、多くの場合はconstで問題ない。他人が書いたソースコードの中でletを見ると、「これ後で再代入されるん?」って一瞬身構えるので、再代入の必要がないならconstを使う方が可読性も良くなる。ES2015になって変数の文法が増えたわけだけど、開発者はまずconstを使って、再代入が必要ならletを使って、letも使えない特殊な事情がある場合のみvarを使う、というようにするといい。varは別に非推奨になったわけではないので普通に使えるんだけど、プロジェクトで機械的にvarを使わせたくない場合には、ESLintでno-varを有効にする。(no-var)Airbnbが公開しているES6に対応したJavaScriptコーディング規約においても、まずconstを使うこと、varは避けることが書かれている。調べてみると、ESLintには再代入しないletに警告を出すprefer-constがあった。厳格にしたい場合はこのprefer-constを有効にする。(prefer-const)まとめES2015では、varやletを使う必要のある場面はそれほどない。変数の宣言にはconstを使う。再代入が必要な場合にのみlet使う。読者になる広告を非表示にする2016-03-16factorでズンドコキヨシを書いてみた連鎖性言語のfactorで今流行り(?)のズンドコキヨシ書いてみた。連鎖性言語って何?っていう方はここの説明を見てほしい。zundoko.factorズンドコドコズンズンズンズンドコキ・ヨ・シ!昔触ってたfactorのこと完全に忘れててこれ書くのになんやかんやで1時間ぐらいかかったけど、たまにfactor書くとやっぱ面白い。最近の連鎖性言語をちょろっと調べてみたら、今はkittenというイケてる感じの関数型連鎖性言語も登場してるみたい。暇があったらまたこういうの触っていきたい。Layoutについて2015年にもなるのにJavaScriptでのDOM操作のパフォーマンスについて書く。ウェブページにインタラクションを持たせたい時に、JavaScriptでDOM操作を行うことがよくある。このDOM操作のパフォーマンスについて、よく聞く意見を大別すると次の2つがある。JavaScriptによるDOM操作は重たいレンダリングが重いだけで、DOM操作そのものはそれほど重たくないJavaScriptでオブジェクトのプロパティを操作したりする単体の処理は通常1ミリ秒もかからないが、DOM操作をするとレンダリングが完了するまでに数十ミリ秒程度かかったりする場合がある。1番目のDOM操作が重たいと言っている人は経験則的にそう言っていることが多い。レンダリングの仕組みを知っている人は2番目の意見を言うが、重箱の隅をつつくような話をするとこれも必ずしも正しいわけではない。DOM操作するコードによっては、JavaScriptの実行そのものをブロックするケースもあるからだ。この記事ではその辺りの事情についておさらい的に説明する。DOM操作するとそもそも何が起こるのか現在見ているウェブページのドキュメントのDOMツリーに属するDOM要素を操作をすると、JavaScriptの実行が終わってからブラウザのレンダリング処理が行われる。具体的にはWebkit系のレンダリングエンジンだと次の図のようになる。ScriptingではJavaScriptの実行が行われる。DOM操作の処理もここに含まれる。Styleでは、更新されたDOM要素ごとのスタイルが再計算される。DOM要素を生成してDOMツリーに追加すると、その影響で当たるスタイルを更新しないといけない要素が出てくるので、それらのDOM要素に当たるスタイルがCSSセレクタのマッチング処理とともに再計算される。Layoutでは、計算されたDOM要素のスタイルを元に要素のレイアウトの計算を行う。いわゆるリフローと呼ばれるものはこれ。Firefoxだとリフローと呼ばれる。Paintでは要素をレイヤごとにラスタライズする。Layersではラスタライズした各レイヤを1枚に合成して最終的なレンダリング結果を生成する。HTML5アプリでのインタラクションやアニメーションのレンダリングのパフォーマンス改善というのは、このDOM操作した後のこの一連の実行パスをどのようにして最適化するかという話である。Layersだけが実行されるようなコードを記述したりする。DOM操作に伴うレンダリングの処理は、JavaScriptの実行そのものを遅くするわけではないので、そういう意味では後続するレンダリングが重いだけでDOM操作そのものは大して重くない、というのはおおむね正解である。実際ドキュメントのDOMツリーに属していないDOM要素を操作してもこれらのレンダリング処理は行われない。Layoutを引き起こして、JavaScriptの実行そのものをブロックする場合がある。Layoutとは、JavaScriptと同期する形で実行されるレイアウト計算処理のことである。通常このレイアウト計算は、JavaScriptの実行が終わってから初めて行われるので、JavaScriptの実行を遅くしたりするわけではない。LayoutではJavaScriptの実行中に同期的に処理されるので、JavaScriptの実行パフォーマンスを劣化させることがある。APIにはレイアウト情報を参照するメソッドやプロパティがいくつかある。具体的には、offsetHeightプロパティやoffsetWidthプロパティやgetBoundingClientRect()メソッド等がある。Layoutは、ドキュメントのDOMツリー内でDOM操作を行った後、そのDOM要素のレイアウト情報を参照するコードを書くと起こる。DOM要素を生成してbody要素に追加する次のようなコードを見てみよう。'hogehoge';document.body.appendChild(div);このコードでは、JavaScriptの実行が終わってから初めてレイアウト計算が行われる。Layoutが発生する。console.log(div.offsetHeight);Webkitなどのレンダリングエンジンでは、JavaScriptによるDOM操作が行われてもすぐにレイアウト計算を行うのではなくJavaScriptの実行が一旦終わってから行うが、DOM操作を行った後にgetBoundingClientRect()やoffsetHeightなどのプロパティを参照すると、正しいレイアウト情報を返すためにレンダリングエンジンはその場でレイアウト計算を行う。Layoutが起こっているかどうかは、ChromeのウェブインスペクタのTimelineでプロファイルを取ればわかる。Layoutを引き起こすと、JavaScript実行中にレイアウト計算が何度も繰り返し起こるのでJavaScriptのパフォーマンスが大幅に劣化する事がある。まとめJavaScriptでのDOM操作自体は大して重くない。重く見えるのはDOM操作に伴うレンダリング処理がJavaScriptの実行後に行われるからである。Layoutを引き起こす場合にはJavaScriptの実行パフォーマンスを劣化させる原因になる。#phpconfuk6/27に開催されたPHPカンファレンス福岡2015で「PHPで学ぶ仮想マシン型正規表現エンジンの仕組み」という題で発表してきました。正規表現エンジンの実装は、大別するとDFA型とVM型の二種類あるのですが、今回のこの発表ではVM型の仕組みについて解説しました。Approachという記事です。この記事を読んで、こんなに単純な仕組みで正規表現エンジンって実装できるのか!とちょっとした衝撃を受けて、その感動を伝えられればということで今回話しました。時間が足りず最後の方が早足になってしまって当日会場で話を聞いていた人にはわかりづらくなってしまいましたが、資料を一度ゆっくり見てもらえば多分理解できると思います。PHPで学ぶ〜とか言いつつスライドにはPHPのコードは一行たりとも出てきませんが、スライド中で紹介している自分の記事の中ではPHPを使ってVMの実装をしています。発表資料は以下になります。セッションに参加していただいた皆さんありがとうございました。@localdiskさんお疲れ様でした。読者になる広告を非表示にする2015-05-05JavaScriptをプロトタイプベースのオブジェクト指向言語と言うべきではない勘違いしている方も結構多いと思ったので、これの解説。3ウェブ上の記事を眺めていると、JavaScriptをプロトタイプベースのオブジェクト指向言語(以下OOPと書く)と説明している例がよく散見される。この書き方は間違ってはいないかもしれないが、もはや誤解を生むだけである。言う理由には、ES6からはclass構文があるため、通常のクラスベースのOOPと一切何も変わらなくなっているからというのがある。大きな理由は、JavaScriptはプロトタイプベースのOOPの中でも異端であり、本来のプロトタイプベースのOOPとはあまり似ていないからである。JavaScriptでは、new演算子を使ってオブジェクトを生成したり、prototypeオブジェクトを使ってオブジェクトのメソッドやプロパティを定義したりするが、他のプロトタイプベースのOOPではnew演算子は無いし、prototypeオブジェクトも無い。この記事では、本来のプロトタイプベースのOOPがどういったものであり、JavaScriptとはどう違うのかを説明する。JavaScriptの確認まずは、JavaScriptでオブジェクトを定義・生成する方法を確認していく。コンストラクタとして、まずは関数を定義する。name;};次に、定義した関数オブジェクトのprototypeプロパティにプロパティを定義することで、オブジェクトがインスタンス化された時のプロパティやメソッドを定義できる。}};オブジェクトをインスタンス化する際には、new演算子を使って生成する。JavaScript'が返るさて、プロトタイプベースのOOPではこういったオブジェクトの定義や生成はどうやって行うのか。プロトタイプベースのOOPでは?純粋なプロトタイプベースのOOPでは、クラスやJavaScriptのprototypeオブジェクトのようなものは無い。新しいオブジェクトを作るには、new演算子によるインスタンス化ではなくオブジェクトの複製を作ることで自分が欲しいオブジェクトを作成していく。ここでは、プロトタイプベースのOOPの例として、ioという言語で説明する。ioは純粋なプロトタイプベースのOOPだ。ioには制御構文用の文法が無く全てが(if文ですらも)メソッドである。先ほどJavaScriptで書いたようなMyObjectをioで作ったのが以下だ。Name"ioの文法のほんの少し説明すると、:=演算子は変数を宣言する演算子である。JavaScriptではオブジェクトのプロパティのアクセスに"."演算子を使うが、ioでは単にスペースを使う*1。引数がない場合にはメソッド呼び出しに()は不要だ。printメソッドの呼び出し先ほどの例では、MyObjectというオブジェクトを作っているが、重要なことはこのMyObjectはすでに利用できる一個のオブジェクトだということだ。ここでcreateGreetingメソッドを呼び出せばそれはそのまま動作する。JavaScriptではこうはいかない。返るioでは新しくオブジェクトを作るときには、クラスをインスタンス化してオブジェクトを生成する代わりに、すでにあるオブジェクトを複製することでオブジェクトを生成する。返るさて、ioのやり方を見るとJavaScriptとはだいぶ違うことがわかる。ioなどのプロトタイプベースのOOPではオブジェクトの定義や継承や生成などの処理を全てcloneを通じて行えるので非常にシンプルだ。それに比べるとJavaScriptのprototypeオブジェクトを使うやり方は何かちぐはぐな印象を与えてくる。GoFのデザインパターンの一つにオブジェクトの生成に関わるプロトタイプパターンというのがあるが、プロトタイプベースのOOPではこのデザインパターンを言語の設計レベルで全面的に採用することでnew演算子やクラスの存在を消してしまっている。JavaScriptでは、プロトタイプ(ひな形)となるオブジェクトは関数オブジェクトのprototypeプロパティに代入したオブジェクトになるが、これは通常のオブジェクトとしてそのまま利用できるわけではないし、これはある意味クラスを表現するクラスオブジェクトのような形になっている。ioではそういったオブジェクトは無くプロトタイプ(ひな形)となるのはそのオブジェクト自身である。ioではオブジェクトの複製を通じてのみ新しいオブジェクトを生成できる。やって書いてみると、JavaScriptが通常のプロトタイプベースのOOPとどれほどかけ離れているかがわかる。JavaScriptはクラスを持たないためプロトタイプベースのOOPとして分類できるのかもしれないが、その仕組みを観察してみると、クラスベースとプロトタイプベースの合いの子のような妙な形になっている。終わりに個人的な意見になるが、JavaScriptをプロトタイプベースのOOPと言い切っている人は、プロトタイプベースのOOPがどういったものかを理解していない、もしくはioやSelfのような言語を触ったことがない人だろう。JavaScriptは何の留保も無しにプロトタイプベースと言い切るにはあまりに奇妙だからだ。何にせよ、ES6からはclass構文が追加されたので、JavaScriptをプロトタイプベースのOOPと言うのはもはや適切ではないだろう。jsをクラスベースと呼ぶ方が無理があるhttp://b.hatena.ne.jp/entry/249961310/comment/otherworldこの記事では、JavaScriptをクラスベースのOOPと呼ぶべきという主張をしているわけではないです。プロトタイプベースの、という枕詞を付けても説明として何の意味もないという話です。ブログを報告する引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。