<html><!-- A feeble attempt to understand Javascript scopes through unit testing --><!-- (the prototype.js/scriptaculous.js way) --><!-- released by rafsoaken under the MIT-license --><!-- feel free to copy, distribute and change for whatever purposes you like --><!-- ver 0.1 --><head> <title>Testing Javascript Scopes</title> <!-- the following javascript files are needed and must be referenced correctly --> <script type="text/javascript" src="js/prototype.js"></script> <script type="text/javascript" src="js/scriptaculous/scriptaculous.js"></script> <script type="text/javascript" src="js/scriptaculous/unittest.js"></script> <link rel="stylesheet" href="js/scriptaculous/test.css" type="text/css"/></head><body><h1>Unit Test Results</h1><!-- Results of Unittests here --><div id="testlog"></div><!-- Testing--><script type="text/javascript"> new Test.Unit.Runner({ setup: function(){ /*runs before any tests*/ }, teardown: function(){ /*runs after every test*/ }, // ------------------------------ TESTS GO HERE ------------------------------- /*tests that start with 'test' will be run automagically*/ testJavascriptScopes: function(){ with(this){ var ScopeObject = Class.create(); //global ScopeObject.prototype = { initialize: function(){}, return_this: function(){return this;}, return_that: function(){return this.return_this();}, return_again: function(){return (function(){return this;})();}, return_again2: function(){return (function(){return this;}.bind(this))();} }; var myScopeObject = new ScopeObject; assertNotIdentical(window, this); // We are are not in the global scope assertNotIdentical(this, myScopeObject.return_this()); // Our scope and the functions scope are not the same - // 'this' in the function refers to the Object it was defined in (myScopeObject)! assertIdentical(myScopeObject, myScopeObject.return_this()); // proof assertIdentical(myScopeObject, myScopeObject.return_this()); // although chained this goes 'this' goes through assertNotIdentical(myScopeObject, myScopeObject.return_again()); // now this anonymous function defined inside return_that does not refer to global scope // it does not even refer to our scope! assertNotIdentical(this, myScopeObject.return_again()); // but to the global scope! assertIdentical(window, myScopeObject.return_again()); // proof assertIdentical(myScopeObject, myScopeObject.return_again2()); // now the anonymous function inside return_again2 was bound to 'this' of return_again2 // much better: the anonymous function now accesses it instead of the global scope // now how about changing scope of the objects methods? assertIdentical(this, myScopeObject.return_this.bind(this).call()); // works assertRaise('TypeError', myScopeObject.return_that.bind(this)); // assertRaise(exceptionName, method) // that doesn't work, as the function 'return_that' calls this.return_this(), // and 'this' refers now to our scope and not myScopeObject, so it is not function (nor exists) // what about chained binds? assertIdentical(this, myScopeObject.return_this.bind(this).bind(this).bind(this).call()); // and some mixed chained binds? assertIdentical(window, myScopeObject.return_this.bind(window).bind(this).call()); assertIdentical(this, myScopeObject.return_this.bind(this).bind(window).bind(myScopeObject).call()); // from this we learn: // -> the first bind determines the scope, further binds don't change a thing // once bound, its bound and unreboundable... assertIdentical(window, myScopeObject.return_again.bind(this).call()); // the anonymous function can't be bothered by our bind.. assertIdentical(this, myScopeObject.return_again2.bind(this).call()); // this one in contrast works fine when bound }} });</script></body></html>