僕らは JavaScript を知らない - 巻き上げ Hoisting
参考:
JavaScript において、変数を宣言するには var
、 let
、 const
を利用します。これらのうち、 var
let
では、初期値を指定せずに宣言した場合すべて undefined
になります。
var a; let b; console.log(a); // undefined console.log(b); // undefined
変数や関数の宣言が、自身のスコープ内のコードの一番上に来ているかのような動作を巻き上げ (Hoisting) と呼びます。例えば、次のコードを実行してみましょう。
a = 1;
var a;
console.log(a);
上記のコードを上から順に解釈していけば、 undefined
と出力されそうですが、実際には 1
が出力されます。関数宣言でも同様です:
foo(); function foo() { console.log(1); }
foo
関数の宣言前に foo
を実行しているようにみえますが、出力は 1
になります。コードの実行順に即したコードはそれぞれ次のようになります:
var a;
a = 1;
console.log(a);
function foo() { console.log(1); } foo();
このように、変数や関数の宣言をスコープ内の一番上 (今回はグローバルスコープ) にもってくることを巻き上げ (Hoisting) と呼びます。実際の JavaScript の動作としては、コード実行前のコンパイル時に宣言式を処理しているというだけで、宣言式を物理的に動かしているということはありません。
注意点として関数式は巻き上げされないため、次のコードではエラーが発生します:
foo(); // Uncaught TypeError: foo is not a function var foo = function() { console.log(1); }
変数 foo
の宣言は巻き上げられて処理されます。しかし、関数の代入はコードの実行時に処理されるため、 foo()
は undefined
を実行し、 TypeError
が発生します。コードの実行順に即して書き直すと次のようになるでしょう:
var foo; foo(); foo = function() { console.log(1); }
foo
の値が undefined
になることがよく理解できるのではないでしょうか。
また、 let
/ const
では巻き上げは起こりません。
console.log(a); // ReferenceError: a is not defined let a = 1;
僕らは JavaScript を知らない - シンボル Symbol
初めてプログラミングを触って、それからずっと2年くらい JavaScript 使ってますが、なかなか初心者から抜け出せないなあという思いがあり、恥を忍んで JavaScript の勉強記事を書くことにしました。たぶん何回か続きます。
参考:
シンボル Symbol
ES6 (実装はもう3年以上前?) では "Symbol" と呼ばれるプリミティブ(基本)データ型が追加されました。下記のコードでは、実際にシンボルを生成しています:
var sym = Symbol( "some optional description" ); typeof sym; // "symbol" sym.toString(); // "Symbol(some optional description)" var obj = { }; obj[sym] = "foobar"; Object.getOwnPropertySymbols( obj ); // [ Symbol(some optional description) ]
注意すべき特徵は、
- new 演算子で生成するわけではない
- 引数は任意。一度生成されたシンボルは自身のみと等しい
- シンボルの値そのものを取得することは出来ない
ということです。ほとんどの JavaScript デベロッパーには使う機会のない代物かもしれません。具体的な使用例を以下に見ていきましょう。
列挙定数
シンボルには「一度生成されたシンボルは自身のみと等しい」という特徴があるため、次のように定数として表すことが出来ます:
const EVN_LOGIN = Symbol( "event.login" ); const EVN_LOGOUT = Symbol( "event.logout" );
Redux の ActionTypes もシンボルで定義したいところですが、残念ながら、シンボルはJSONへのパースができないため Redux DevTool との相性が悪いということもあってか、推奨されていませんでした[^1]。
オブジェクトプロパティとしてのシンボル
シンボルをオブジェクトの特別なキープロパティとして使うことも出来ます。
const MEMBER = Symbol( "a" ); function save(value) { return save[MEMBER] = value; }
動作自体は以下と変わりありません:
function save(value) { return save.__member = value; }
シンボルをオブジェクトのキーにした場合、シンボルは Object.getOwnPropertyNames
メソッドからは秘匿されます:
var o = { foo: 42, [ Symbol( "bar" ) ]: "hello world", baz: true }; Object.getOwnPropertyNames( o ); // [ "foo","baz" ]
しかし、次のメソッドを使用することでオブジェクトのシンボルプロパティを取得することができます:
Object.getOwnPropertySymbols( o ); // [ Symbol(bar) ]
Well Known Symbol
シンボル関数オブジェクトにあらかじめ定義されたシンボルのことを Well Known Symbol と呼びます。
たとえば、 iterate
という Well Known Symbol は Symbol.iterate
として参照可能です。これらは、 JavaScript の組み込み関数の挙動をオーバーライドするために使用することが出来ます。
また、これらを @@
プレフィックスを付けて呼ぶ(@@iterate
)ことがあります。
var arr = [4,5,6,7,8,9]; for (var v of arr) { console.log( v ); } // 4 5 6 7 8 9 // for ... of ループの挙動を自作のイテレータでオーバーライド arr[Symbol.iterator] = function*() { var idx = 1; do { yield this[idx]; } while ((idx += 2) < this.length); }; for (var v of arr) { console.log( v ); } // 5 7 9
Symbol.for / Symbol.keyFor
シンボルを使用する可能性のあるコードがアクセスできるように、シンボルは外部のスコープに定義しなければなりませんが、 Symbol.for
メソッドを使えば、グローバルな空間における一意の文字列で管理することが可能です。
Symbol.for
メソッドは、文字列を引数にとり、その文字列ですでにシンボルが定義されていればそのシンボルの値を、定義されていなければ新たに作成し、シンボルの値を返します。
また、 Symbol.keyFor
メソッドでは、登録されたシンボルに渡された文字列を得ることが可能です。
var s = Symbol.for( "something cool" ); var desc = Symbol.keyFor( s ); console.log( desc ); // "something cool" // 再びシンボルを取得 var s2 = Symbol.for( desc ); s2 === s; // true
Symbol については以上になります。 余裕ができたら Well Known Symbol についても詳しく書くことにしましょう。
You Don't Know JS の日本語訳プロジェクトってないのかな?あったら教えて下さい。 もしなくて、日本語訳に興味がある方がいたら一緒にやりましょう。Twitterとかで連絡下さい。スペイン語翻訳のプロジェクトは見た記憶があるので許可はもらえると思います。
Amazon ECS Scheduled Tasks によるコマンドの定期実行
使い方
CMDに実行したいコマンドをカンマ区切りで入力し、Task Definition を作成。その他環境変数とかも
作成した Task Definition を Cluster の scheduled task にて設定。Cronかインターバルかを選択できる。
CloudWatch でログも見れるので便利
ActiveRecord IN clause
環境
$ rails -v Rails 5.1.2
基本形 where(カラム: [要素])
Model.where(id: [1,3,5])
enumのSymbolもそのままいける
Model.where(status: [:active, :inactive])
参考:
【SQL】今週の日曜日・今週の土曜日を求める
メモ:
CURRENT_DATE - interval (DAYOFWEEK(CURRENT_DATE) - 1) day AS THIS_SUNDAY
日曜日始まりとする。
今日の曜日インデックス(DAYOFWEEK(CURRENT_DATE)
)から日曜日の曜日インデックスを引くと、今日が日曜日から何日目かが分かる。
CURRENT_DATE + interval (7 - DAYOFWEEK(CURRENT_DATE)) day AS THIS_SATURDAY
土曜日の曜日インデックスから今日の曜日インデックスを引くと、土曜日は今日から何日目かが分かる。
もしかしたらそれ用の関数とか用意されてるのだろうか
Alpineでパッケージをインストールしようとしたらエラーがでたので解消する
メモ
ERROR: unsatisfiable constraints: py-pip (missing): required by: world[py-pip] ERROR: Service 'web' failed to build: The command '/bin/sh -c apk add py-pip' returned a non-zero code: 1
インストール可能なパッケージ一覧(インデックス)の更新オプションを付けると解消される (--update
)
apk add --update py-pip