console.logにかぎらず this が変わることに対処する

JavaScript関連のネットサーフィンしてたときのこと
console.logを短く書くときは
var l = console.log l(100)
だとダメで
var l = function(a){ console.log(a) }
と書かないとダメ
Nativeな関数はこういうもの
という感じなことを 書いてるところがちらほら

console.log を変数に直接入れると動かないしクロージャ内で呼べばOKなのはそうだけど 理由も書いて欲しいし 可変引数対応させてほしいし 別にこれはNativeな関数かどうかは関係ないよね と思ったので解説記事を書いてみます

まず動かない理由

これはthisが違うから

JavaScriptではオブジェクトのプロパティに関数があって その関数を実行したときはそのプロパティを持っているオブジェクトになります

var obj = { a: 1, f: function(){console.log(this)} } var obj2 = { a: 100, f: obj.f } var f = obj.f obj.f() obj2.f() f()
結果
Object {a: 1,…} Object {a: 100,…} Window {top: Window, location: Location, document: document, window: Window, …}

obj.f を別のオブジェクトやグローバル変数にコピーして実行すると this の値が変わっています
グローバル変数は window のプロパティなので this は window です


console.log は内部で this を使っているので変数にそのまま代入しても this が違って必要なメソッドが取得できずにエラーになるわけです
クロージャの中での実行は「console.log」として実行してるので this は変わらないのでちゃんと動くというわけです

非Nativeでも

原因は this の違いなのでNative関数かどうかは関係ありません
例えばこんなライブラリを誰かが作っていたとします

var Day = { getTodayDateObject: function(){ return new Date() }, getTomorrowDateObject: function(){ var date = this.getTodayDateObject() date.setDate(date.getDate() + 1) return date } }

明日の DateObject 欲しい時に Day.getTomorrowDateObject() なんて書くのは大変です
かと言って
var gt = Day.getTomorrowDateObject gt()
じゃ this window になってしまってグローバル変数に getTodayDateObject がないのでエラーです

クロージャ内で実行するしかないの?

JavaScriptにはbindというのがあります
関数のメソッドで this の値を固定した関数を返します
var l = console.log.bind(console)

console.log という関数のメソッド bind console を指定すると関数が返り値として返ってくるので l には関数が入っています
その関数は console.logthis を console にした状態で実行してくれます

これでエラーも出ずに console.log を短く書くことができます

クロージャでやる場合

クロージャでやるほうがいい場合もあります

console.log の前後に好きな処理を追加できますし console.log では不要かと思いますが 引数の順番を変えて実行といったこともできます
他にも 引数が 2次元配列なら console.log じゃなくて console.table にして見やすくすることもできます

ただしやるのならば可変引数にも対応させたいです
var l = function(){ console.log.apply(console, arguments) }
これで可変引数に対応です
ですがよく見ると apply this を指定しています

結局 this についての知識が必要なわけですね

まとめ

JavaScriptってちょっとホームページやブログとか作ってみたい程度の人が気軽に触ってることが多いと思うので bind や apply とか this 関係は複雑ですしこんな説明されても困るかもしれないので シンプルに 「そういうことはできません。クロージャでやるとできます。」  と書いておいて簡単に書き換えれるサンプルも載せておくくらいのほうが 親切なのかもしれませんね