JS クイズ
Q: 以下のテストをパスしてください
function assert(cond) { if (!cond) throw new Error("failed!!"); } // Foo と Bar は異なる assert(Foo !== Bar); // new Foo() は Foo / Bar のインスタンスである assert(new Foo() instanceof Foo); assert(new Foo() instanceof Bar); // new Bar() も Foo / Bar のインスタンスである assert(new Bar() instanceof Foo); assert(new Bar() instanceof Bar);
JavaScriptの小銭リテラルが便利
コンピュータプログラムのソースコードなどで、特定のデータ型による値を直接表記する際の書式。また、そのような書式に従って記載された値。
JavaScriptにも数値や文字列、オブジェクト、正規表現などのリテラル表現があるのだけど、意外と知られていないものに 小銭リテラル がある。小銭リテラルはその名のとおり小銭を表現する書式で仕様では以下のように定義されている。
KozeniLiteral :: DecimalIntegerLiteral KozeniParts(opt) KozeniParts :: KozeniPart KozeniParts KozeniPart KozeniPart :: KozeniDelimiter KozeniDigits KozeniDigits :: DecimalDigit DecimalDigit DecimalDigit KozeniDelimiter :: ,
使用例
変数(price)には小銭の部分だけが代入されるので余計な演算をすることなく小銭を取得できる。
var price = 1,234,567; // 小銭リテラル console.log("小銭は " + price + "円です"); // => 小銭は 567 円です
試しに数値リテラルで同じことをする例も載せるが複雑な演算子を必要としない小銭リテラルの方が明らかにシンプルで便利なのが分かると思う。
var price = 1234567; // 数値リテラル console.log("小銭は " + (price % 1000) + "円です"); // => 小銭は 567 円です
このように便利な小銭リテラルだけど、エッジすぎる機能なのか残念なことに現時点ではきちんと実装されておらず非常にバギーなので、実装が安定するまでは使うのを控えた方がよさそう。
var price = 1,234,067; // 小銭リテラル console.log("小銭は " + price + "円です"); // => 小銭は 55 円です (12円の損)
確認されているバグ的なやつ
- 小銭が少なくなる場合がある
- strict mode だと SyntaxError になる場合がある
- 定義されていない書式でも動作することがある
参照
読み込んだファイルを格好良い変数に格納する
./index.html
を読み込んで index.html
でアクセスできるようにする。
var fs = require("fs"); var index = { html: fs.readFileSync("index.html", "utf-8") }; console.log(index.html);
以上です。
prominence - node.jsコールバックをPromise化するやつ
と、いうのを作りました。
node.jsの非同期APIはコールバックでエラーと結果を受け取りますが、それをPromiseベースのAPIに変換します。
こうやって使う。
var fs = require("fs"); var prominence = require("prominence"); // prominence するとそのオブジェクトで使える全メソッドが Promise 仕様になる prominence(fs).readFile("hoge.txt", "utf-8").then(function(text) { console.log(text); }).catch(console.error.bind(console)); // こういう書き方もできる prominence(fs, "readFile", [ "hoge.txt", "utf-8" ]).then(function(text) { console.log(text); }).catch(console.error.bind(console)); // 中でやっていること new Promise(function(resolve, reject) { fs.readFile("hoge.txt", "utf-8", function(err, text) { if (err) { return reject(err); } return resolve(text); }); }).then(function(text) { console.log(text); }).catch(console.error.bind(console));
prominence というのは凄く書きづらいですね。
類似のやつも紹介しておきます。
画像を点字にする
2年くらい前にこの記事を見て、真似してブラウザで動くやつを作ったのだけどすっかり忘れて放置していた。
僕の書いたのは二値化した単色点字で、元になったほうを改めて見るとクオリティが全然違っててビックリするのだけど、今週になってもうちょっと便利にならんか?という問い合わせをいただいたので、せっかくだしnpmモジュール化しました。(ブラウザのほうは修正するのが面倒そうだった)
こういう感じで使う。
$ seurat image/lena.jpg
他にサイズや二値化の具合を調整したり、白黒反転させたりできる。
$ seurat --help Usage: seurat [options] path/to/image -w, --width Number width(cols) of the converted text -h, --height Number height(rows) of the converted text -t, --threshold Number threshold for binarization -i, --invert invert to negative -o, --output String write the converted text to this file -p, --print print out the converted text -v, --version show version --help show help
勢いで作ってみたは良いものの問い合わせをくれたのは技術系の人ではなくて node.js が使えないとのことなのでどう連絡しようか悩んでいるところです。
ES6の書き方が定まらない
最近ちょっとしたコードは ES6 で書くようにしているのだけど、慣れていないせいか書き方が定まらない。
例えば ArrowFunction の => の前後にスペースを入れるかどうか
let foo = ()=>{}; // 最初はこうしていたけど let foo = ()=> {}; // これを経て let foo = () =>{}; let foo = () => {}; // 結局これになった
ArrowFunction の {} を省略するかどうか
let foo = array.map(x => x * 2); // 単純な演算なら省略する let foo = array.map((x) => { // メソッド呼び出しが入っていたら return x.valueOf(); // {} は 省略しないようにしていたけど }); let foo = array.map(x => x.valueOf()); // 結局は省略するようになった // でも(感覚的に)長いときや入れ子になっているときは省略しない let foo = array.map((x) => { return x.slice(10).concat(x.slice(0, 10).reverse().map(x => x.valueOf())); }); // {} を使うときは引数の () も省略しない (これはまだ悩んでいる) // 関係ないけど、よく括弧を書き忘れる let a = aray.map x => x.clone();
export のタイミングとか
class Foo {} export default Foo; // 最初はファイルの最後にこうしていたけど export default class Foo {} // 良く考えたらこっちの方が良いと思う export class Bar {} // 上の書き方の場合、default 以外が書きにくくなる
上の書き方だとこういうインポートをする羽目になる
import Foo, {Bar} from "./foobar"; // なんか格好悪い
今、気が付いたけどこう書けばよかったのかも
export class Foo {} // export はその場で書く export class Bar {} export default Foo; // export default はファイルの最後に書く
// 格好良い import Foo from "./foobar"; import { Foo, Bar } from "./foobar"; // こっちの方が分かりやすいのかも知れない.. import * as foobar from "./foobar";
あと var と let を使い分けたり..
let a = () => { // 一番外側は let var a = 10; // 関数の最初は var { let a = 5; // ブロックの中は let } return a; }; // 今は var はいっさい使わない
本当に最初のときはすごく乱暴にこういう感じだった
export default new (class Bar extends require("./foo") { })();
ES6、こういう感じで書くのが良いよというのがあったら教えてください!!
Promiseの使い方が良く分からなくなってきた
先に言っておくと疑問文で終わる雑な記事です。
Promise、正常系の処理は比較的簡単に書けるのだけど、何か間違いがあったときに Promise 自体のエラーハンドリングが強力すぎて良く分からなくなる。
readFile
というファイルを読み込む Promise ベースの良くできた関数があるとして、
読み込んだファイルを処理するとき
readFile("foo.txt").then(function(text) { doSomething(text); });
ファイルが読み込めない場合を想定するとき
readFile("not-found.txt").then(function(text) { doSomething(text); }, function() { readFailed(); });
この時、catch
を使うのは良くなくて、ファイルの読み込みは成功したのに readFailedが実行される場合が考えられる。
readFile("存在するファイル.txt").then(function(text) { doBrokenSomething(text); // ここでエラーが発生する }).catch(function() { readFailed(); });
これを回避するにはこう書く。というか Promise ベースの API を使ったら最後に必ず catch
しておく必要があると思う。
readFile("foo.txt").then(function(text) { doComplexSomething(text); // ここでエラーが発生するかも知れない }, function() { readFailed(); }).catch(console.error.bind(console)); // ^^ doComplexSomething/ readFailed でエラーがあったとき
と、いうのが Promise の基本的な使い方だと思っているのだけど、、
これだとエラーがあったことは分かるけど、どこでエラー発生したか等の情報がいまいち分かりにくくて、デバッグしづらい。よくよく考えると Promise は非同期で実行されるフローを分かりやすく書くことが目的なので、すべてのおぜん立てが揃った最後の then
の中で複雑な処理を書くのがそもそもの間違いな気がする。その段階では Promise のエラーハンドリング機能は邪魔でしかないと思う。Promise の呪縛から逃れるには 大きなスコープ を使うか setTimeout
を使うというのが考えられるのだけど、本当にこんなので良いのでしょうか?
// 大きなスコープを使う var text = null; readFile("foo.txt").then(function(_text) { text = _text; }); button.on("click", function() { if (text !== null) { doComplexSomething(text); } else { readFailed(); } });
// setTimeout を使う button.on("click", function() { readFile("foo.txt").then(function(text) { setTimeout(function() { doComplexSomething(text); }, 0); }, function() { setTimeout(function() { readFailed(); }, 0); }); });
追記:
ということをブツブツ書いていたら、有益な情報教えていただきました!!
@mohayonao > 回避するのに then の中で setTimeout
Promise#done的なやつですね。
エラーの握りつぶし(unhandledRejection)が起きやすい問題は今実装進んでる最中という感じです
https://t.co/Yylri9lYEw
— azu (@azu_re) 2015, 3月 3