JavaScriptã®ã¹ã³ã¼ãã¨ãã¤ã³ãã£ã³ã°ãç解ãã
http://alternateidea.com/blog/articles/2007/7/18/javascript-scope-and-binding
JavaScriptã®ã¹ã³ã¼ãã¨ãã¤ã³ãã£ã³ã°ãç解ãã
ãã¤ã³ãã£ã³ã°ã®ãã¢ã¯ããããå®è¡ã¹ã³ã¼ã âé¢æ°xã¯ãªãã¸ã§ã¯ãyã®ã¹ã³ã¼ãã§å®è¡ããããã¨ãâ ãã³ã³ããã¼ã«ããæ段ã«ãããªãã£ã¦ãã¨ã ãæåã¯ãªãã®ãã¨ã ãåããã«ãããã©ãããã¤ãã®ninja referencesã使ãã°å ¨é¨èª¬æã§ãããã誰ã§ãç解ã§ããã ããã
What's my name fool
ãã¤ã³ãã£ã³ã°ã®åºæ¬çãªã¨ãããç解ããããã«ã次ã®ä¾ã試ãã¦ã¿ããã
var Car = function() { this.name = 'car'; } var Truck = function() { this.name = 'truck'; } var func = function() { alert(this.name); } var c = new Car(); var t = new Truck(); func.apply(c); func.apply(t);
ããã¯Firebugã§ç°¡åã«å®è¡ã§ãã¦ãcarã¨truckããããã®ã¢ã©ã¼ããäºã¤ããã£ã¦ããã ããããªãã§ããããã¾ãåããç解ããã«ã¯ãã¾ãããã¤ãã®åºæ¬çãªãã¨ãç解ãã¦ããå¿
è¦ãããã
JavaScriptã§ã¯é¢æ°ã¯ãªãã¸ã§ã¯ãã§ãapplyã使ãã¨ãããªãã¸ã§ã¯ãã®ã¡ã½ãããå¥ã®ãªãã¸ã§ã¯ãã«é©ç¨(apply)ã§ããããããå®è¡ã¹ã³ã¼ããå¶å¾¡ããã¨ãããã¨ã®åºæ¬çãªæå³ã ã
funcã¯ã©ã®ãªãã¸ã§ã¯ãã«ãå±ãã¦ç¡ããããªãããã¨æããããããªããã©ãããããªããå®ã¯windowãªãã¸ã§ã¯ãã«å±ãã¦ããã ã(ç´æ¥ç®ã®åã®ã³ã¼ãã«è¨è¿°ããã¦ããã¨ããæå³ã§)æ示çãªãªãã¸ã§ã¯ãã®ä¸ã«ã¹ã³ã¼ãããã¦ããªãé¢æ°ã¯å ¨ã¦æ¬¡ã®ããã«ã¿ãªãããã¨æãã¨ãã:
// 次ã®ãããªæ¸ãæ¹ã¯ããªãããã«ãããã¯åãªã説æç¨ã®ä¾ãªã®ã§ã function window() { this.func = function() { alert(this.name); } }
ãã®å³ã§ããã£ã¦ããããã ãããã
Rubyãªã
ãã¾ã¾ã§Rubyã§ããããããæ¹ããããã¨ã¯ç¡ããã ãã©ã大ä½ãããªæãã§ã§ããã ããã
class Car attr_accessor :name def initialize @name = 'car' end end class Truck attr_accessor :name def initialize @name = 'truck' end end def func puts @name end c = Car.new t = Truck.new eval "func", c.send(:binding)
Prototypeã¨ãã®ãã³ãã³ãªãããã¯
éçºè ãPrototypeã使ãã¨ãã«ä¸»ãªæ··ä¹±ã®åå ã«ãªãã®ããã¤ã³ãã£ã³ã°ãç¹ã«ãããã¯ã¨ã¤ãã³ãã®ä¸ã«ããããã ãããã¦ãã®äºã¤ãPrototypeã¨Prototypeã使ã£ã¦æ¸ãããJavaScriptã®ä¸ã§ãã¤ã³ãã£ã³ã°ã使ããã主ãªå ´æã«ãªã£ã¦ãã次ã®ä¾ãè¦ã¦ã¿ããã
var Ninja = Class.create(); Ninja.prototype = { initialize: function(abilities) { this.abilities = [ 'Kick you in the face', 'Rip out your spleen' ]; this.abilities.each(function(ability) { this.executeAbility(ability) }); }, executeAbility: function(ability) { console.log(ability); } } // ãã®ã¡ã½ããã¯Ninjaã¯ã©ã¹ã«ããã¡ã½ããã¨åãååã§ãããã¨ã«æ³¨æã function executeAbility(ability) { console.log("I was called from the window object:" + ability); } new Ninja();
Firebugã§ãã®èå³æ·±ãJavascriptãå®è¡ããã¨ãwindoãªãã¸ã§ã¯ãããã³ã¼ã«ããã¦ã³ã³ã½ã¼ã«ã«2è¡è¿½å ãããã¯ãã ããªããããªãã®ãã¨è¨ãã¨ãeachã«æ¸¡ãããç¡åé¢æ°ã®å é¨ã«ããthisã¯windowãªãã¸ã§ã¯ãã§ãåããå®ç¾©ããã¯ã©ã¹ããç¡ãããã ããã¡ããããã¯æå¾ ããåä½ã§ã¯ãªãã®ã§bindã使ã£ã¦ã¹ã³ã¼ããå¶å¾¡ãããã¨ã«ããã次ã®ä¾ã®ããã«ã³ã¼ãã«bindã追å ãã¦ãããä¸åº¦å®è¡ãããã
this.abilities.each(function(ability) { this.executeAbility(ability) }.bind(this));
ä¸ã®ã³ã¼ããå®è¡ããã°åãã®ã¯ã©ã¹ã®executeAbilityãå®è¡ãããã ãããããã¯executeAbilityã®å®è¡ãNinjaã¯ã©ã¹ã«ãã¤ã³ãããããã ãå³ã使ã£ã説æãå ¨ç¶ç¡ãã£ãã®ã§ã次ã®ãããªè²ã¤ãã®ä¾ãç¨æãã¦ã¿ãã
ãã¤ã³ãã£ã³ã°ã¨ã¤ãã³ã
PAJ(Plain Ass JavaScript)ã§ã¯ãã³ã¼ã«ããã¯å é¨ã®thisã¯ã¤ãã³ããçºçããã¨ã¬ã¡ã³ãã«ãªã£ã¦ããã®ã§ãã¨ã¦ãç°¡åã«æ¬¡ã®ããã«æ¸ããã
var ninja = document.getElementById('ninja'); ninja.addEventListener('click', function () { alert(this.tagName); }, false);
ã ãã©ãPrototypeã§ã¯thisã¯ã³ã¼ã«ããã¯ã®ä¸ã§ãwindowãæãã®ã§ãã¡ã½ãããå±ãããªãã¸ã§ã¯ãã«æç¸ããããã«bindã使ãå¿ è¦ãããã
var Ninja = Class.create(); Ninja.prototype = { ... addObservers: function() { $('item').observe('click', this.kickSomeone.bindAsEventListener(this)); }, kickSomeone: function(event) { // Works because `this` is the Ninja instance // Without binding it would be the window this.someOtherMove(); } ... }
bindAsEventListenerã¯eventãªãã¸ã§ã¯ãã第ä¸å¼æ°ã¨ãã¦æ¸¡ãã¦ããããã¨ããbindã¨bindAsEventListenerã®å¯ä¸ã®éãã ã
ãã¾ãã®å°æ: Early Binding
ã¨ãã©ã追å ã®å¼æ°ãã³ã¼ã«ããã¯é¢æ°ã«æ¸¡ãå¿ è¦ããããã¨ãããã ãããã¾ãããã¤ã³ãæã®å¼æ°ã®å¤ãå¿ è¦ãªãã¨ãããã ãããåãä½ããããããåããã«ãããã°ã次ã®ä¾ã試ãã¦ã¿ããã
var phrase = "This is SPAARRTTAAAA!"; $('somelink').observe('click', sayIt); function sayIt(event) { console.log(phrase); } phrase = "Red sauce on PAASTAAAA!"
somelinkãã¯ãªãã¯ãããã¨ããphraseã®å¤ã¯"This is SPAARRTTAAAA!"ã ã¨æãã ããã
ã ãã©éããã ãã¤ãã³ããªã¹ãã«ç»é²ãããæç¹ã§phraseã®å¤ã"This is SPAARRTTAAAA!"ã ã£ãã¨ãã¦ãã'''ã¤ãã³ããå®è¡ãããåã«'''å¤ã¯å¤æ´ããã¦ãã¾ãããªã®ã§å®éã«ã³ã³ã½ã¼ã«ã«è¡¨ç¤ºãããã®ã¯"Red sauce on PAASTAAAA!"ã ãNot quiet the dramatic effect we wanted.ããã«å¯¾å¿ããããã«ããã¤ã³ãã£ã³ã°ãä½æãããæã«ã³ã¼ã«ããã¯ã«phraseã®å¤ã渡ããã¨ãã§ããã
var phrase = "This is SPAARRTTAAAA!"; $('somelink').observe('click', sayIt.bindAsEventListener(this, phrase)); function sayIt(event, phrase) { console.log(phrase); } phrase = "Red sauce on PAASTAAAA!";
ããã§ãå®è¡æ(execution time)ã§ã¯ãªãè©ä¾¡æ(runtime)ã«å¤ããã¤ã³ãããã®ã§ãã³ã¼ãã®å¾åã§phraseã®å¤ãå¤æ´ãããã«ãããããããã¡ããã¨"This is SPAARRTTAAAA!"ãåãåããã¨ãã§ããã
ã¾ã¨ã
ããã¾ã§è¦ã¦ããããã«ããã¤ã³ãã£ã³ã°ã¯ããã»ã©é£ãããããããªããåã«ç解ã§ããããã«èª¬æããã®ãé£ããã ãã ããã¾ã説æã§ãã¦ãããããã ãã©ããã¾ãè¡ã£ã¦ãªãã£ãã¨ãã¦ãããã¯ninja referencesãååãããªãã£ãããã ãããé²ãã 説æãå¿ è¦ãªãã次ã®ãµã¤ãããã§ãã¯ãã¦ã¿ããã