Reading JavaScript Good Parts, I come across two patterns to call a function:
// Method Invocation
var myObject = {
value: 0;
increment: function (inc) {
this.value += typeof inc === 'number' ? inc : 1;
}
};
myObject.increment( );
document.writeln(myObject.value); // 1
myObject.increment(2);
document.writeln(myObject.value); // 3
// Function Invocation
myObject.double = function ( ) {
var that = this; // Workaround.
var helper = function ( ) {
that.value = add(that.value, that.value)
};
helper( ); // Invoke helper as a function.
};
// Invoke double as a method.
myObject.double( );
document.writeln(myObject.getValue( )); // 6
The method invocation pattern makes sense. However, in the function invocation pattern, he says "When a function is not the property of an object, then it is invoked as a function". Well wait a second, isn't the double function a property of myObject? I assume here that myObject is an object literal although it doesn't show its initialization in text. So if it is an object literal, then there is no difference between the two patterns. All we are doing is augmenting a value to the literal. Further, does anyone know where this getValue() is coming from?
I know that these two are indeed distinct in some way, since this in function invocation refers to global context in function invocation, whereas it refers to object itself in method invocation pattern.
The difference is in how the this keyword works inside a function. The odd interesting thing is that in JavaScript it doesn't depend on how the function is defined, but how it is called:
If the function is called as helper(), you cannot use this (with a meaningful value) in the helper code.
If the function is called as myObject.double(), we call that a "method invocation", and this in the double code is the myObject as expected.
This example in the book really confused me for some reason. I reworked his example to better match his explanation (IMHO)
var myObject = {
value: 1,
double: function() {
that = this;
var inner = function() { that.value = that.value + that.value; };
inner(); // Functional invocation
}
};
myObject.double(); // Method invocation
console.log(myObject.value);
Method Pattern
The double method is invoked using the method pattern, therefore this is bound to myObject
Functional Pattern
The inner method is invoked using the functional pattern, therefore this is bound to the global object instead of myObject
Notice the lack of affect on the value property if you modify the double method as follows:
double: function() {
var inner = function() { this.value = this.value + this.value; };
inner();
}
Related
[This is related to Bound function instead of closure to inject extra arguments, but that was neither clearly asked nor answered.]
I'm calling a function that expects a function as its argument. I want to pass a method from my class, bound to an instance of my class. To make it clear, assume my class looks like:
var MyClass = function() {}
MyClass.prototype.myMethod = function() { ... }
var my_instance = new MyClass();
Is there any substantive difference between using bind:
doSomething(my_instance.myMethod.bind(my_instance))
and wrapping the call in an anonymous function:
doSomething(function() { my_instance.myMethod(); })
?
If a prototype within your class needs to generate a callback, it may not know its instance's name. As a result, you'll need to use this, but the value of this depends on where the callback was executed.
Consider the following example:
var MyClass = function (x) { this.something = x; };
MyClass.prototype.makeCall = function () {
var myBadCallback = function() { console.log(this.something); };
var myGoodCallback = function() { console.log(this.something); }.bind(this);
// When called, the value of "this" points to... we don't know
callMeBack( myBadCallback );
// When called, the value of "this" points to this instance
callMeBack( myGoodCallback );
};
function callMeBack( callback ) { callback(); };
var foo = new MyClass('Hello World!');
var bar = new MyClass('Goodbye!');
// Probably prints "undefined", then prints "Hello World!"
foo.makeCall();
// Probably prints "undefined", then prints "Goodbye!"
bar.makeCall();
In the above example, the first output probably prints undefined because the context (what this refers to) has changed by the time the callback has executed.
This example may seem contrived, but these sort of situations do arise, a common case being AJAX callbacks.
I'm, curios how the _.chaining function is implemented and how (or better, why) it works the way it does.
Especially my question is where does the wrapping for each function happen. Let's assume I'm using _.chain(someArray).filter(...); When I step into the function, I can see that the filter function got transformed into something like
function () {
var args = [this._wrapped]; //the data from chain(...)
push.apply(args, arguments); //push to the (?) array
return result.call(this, func.apply(_, args)); //?? where are these coming from?
}
I can see that the function has 3 Closures in it's scope (compare this to the un-chained function that show the definition of the function without all the Closure to it's original function)
The first one is the find function itself, the second "the safe reference to the object itself" and the third on the underscore class itself.
When calling _.chain(), how and where (code-wise) does the transformation (the creating of the scopes etc). I can see that
//http://underscorejs.org/docs/underscore.html#section-139
_.chain = function(obj) {
return _(obj).chain();
};
gets called and this goes to
//http://underscorejs.org/docs/underscore.html#section-145
//...
chain: function() {
this._chain = true;
return this;
},
//...
Then I'm stuck. I can't figure out what happens from there. I assume that the magic happens inside the constructor, but I can't seem to figure out where the additional creation of the Closures comes in. All the functions themselves don't show any sign of being wrapped, the chain call doesn't look like it wraps something. result seems to be there but I don't know where it came from. So, where and how does this happen?
_.chain(obj) returns new instance of _ with attribute _chain = true, that instance of _ has a _wrapped attribute set to current object (great work here). _.mixin(_) in line #1210 add all of underscore methods to underscore (constructor). _.mixin method replace and extend _ methods (still has the parent functions! Accessible via _.prototype). _.mixin change functions of that _ instance (this is the place you see that new function).
New function is:
function () {
var args = [this._wrapped];
push.apply(args, arguments);
return result.call(this, func.apply(_, args));
}
(doesn't matter what method it is, same for all, func is referenced to the original method)
result method function is :
var result = function(obj) {
return this._chain ? _(obj).chain() : obj;
};
so if the object returned by func.apply(_, args) has _chain (_.chain set that attribute) returns _(obj).chain() then you can use it again :)
This is process of chaining but what about prototypes!
In constructor function :
var _ = function(obj) {
if (obj instanceof _) return obj;
if (!(this instanceof _)) return new _(obj); // This line do the magic
this._wrapped = obj;
};
Consider this :
func = function(a){this.a = a;}
b = func(2);
b.a // TypeError: Cannot read property 'a' of undefined
c = new func(2);
c.a // returns 2, whooa this the magical javascript!
Read this (Underscore docs about OOP) if you want to learn more about underscore mixin function
Am I missing something?
I just started reading Functional JavaScript and immediately was introduced to a function that I don't understand:
function splat(fun) {
return function(array) {
return fun.apply(null, array);
};
}
var addArrayElements = splat(function(x, y) { return x + y });
addArrayElements([1, 2]);
//=> 3
How does splat(function(x, y) { return x + y }) work. It's called with the array [1,2], but it seems like the anonymous function inside the call to splat takes two parameters, not one array.
Putting console.log(fun) on line 2 of this code shows that fun is the entirety of the anonymous function(x, y) { return x + y }. console.log(array) after return function(array) { shows that array is [1, 2]. Where does array come from then?
Thanks much.
It might be simpler to see how this function would have been written without using the .apply method:
function splat(fun) {
return function(array) {
return fun(array[0], array[1]);
};
}
First you call splat, passing it a function:
var add = function(x,y){ return x + 1 };
var ff = splat(add);
At this point, ff refers to the function(array) function, meaning its an one-argument function. The private variable fun refers to the add function.
Now, you call ff passing its one argument
ff([1,2]);
and it uses the values in the array to call fun with two arguments
return fun(array[0], array[1]);
The only difference between this and the real example is that the apply method lets you work with any argument array length instead of hardcoding a specific length (2) like I did.
//Every time we call this function, we get another one back
function splat(fun) {
return function(array) { // <-- this one will be returned in splat();
return fun.apply(null, array);
};
}
//Step one, call splat, pass a function as parameter
var addArrayElements = splat(function(x, y) { return x + y });
/*
Get back a function that accepts an array, and will execute the function we just passed in on it
*/
// This will call the newly created function, func will be available because it's in a closure
addArrayElements([1, 2]);
The last thing is that, even if the anonymous function takes two parameters, we call apply on it so it will bind array[0] ==> x and array[1] ==> y
This is an example of a higher order function. That's a function that takes functions as arguments and returns functions instead of just regular values (though functions are "just regular values" in Javascript). In this case:
function splat(fun) {
splat takes a function as its argument...
return function(array) {
...and returns a new function which takes an array...
return fun.apply(null, array);
...and when called calls the first fun function with the array .applied as its arguments.
So splat takes one function which expects several parameters and wraps it in a function which takes an array of parameters instead. The name "splat" comes from languages like Ruby, where a * (a "splat" or "squashed bug") in the parameter list of a function accumulates an arbitrary number of arguments into an array.
var addArrayElements = splat(function(x, y) { return x + y });
addArrayElements is now basically:
function (array) {
// closed over variable:
// var fun = function(x, y) { return x + y }
return fun.apply(null, array);
}
Here this is realized by a closure, which closes over and "preserves" the original fun passed to splat in the new returned function.
addArrayElements = function(array) { fun.apply(null, array); };
BUT
it has a closure whereby the variable context of its containing scope (that of the splat function that created the anonymous function) remains visible and accessible.
In JavaScript, functions are first-class objects that can be referenced and passed as arguments or, as in this case, through the closure mechanism.
Edit: about JavaScript and scope
In most languages, variables are, by default, local to the scope they're defined in (which usually is a function's local symbol table). By contrast, in JavaScript a variable is local only if it is defined using the var keyword; otherwise, the symbol will be looked back in the chain of the containing scopes, up to the implicit root object (which in the case of web browsers is window. I.e.,
function foo() { someVar = "bar"; }
foo();
alert(someVar); // shows "bar"
Not being restricted to the local scope, the symbol has been (purposely or not) leaked to the root scope.
Taking it one step further:
function foo() {
var baz = function() {
someVar = "bar";
};
baz();
}
foo();
alert(someVar); // shows "bar"
However, if you declare someVar within foo:
function foo() {
var someVar;
var baz = function() {
someVar = "bar";
};
baz();
alert("someVar in foo=" + someVar); // shows "bar"
}
foo();
alert("someVar in root=" + window.someVar); // shows "undefined"
Note that in this last version I needed to use window.someVar instead of just someVar because someVar never got defined as a variable in the root scope nor as a property of the root object, which caused an error.
a more functional approach uses bind(), which is short enough you don't really need splat anymore, and it's always nice to eliminate closures:
var addArrayElements = Function.apply.bind( function(x, y) { return x + y } , null );
addArrayElements([1, 2]); // === 3
what is the this (inside inner functions) referring to in the following code context? Does it point to TimeSpan?
var TimeSpan = function (days, hours, minutes, seconds, milliseconds) {
var attrs = "days hours minutes seconds milliseconds".split(/\s+/);
var gFn = function (attr) {
return function () {
return this[attr];
};
};
var sFn = function (attr) {
return function (val) {
this[attr] = val;
return this;
};
};
}
Thanks
The this value is set implicitly depending on how the function is invoked, there are three cases where this happens:
When a reference with no base-object, or a non-reference is invoked:
myFn(); // the myFn reference has no base object
(function () {})(); // non-reference
The this value will point to the global object 1
When a reference contains a base object, for example:
myObj.method();
The this value inside method will point to myObj.
When the new operator is used:
var obj = new Foo();
The this value inside the Foo function, will point to a newly created object that inherits from Foo.prototype.
The this value can be set also explicitly, by using the call and apply methods, for example, with call:
function test(a) {
return alert(this + a);
}
test.call("hello", " world"); // alerts "hello world"
Or with apply if we need to "apply" a set of arguments from an array to a function:
function test(a, b) {
return alert(this + a + b);
}
var args = ["my ", "world "];
test.apply("hello ", args); // alerts "hello my world"
[1] This has changed on the new ECMAScript 5th Strict Mode, now when a function reference with no base object, or a non-reference is invoked (as the first case), the this value will contain undefined.
This was made because when working with constructor functions, people often forgot to use the new operator when calling the constructor.
When that happened, the this value pointed to the global object, and that ended up adding unwanted global properties.
Now on strict mode, this will contain undefined, and if property lookup is made on it (this.foo = 'foo') we will have a nice TypeError exception, instead of having a global foo property.
this refers to the current object, in this case the function you are inside of. Since everything in JavaScript is an object you can modify the attributes of a function object using the this keyword:
var f = function() {
this.key = "someValue";
}
console.log(f.key); // prints "someValue"
So in this case this should point to the function at the deepest scope level, and not TimeSpan.
Consider the following example:
var funcToCall = function() {...}.bind(importantScope);
// some time later
var argsToUse = [...];
funcToCall.apply(someScope, argsToUse);
I want to preserve 'importantScope' of funcToCall. Yet, I need to use apply to apply an unknown number of arguments. 'apply' requires that I provide 'someScope'. I don't want to change the scope, I just want to apply the arguments to the function and preserve its scope. How would I do that?
You can pass any old object (including null) as the first argument to the apply() call and this will still be importantScope.
function f() {
alert(this.foo);
}
var g = f.bind( { foo: "bar"} );
g(); // Alerts "bar"
g.apply(null, []); // Alerts "bar"
The bind method creates a new function in which the this value is guaranteed to be the object you passed in as the parameter to the bind call. Regardless of how this new function is called, this will always be the same. A simple implementation would look like this (note the implementation specified ECMAScript 5 and that in Prototype does more than this but this should give you the idea):
Function.prototype.bind = function(thisValue) {
var f = this;
return function() {
return f.apply(thisValue, arguments);
};
};