javascriptの関数とthis
との関係のメモの続きです。
関数のthis
を決めることができるcall()
とapply()
で実行される関数がFunction.prototype.bindやアロー関数でthis
が決められているものだった場合どうなるのか気になったので調べてみました。
call と apply
call()
も apply()
も this
を指定して関数を実行するメソッド。
違いは関数に渡す引数の指定方法だけ。
call()
は 関数に渡す引数を1つ1つ列挙していく
myFnc.call(this, param1, param2, param3);
apply()
は 関数に渡す引数を第二引数に配列で渡す。実行される関数には引数は展開されて渡される。(argumentsでも参照できる)
myFnc.apply(this, [param1, param2, param3]);
bind (ES5)
Function.prototype.bind()
は新たな関数(a bound function)を生成して返すメソッド。
var fnc = function() { console.log(this); }; var bindFnc = fnc.bind(null); console.log(bindFnc); // => [Function: bound fnc]
bind() 関数は、新たな関数(束縛された関数 = a bound function)を生成して返します。この新たな関数の本体(ECMAScript 5 の観点では内部の call プロパティ)は、call() 先の関数(束縛された関数のターゲット関数)【訳注: fun.bind(thisArg) の fun 】 と同じです。ターゲット関数の this の値が bind() に与えた第 1 引数になり(束縛され)、それを上書きすることはできません。
[出典] Function.prototype.bind() - JavaScript | MDN
bind
で生成された関数は実行時に内部的にcall
が呼ばれるという事だと考えられるので、この関数をcall()
やapply()
で呼出しても、実行される関数内でthis
がbind()
で指定したものに置き換えられるので、bind()
で指定したものが実行される関数内のthis
になる。
'use strict'; var global = Function("return this")(); // global オブジェクトを取得 global.name = 'global'; var obj1 = { name: "obj1" }; var obj2 = { name: "obj2" }; var callback = function() { console.log('> callback this is ', this.name); }; var applyFnc = function(f) { if(typeof(f) === 'function') { let _this = this || global; console.log('this is', _this.name); f.apply(_this); } }; applyFnc( callback ); // => this is global // => > callback this is global // Function.prototype.bind() applyFnc( callback.bind(obj1) ); // => this is global // => > callback this is obj1 applyFnc.call( obj2, callback.bind(obj1) ); // => this is obj2 // => > callback this is obj1
アロー関数 ()=>
(ES6)
アロー関数式 は、function 式 と比べてより短い構文を持ち、this の値を語彙的に束縛します (ただし、自身の this や arguments, super, new.target は束縛しません)。アロー関数は、常に 匿名関数 です。
call や apply からの呼び出し
this はすでに語彙的に束縛されているため、call() や apply() メソッドを介してアロー関数が呼ばれた場合、引数で渡されるだけなので this は影響を受けません
[出典] アロー関数 - JavaScript | MDN
アロー関数は記述が出てきた場所のスコープにあるthis
を関数のthis
に決定するというイメージです。
引用元にも書かれているようにcall()
やapply()
でthis
の値を渡されようと、アロー関数作成時に決定したthis
が実行される関数のthis
になります。
'use strict'; var global = Function("return this")(); global.name = 'global'; var obj1 = { name: "obj1" }; var obj2 = { name: "obj2" }; var applyFnc = function(f) { if(typeof(f) === 'function') { let _this = this || global; console.log('this is', _this.name); f.apply(_this); } }; obj1.fnc1 = function() { applyFnc(() => { console.log('> callback this is ', this.name); }); }; obj1.fnc1(); // => this is global // => > callback this is obj1 obj1.fnc2 = function() { applyFnc.call(obj2, () => { console.log('> callback this is ', this.name); }); }; obj1.fnc2(); // => this is obj2 // => > callback this is obj1
概ね予測通りの結果でした。
.bind()
が新しい関数を生成するというのは知らなかったので、この機会に知ることができて良かったです。同時にデフォルト引数を設定できることも初めて知り寧ろこちらの方に興味惹かれるものがありましたw
こんな事をしているからなかなか本が読み進められないわけです...
[参考]
- Javascriptのbind関数と部分適用 〜 JSおくのほそ道 #015
- arrays - Javascript call() & apply() vs bind()? - Stack Overflow
- Function.prototype.bind() - JavaScript | MDN
- アロー関数 - JavaScript | MDN
- Function.prototype.call() - JavaScript | MDN
- Function.prototype.apply() - JavaScript | MDN
- globalオブジェクトを取得する

- 作者: Nicholas C. Zakas,和田祐一郎
- 出版社/メーカー: オライリージャパン
- 発売日: 2014/06/18
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (4件) を見る