Related
Note: while the code in this question deals with functional programming/monads, etc., I'm not asking about functional programming (nor do I think this question should have tags related to functional programming, etc.). Instead, I'm asking about the use of JavaScript's prototype.
Code Source
I'm watching Douglas Crockford's video entitled "Monads and Gonads" (on YouTube either here or here). He includes a demo implementation of a monad in JavaScript, shown below.
The monad Object and its Prototype
In his code, he creates a truly-empty object using Object.create(null) and uses this as the prototype for his eventual monad object. He attaches the bind method to the monad object itself, but any custom functions that are later attached to the monad using lift are attached not to the monad object itself but to its prototype.
Prototype Needed?
It seemed to me that the use of a prototype was unnecessary complexity. Why couldn't those custom functions simply be attached directly to the monad object itself? Then, it seemed to me, the prototype wouldn't be needed, and we could simplify the code.
Puzzling Results When Prototype Removed
I tried implementing this simplification and got puzzling results. The non-prototype-using code sometimes still worked, i.e. it could still use the monad-wrapped value (the string "Hello world.") when the custom function was invoked with no extra parameters (monad2.log()). However, when the custom function was invoked using extra parameters (monad2.log("foo", "bar")), the code was now unable to find value even though it could still use those extra parameters.
Update on Puzzling Results: In part because of the answer from #amon, I have realized that the puzzling results do not appear because I change the number of parameters, but rather because I simply repeat a call to a lifted method on a monad (whether or not the number of parameters has changed). Thus, running monad2.log() twice in a row will yield the correct value the first time but will be undefined the second time.
Questions
So, why is the prototype needed in this code? Or, alternatively, how does eliminating the prototype cause value to be accessible some times but not other times?
Demo Code Descriptions
The two versions of the code are shown below. The prototype-using code (MONAD1) is identical to the code Crockford uses in his video except that the custom function attached is console.log instead of alert so that I could play with this in node rather than in a browser. The non-prototype-using code (MONAD2) makes the changes indicated in the comments. The output is shown in the comments.
The Prototype-Using Code
function MONAD1() {
var prototype = Object.create(null); // later removed
function unit (value) {
var monad = Object.create(prototype); // later moved
monad.bind = function (func, ...args) {
return func(value, ...args);
}
return monad;
}
unit.lift = function (name, func) {
prototype[name] = function (...args) { // later changed
return unit(this.bind(func, ...args));
};
return unit;
};
return unit;
}
var ajax1 = MONAD1()
.lift('log', console.log);
var monad1 = ajax1("Hello world.");
monad1.log(); // --> "Hello world."
monad1.log("foo", "bar"); // --> "Hello world. foo bar"
The Non-Prototype-Using Code
function MONAD2() {
// var prototype = Object.create(null); // removed
var monad = Object.create(null); // new
function unit (value) {
// var monad = Object.create(prototype); // removed
monad.bind = function (func, ...args) {
return func(value, ...args);
}
return monad;
}
unit.lift = function (name, func) {
monad[name] = function (...args) { // changed
return unit(this.bind(func, ...args));
};
return unit;
};
return unit;
}
var ajax2 = MONAD2()
.lift('log', console.log);
var monad2 = ajax2("Hello world.");
monad2.log(); // --> "Hello world." i.e. still works
monad2.log("foo", "bar"); // --> "undefined foo bar" i.e. ???
JSBin
I've played with this code in node, but you can see the results in this jsbin. Console.log doesn't seem to work exactly the same in jsbin as it does in node in the terminal, but it still shows the same puzzling aspects of the results. (The jsbin doesn't seem to work if you just click on 'Run' in the console pane. Rather, you have to activate the output pane by clicking on the 'Output' tab, and then click on 'Run with js' in the 'Output' pane to see the results in the 'Console' pane.)
You have to make a clear distinction between a particular type of monad, and a monad instance that actually contains a value. Your second example is mixing the two up in a manner that I'll discuss in a moment.
First, the MONAD function constructs a new monad type. The concept “monad” is not a type in itself. Instead, the function creates a type that has monad-like behaviour:
The unit operation wraps a value inside a monad. It is a kind of constructor: monadInstance = MonadType(x). In Haskell: unit :: Monad m => a -> m a.
The bind operation applies a function to the value(s) within a monad instance. That function must return a monad of the same type. The bind operation then returns the new monad: anotherMonadInstance = monadInstance.bind(f). In Haskell: bind :: Monad m => m a -> (a -> m b) -> m b.
You can think of the MonadType and the unit() operation as being more or less the same thing. The reason why we create a separate prototype is that we don't want to inherit random baggage from the “function” type. Also, by hiding it within the monad-type constructor, we protect it from unchecked access – only lift can add new methods.
The lift operation is not essential, but mightily convenient. It allows functions that works on plain values (not monad instances), to be applied to monad instances instead. Usually, it would return a new function that operates on the monad level: functionThatReturnsAMonadInstance = lift(ordinaryFunction). In Haskell: lift :: Monad m => (a -> b) -> (a -> m b). But which kind of monad is lift supposed to return? To keep this context, each lifted function is bound to a particular MonadType. Note: not just a particular monadInstance! Once a function is lifted, we can apply it to all monads of the same type.
I'll now rewrite the code to make these terms more clear:
function CREATE_NEW_MONAD_TYPE() {
var MonadType = Object.create(null);
function unit (value) {
var monadInstance = Object.create(MonadType);
monadInstance.bind = function (func, ...args) {
return func(value, ...args);
}
return monadInstance;
}
unit.lift = function (name, func) {
MonadType[name] = function (...args) {
return unit(this.bind(func, ...args));
};
return unit;
};
return unit;
}
var MyMonadType = CREATE_NEW_MONAD_TYPE()
MyMonadType.lift('log', console.log); // adds MyMonadType(…).log(…)
var monadInstance = MyMonadType("Hello world.");
monadInstance.log(); // --> "Hello world."
monadInstance.log("foo", "bar"); // --> "Hello world. foo bar"
What happens in your code is that you get rid of the monadInstance. Instead, you add a bind operation to the MonadType! This bind operation happens to refer to the last value that was wrapped with unit().
Now note that the return value of lifted functions is wrapped as a monad with unit.
When you construct the monadInstance (which is actually MonadType), then MonadType.bind() refers to the "Hello World" value.
You invoke the lifted log() function. It receives the value within the monad, which is the last value that was wrapped with unit(), which is "Hello World". The return value of the lifted function (console.log) is wrapped with unit(). This return value is undefined. You then replace the bind function with a new bind that refers to the undefined value.
You invoke the lifted log() function. It receives the value within the monad, which is the last value that was wrapped with unit(), which is undefined. The observed output ensues.
How can I access a function name from inside that function?
// parasitic inheritance
var ns.parent.child = function() {
var parent = new ns.parent();
parent.newFunc = function() {
}
return parent;
}
var ns.parent = function() {
// at this point, i want to know who the child is that called the parent
// ie
}
var obj = new ns.parent.child();
In ES6, you can just use myFunction.name.
Note: Beware that some JS minifiers might throw away function names, to compress better; you may need to tweak their settings to avoid that.
In ES5, the best thing to do is:
function functionName(fun) {
var ret = fun.toString();
ret = ret.substr('function '.length);
ret = ret.substr(0, ret.indexOf('('));
return ret;
}
Using Function.caller is non-standard. Function.caller and arguments.callee are both forbidden in strict mode.
Edit: nus's regex based answer below achieves the same thing, but has better performance!
ES6 (inspired by sendy halim's answer below):
myFunction.name
Explanation on MDN. As of 2015 works in nodejs and all major browsers except IE.
Note: On bound functions this will give "bound <originalName>". You will have to strip the "bound " if you want to get the original name.
ES5 (inspired by Vlad's answer):
If you have a reference to the function, you can do:
function functionName( func )
{
// Match:
// - ^ the beginning of the string
// - function the word 'function'
// - \s+ at least some white space
// - ([\w\$]+) capture one or more valid JavaScript identifier characters
// - \s* optionally followed by white space (in theory there won't be any here,
// so if performance is an issue this can be omitted[1]
// - \( followed by an opening brace
//
var result = /^function\s+([\w\$]+)\s*\(/.exec( func.toString() )
return result ? result[ 1 ] : '' // for an anonymous function there won't be a match
}
I have not run unit tests on this, or verified implementation
differences, but in principle it should work, if not leave a comment.
Note: won't work on bound functions
Note: that caller and callee are considered deprecated.
[1] I include it here because it is legal and often enough syntax highlighting tools fail to take into account the white space between function name and parenthesis. On the other hand, I'm not aware of any implementation of .toString() that will include white space here, so that's why you can omit it.
As an answer to the original question, I would drop parasitic inheritance and go for some more traditional OOP design patterns. I wrote a TidBits.OoJs to comfortably write OOP code in JavaScript with a feature set mimicking C++ (not yet complete, but mostly).
I see from the comments that you would like to avoid passing information parent needs to it's constructor. I must admit that traditional design patterns won't save you from that one though, since it is generally a considered a good thing to make your dependencies obvious and enforced.
I would also suggest to steer away from anonymous functions. They only make debugging and profiling a PITA because everything just shows up as "anonymous function", and there is no benefit to them that I'm aware of.
what you're doing is assigning unnamed function to a variable. you probably need named function expression instead ( http://kangax.github.com/nfe/ ).
var x = function x() {
console.log( arguments.callee.name );
}
x();
however I'm not sure how much cross-browser that is; there's an issue with IE6 that makes you function's name leak to the outer scope. also, arguments.callee is kind of deprecated and will result in error if you're using strict mode.
It looks like the most stupid thing, that I wrote in my life, but it's funny :D
function getName(d){
const error = new Error();
const firefoxMatch = (error.stack.split('\n')[0 + d].match(/^.*(?=#)/) || [])[0];
const chromeMatch = ((((error.stack.split('at ') || [])[1 + d] || '').match(/(^|\.| <| )(.*[^(<])( \()/) || [])[2] || '').split('.').pop();
const safariMatch = error.stack.split('\n')[0 + d];
// firefoxMatch ? console.log('firefoxMatch', firefoxMatch) : void 0;
// chromeMatch ? console.log('chromeMatch', chromeMatch) : void 0;
// safariMatch ? console.log('safariMatch', safariMatch) : void 0;
return firefoxMatch || chromeMatch || safariMatch;
}
d - depth of stack. 0 - return this function name, 1 - parent, etc.;
[0 + d] - just for understanding - what happens;
firefoxMatch - works for safari, but I had really a little time for testing, because mac's owner had returned after smoking, and drove me away :'(
Testing:
function limbo(){
for(let i = 0; i < 4; i++){
console.log(getName(i));
}
}
function lust(){
limbo();
}
function gluttony(){
lust();
}
gluttony();
Result:
Chrome:
Fitefox:
This solution was creating only just for fun! Don't use it for real projects. It does not depend on ES specification, it depends only on browser realization. After the next chrome/firefox/safari update it may be broken.
More than that there is no error (ha) processing - if d will be more than stack length - you will get an error;
For other browsers error's message pattern - you will get an error;
It must work for ES6 classes (.split('.').pop()), but you sill can get an error;
Any constructor exposes a property name, which is the function name. You access the constructor via an instance (using new) or a prototype:
function Person() {
console.log(this.constructor.name); //Person
}
var p = new Person();
console.log(p.constructor.name); //Person
console.log(Person.prototype.constructor.name); //Person
This might work for you:
function foo() { bar(); }
function bar() { console.log(bar.caller.name); }
running foo() will output "foo" or undefined if you call from an anonymous function.
It works with constructors too, in which case it would output the name of the calling constructor (eg "Foo").
More info here: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Caller
They claim it's non-standard, but also that it's supported by all major browsers: Firefox, Safari, Chrome, Opera and IE.
You can't. Functions don't have names according to the standard (though mozilla has such an attribute) - they can only be assigned to variables with names.
Also your comment:
// access fully qualified name (ie "my.namespace.myFunc")
is inside the function my.namespace.myFunc.getFn
What you can do is return the constructor of an object created by new
So you could say
var obj = new my.namespace.myFunc();
console.info(obj.constructor); //my.namespace.myFunc
You could use this, for browsers that support Error.stack (not nearly all, probably)
function WriteSomeShitOut(){
var a = new Error().stack.match(/at (.*?) /);
console.log(a[1]);
}
WriteSomeShitOut();
of course this is for the current function, but you get the idea.
happy drooling while you code
You could use Function.name:
In most implementations of JavaScript, once you have your constructor's reference in scope, you can get its string name from its name property (e.g. Function.name, or Object.constructor.name
You could use Function.callee:
The native arguments.caller method has been deprecated, but most browsers support Function.caller, which will return the actual invoking object (its body of code):
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FFunction%2Fcaller
You could create a source map:
If what you need is the literal function signature (the "name" of it) and not the object itself, you might have to resort to something a little more customized, like creating an array reference of the API string values you'll need to access frequently. You can map them together using Object.keys() and your array of strings
You can use name property to get the function name, unless you're using an anonymous function
For example:
var Person = function Person () {
this.someMethod = function () {};
};
Person.prototype.getSomeMethodName = function () {
return this.someMethod.name;
};
var p = new Person();
// will return "", because someMethod is assigned with anonymous function
console.log(p.getSomeMethodName());
now let's try with named function
var Person = function Person () {
this.someMethod = function someMethod() {};
};
now you can use
// will return "someMethod"
p.getSomeMethodName()
You can use constructor name like:
{your_function}.prototype.constructor.name
this code simply return name of a method.
as part as ECMAScript 6 you can use Function.name method
function doSomething() {}
alert(doSomething.name); // alerts "doSomething"
I know this is a old question but lately I've been facing some similar issue while trying to decorate some React Component's methods, for debugging purposes. As people already said, arguments.caller and arguments.callee are forbidden in strict mode which is probably enabled by default in your React transpiling. You can either disable it, or I've been able to come up with another hack, because in React all class functions are named, you can actually do this:
Component.prototype.componentWillMount = function componentWillMount() {
console.log('Callee name: ', this.__proto__.constructor.toString().substr(0,30));
...
}
This worked for me.
function AbstractDomainClass() {
this.className = function() {
if (!this.$className) {
var className = this.constructor.toString();
className = className.substr('function '.length);
className = className.substr(0, className.indexOf('('));
this.$className = className;
}
return this.$className;
}
}
Test code:
var obj = new AbstractDomainClass();
expect(obj.className()).toBe('AbstractDomainClass');
I had a similar problem and I solved it as follows:
Function.prototype.myname = function() {
return this.toString()
.substr( 0, this.toString().indexOf( "(" ) )
.replace( "function ", "" );
}
This code implements, in a more comfortable fashion, one response I already read here at the top of this discussion.
Now I have a member function retrieving the name of any function object.
Here's the full script ...
<script language="javascript" TYPE="text/javascript">
Function.prototype.myname = function() {
return this.toString()
.substr( 0, this.toString().indexOf( "(" ) )
.replace("function ", "" );
}
function call_this( _fn ) { document.write( _fn.myname() ); }
function _yeaaahhh() { /* do something */ }
call_this( _yeaaahhh );
</script>
If I understood what you wanted to do, this is what I do inside a function constructor.
if (!(this instanceof arguments.callee)) {
throw "ReferenceError: " + arguments.callee.name + " is not defined";
}
This will work in ES5, ES6, all browsers and strict mode functions.
Here's how it looks with a named function.
(function myName() {
console.log(new Error().stack.split(/\r\n|\r|\n/g)[1].trim());
})();
at myName (<anonymous>:2:15)
Here's how it looks with an anonymous function.
(() => {
console.log(new Error().stack.split(/\r\n|\r|\n/g)[1].trim());
})();
at <anonymous>:2:15
A simple solution to dynamically retrieve function names [like magic variables] is the use of scoped variables.
{
function parent() {
console.log(a.name);
}; let a = parent
}
{
function child() {
console.log(a.name)
}; let a = child
};
parent();//logs parent
child();//logs child
Note: Nested functions cease to be source elements, and are hence not hoisted.
Also, this technique cannot work with anonymous functions.
Just try Function.name
const func1 = function() {};
const object = {
func2: function() {}
};
console.log(func1.name);
// expected output: "func1"
console.log(object.func2.name);
// expected output: "func2"
look here: http://www.tek-tips.com/viewthread.cfm?qid=1209619
arguments.callee.toString();
seems to be right for your needs.
Easy way to get function name from within fuction you are running.
function x(){alert(this.name)};x()
you can use Error.stack to trace the function name and exact position of where you are in it.
See stacktrace.js
I would like to override a Javascript built-in function with a new version that calls the original (similarly to overriding a method on a class with a version that calls super in many languages). How can I do this?
For example...
window.alert = function(str) {
//do something additional
if(console) console.log(str);
//super.alert(str) // How do I do this bit?
}
Store a reference to the original function in a variable:
(function() {
var _alert = window.alert; // <-- Reference
window.alert = function(str) {
// do something additional
if(console) console.log(str);
//return _alert.apply(this, arguments); // <-- The universal method
_alert(str); // Suits for this case
};
})();
The universal way is <original_func_reference>.apply(this, arguments) - To preserve context and pass all arguments. Usually, the return value of the original method should also be returned.
However, it's known that alert is a void function, takes only one argument, and does not use the this object. So, _alert(str) is sufficient in this case.
Note: IE <= 8 throws an error if you try to overwrite alert, so make sure that you're using window.alert = ... instead of alert = ....
There is no "super". Anyway, create a closure to "keep" around the original function-object.
Note the "self invoking function" that returns a new function-object (that is assigned to the window.alert property). The new function-object returned creates a closure around the variable original which evaluates to the original value of window.alert that was passed in to the "self invoking function".
window.alert = (function (original) {
return function (str) {
//do something additional
if(console) {
console.log(str)
}
original(str)
}
})(window.alert)
However, I believe some browsers may prevent alert and other built-ins from being modified...
Happy coding.
I'm assuming your question is how do you overwrite a built-in and still be able to call it. First off as a disclaimer, you should never overwrite built ins unless you have a good reason for doing it since it will make it impossible to debug/test.
This is how you would do it:
window._alert = window.alert;
window.alert = function(str) {
if(console) console.log(str);
window._alert(str);
}
How to do simple classical inheritance in Javascript:
SuperClass.call(this) // inherit from SuperClass (multiple inheritance yes)
How to override functions:
this.myFunction = this.myFunction.override(
function(){
this.superFunction(); // call the overridden function
}
);
The override function is created like this:
Function.prototype.override = function(func)
{
var superFunction = this;
return function()
{
this.superFunction = superFunction;
return func.apply(this,arguments);
};
};
Works with multiple arguments.
Fails when trying to override undefined or nonfunctions.
Makes "superFunction" a "reserved" word :-)
JavaScript does not use a classical inheritance model. There is a nice article here which describes a way to write your classes so that a similar syntax can be used, but it's not natively supported.
By using proxy object you can do this.
window.alert = new Proxy(window.alert , {
apply: function(target,that,args){
console && console.log(args.join('\n'));
target.apply(that,args)
}})
If i need to write a java script function that takes an argument and returns a function that returns that argument, i can think of following two implementations. Are both of these same ? or there is anything different technically ? Both works and returns the same result.
/*Implemenation 1*/
function myWieredFunc(arg){
var retf=function inner(){
return arg;
};
return retf;
}
/* Implemenation 2 */
function myWieredFunc(arg){
return function(){
return arg;
};
}
To use these:
var f = myWieredFunc(84);
alert(f());
This would be the way to write it
function wrap(arg) {
return function() {
return arg;
};
};
If you wanted to make it more flexible you could allow multiple arguments:
function wrap() {
var args = arguments;
return function() {
return args;
};
};
var later = wrap('hello', 'world');
var result = later();
console.log(result); // ["hello", "world"]
There is no reason for the variable in the code shown - functions are objects are values. As you've shown this means that function-objects can be assigned to a variable which is later evaluated and returned, or returned directly from the Function Expression.
As such, both forms are generally held equivalent and the closure over arg is unaffected.
However, in the first form..
Function.toString and stack-traces will normally include the function name, this makes "named functions", as in the first example sometimes more useful in debugging. Additionally, Firefox will expose function names - e.g. "inner" - through the non-standard Function.name property. (The function name can be specified without the use of the retf variable.)
Two additional bindings are introduced - retf in the outer function and inner in the inner function. These variables could be observed in the the applicable scope when stopping via a break-point - but are not otherwise accessible in the code shown.
They are the same thing, the second is using an "Anonymous" function which just means its a function that is not given a name or assigned to a variable.
(Question 1)
In Flanagan's JS Definitive Guide, he defines the Function method bind() in case it's not available (wasn't available n ECMAScript 3).
It looks like this:
function bind(f, o) {
if (f.bind) return f.bind(o); // Use the bind method, if there is one
else return function() { // Otherwise, bind it like this
return f.apply(o, arguments);
};
}
He illustrates the use of it with an example (which I have modified to change the 3rd line from f.bind(o)):
function f(y) { return this.x + y; } // This function needs to be bound
var o = { x : 1 }; // An object we'll bind to
var g = bind(f, o); // Calling g(x) invokes o.f(x)
g(2) // => 3
When I first saw this, I thought "Wouldn't arguments refer to the arguments variable within the bind function we're defining? But we want the arguments property of the function we eventually apply it to, like g in the example above..."
I verified that his example did indeed work and surmised that the line return f.apply(o, arguments) isn't evaluated until var g = bind(f, o) up above. That is, I thought, when you return a function, are you just returning the source code for that function, no? Until its evaluated? So I tested this theory by trying out a slightly different version of bind:
function mybind2(f, o) {
var arguments = 6;
return function() { // Otherwise, bind it like this
return f.apply(o, arguments);
};
}
If it's simply returning tbe unevaluated function source, there's no way that it stores arguments = 6 when later evaluated, right? And after checking, I still got g(2) => 3. But then I realized -- if it's just returning unevaluated code, how is the o in return f.apply(o, arguments) getting passed?
So I decided that what must be happening is this:
The o and the arguments variables (even when arguments equals 6) are getting passed on to the function. It's just that when the function g is eventually called, the arguments variable is redefined by the interpreter to be the arguments of g (in g(2)) and hence the original value of arguments that I tried to pass on was replaced. But this implies that it was sort of storing the function as text up until then, because otherwise o and arguments would have simply been data in the program, rather than variables that could be overwritten. Is this explanation correct?
(Question 2) Earlier on the same page, he defines the following function which makes use the apply method to trace a function for debugging:
function trace(o, m) {
var original = o[m]; // Remember original method in the closure.
o[m] = function() { // Now define the new method.
console.log(new Date(), "Entering:", m); // Log message.
var result = original.apply(this, arguments); // Invoke original.
console.log(new Date(), "Exiting:", m); // Log message.
return result; // Return result.
};
}
Wouldn't the this here refer to the function that we're defining, rather than the object o? Or are those two things one and the same?
Question 1
For your first question, let's simplify the example so it's clear what being done:
function bind(func, thisArg) {
return function () {
return func.apply(thisArg, arguments);
};
}
What happens here is that a closure is created that allows the access of the original function and the value of this that is passed. The anonymous function returned will keep the original function in its scope, which ends up being like the following:
var func = function () {};
var thisArg = {};
func.apply(thisArg, [/*arguments*/]);
About your issue with arguments, that variable is implicitly defined in the scope of all functions created, so therefore the inner arguments will shadow the outer arguments, making it work as expected.
Question 2
Your problem is to your misunderstanding of the late binding of this -- this is one of the more confusing things about JavaScript to people used to more object-oriented languages that also have their own this keyword. The value of this is only set when it is called, and where it is called defines the value of this when it is called. It is simply the value of the parent object from where it is at the time the function is called, with the exception of cases where the this value is overridden.
For example, see this:
function a() {return this;};
a(); // global object;
var b = {};
b.a = a;
b.a(); // object b
If this was set when the function was defined, calling b.a would result in the global object, not the b object. Let's also simplify what happens with the second function given:
function trace(obj, property) {
var method = obj[property]; // Remember original method in the closure.
obj[property] = function () { // Now define the new method.
console.log(1); // Log message.
// Invoke original method and return its result
return original.apply(this, arguments);
};
}
What happens in this case is that the original method is stored in a closure. Assigning to the object that the method was originally in does not overwrite the method object. Just like a normal method assignment, the principles of the this value still work the same -- it will return the parent object, not the function that you've defined. If you do a simple assignment:
var obj = {};
obj.foo = function () { return this; };
obj.foo(); // obj
It does what was expected, returns the parent object at the time of calling. Placing your code in a nested function makes no difference in this regard.
Some good resources
If you'd like to learn more about writing code in JavaScript, I'd highly recommend taking a look at Fully Understanding the this Keyword by Cody Lindley -- it goes into much more detail about how the this keyword behaves in different contexts and the things you can do with it.
But this implies that it was sort of storing the function as text up until then, because otherwise o and arguments would have simply been data in the program, rather than variables that could be overwritten. Is this explanation correct?
No. this and arguments are just special variables which are implicitly set when a function is executed. They don't adhere to normal "closure rules". The function definition itself is still evaluated immediately and bind returns a function object.
You can easily verify this with:
var g = bind(f, o);
console.log(typeof g);
Here is a simpler example which doesn't involve higher order functions:
var arguments = 42;
function foo() {
console.log(arguments);
}
foo(1, 2);
I think you see that the definition of foo is evaluated like you'd expect. Yet, console.log(arguments) logs [1, 2] and not 42.
Wouldn't the this here refer to the function that we're defining, rather than the object o? Or are those two things one and the same?
this never refers to the function itself (unless you explicitly set it so). The value of this is completely determined by how the function is called. That's why this is often called "the context". The MDN documentation provides extensive information about this.
Reading material:
MDN - this
MDN - arguments