Underscore chaining inner workings - javascript

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?

Related

Am I passing an object to object.defineProperties?

I am learning javascript and would love help understanding the snippet of code.
From Object.DefineProperties definition, the first parameter is an object. Is MyObjectConstructor a declaration or an object. With a constructor function I would expect to call new to make it an object.
This is what is confusing me. Or as I read in Javascript functions are objects so do I treat it as an object and the this property is where all staticProps and instanceProps are added to?
var _prototypeProperties = function (child, staticProps, instanceProps) {
if (staticProps){
Object.defineProperties(child, staticProps)
};
if (instanceProps) {
Object.defineProperties(child.prototype, instanceProps);
}
};
function myFunction() {
function MyObjectConstructor(element) {
this.element = element;
this.initialized = false;
}
_prototypeProperties(MyObjectConstructor, {...}, {...});
}
Yes, (constructor) functions are objects as well in javascript, and you can add properties directly to them.
The _prototypeProperties function in your example snippet does put the staticProperties on the constructor, so that they could be accessed as MyObjectConstructor.myStaticProperty. It also does put instanceProps (better: "class properties", "prototype properties") on the MyObjectConstructor.prototype object, from where they are inherited by instances: (new MyObjectConstructor).myPrototypeProperty. Lastly, your MyObjectConstructor does put "real" (own) properties on the instances, specifically (new MyObjectConstructor).element and .initialised.
In JavaScript, once defined, the resulting functions act identically:
function Hat() { }
var Hat = function() { }
Conventionally the first is used to create objects (usually with new) and the second is used as a regular method.
The new operator, when preceding a function gets kinda weird. Using the new operator will:
create a new Object "it"
set the function being called as "it"s prototype
binds "it" to this within the function
overrides the return value of the function with "it". This overrides both explicit returns and implicit returns of undefined.
For example:
// first define Hat function
function Hat() { this.color = 'red' }
// calling with `new` implicitly returns a new object bound to the function
new Hat()
// > Hat { color: "red" }
// invoking without `new` implicitly returns `unefined`,
// but `this` points to Hat's parent object.
// If running in the browser, Hat's parent object would be `window`
// so now Window.color is set to "red"
Hat()
//> undefined
Window.color
//> "red"
Be careful with new, because the new object will be returned instead of any explicit returns.
var color = function() { return "blue" }
color()
//> "blue"
new color()
//> color {}
JavaScript is prototypal by nature. The new operator reflects neither prototypical nor classical inheritance. I avoid it when possible, although many popular libraries use it.
I recommend reading through Crockford's explanation of JavaScript's prototypal inheritance: http://javascript.crockford.com/prototypal.html
Its terse, but if you understand his 10 lines of demo code you'll be good.
Play with bind, call and apply, and different scoping contexts too. After understanding scoping and the prototypal nature, the rest is just syntax.
first : the function is the first type object in the javascript . it means you can deliver the function as value . for example :
function test(){
return function(){
console.log('function');
}
}
test()();
you return the function as return an object , function can be assigned and the function another kind of value !
var test = function(i) {
// body...
return i;
}
test('123');
a character string 'test' refer to a Anonymous function , you can understand that you transmit a function to a character string .
second : if you use new to create a instance via function , this function will be called construction function , normally it used to init the params , and the instance will take the construction function own property or method and prototype's property or method from the construction function .
third : the instance's property of "__proto__" is refer to the construction function's prototype object . this is why the instance can use the prototype's property or method from the construction function .
forth : if you create the instance by new , the this will refer to the instance object ! so that instance can use the property and method .
from your code :
var _prototypeProperties = function (child, staticProps, instanceProps) {
if (staticProps){
Object.defineProperties(child, staticProps)
};
// the properties from the own construction function , like this :
// this.element = element;
// this.initialized = false;
if (instanceProps) {
Object.defineProperties(child.prototype, instanceProps);
}
};
// the properties from the construction function's prototype object . like this :
// MyObjectConstructor.prototype.name = 'somebody';
// MyObjectConstructor.prototype.getName = function(){
// return this.name;
// }

the "new" word changes a function to an object?

I'm stuck in some issue, a had a function like this:
var sayHi = function(string){
console.log(string + '' + this.name);
};
then i need to do :
sayHi = giveContext(sayHi,{"name":"moe"});
and then I do :
function giveContext(func,obj){
var fn = func;
fn.prototype.name = obj.name;
var myFn = new fn;
return myFn;
}
and the expected behavior would it be :
sayHi('Hello') // ==> "Hello moe"
the thing is that the "new" keyword in givecontext returns an object instead of a function.
and I'm only getting a
undefined moe
Uncaught TypeError: object is not a function
I'm missing something ?
When you are using new fn it will call the function fn as the constructor of an object, and the result is the object that was created.
Basically this:
var myFn = new fn;
works as:
var myFn = {}; // create an object
fn.call(myFn); // call the constructor with the object as context
(There are more things going on of course, but that is the important stuff for now.)
So, the function giveContext doesn't give a context to a function and return it, instead it will call the function as a constructor of an object and return the object. The code inside the function will be called already (that's why there is a console output at all), and when you are trying to use the return vale from giveContext as a function you will get an error as it's not a function at all.
There is already a built in method bind that sets the context for a function:
sayHi = sayHi.bind({"name":"moe"});
(Note the support information for the method though, it's not supported in iE 8 for example.)
You can also do the same without the bind method by creating a function that calls the function:
function giveContext(f, obj) {
return function(){
return f.apply(obj, arguments);
};
}
Yes, JavaScript is object-oriented, so when you say new fn, it creates a new object. In your setup, your function has a name property, so you should be using "Hello " + sayHi.name to get the results you expect.
You're going to want to read though this to get a good overview: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript

Any difference between explicit and implicit return in javascript function?

Is there any difference when I explicitly return from a function vs. implicitly return?
Here's the code that puzzles me ATM:
function ReturnConstructor(arg){
// Private variable.
var privateVar = "can't touch this, return ctor.";
// This is what is being exposed to the outside as the return object
return {
print: function() {
console.log("ReturnConstructor: arg was: %s", arg);
}
};
}
function NormalConstructor(arg){
// Private variable.
var privateVar = "can't touch this, normal ctor";
// This is what is being exposed to the outside as "public"
this.print = function() {
console.log("NormalConstructor: arg was: %s", arg);
};
}
var ret = new ReturnConstructor("calling return");
var nor = new NormalConstructor("calling normal");
Both objects ('ret' & 'nor') seem the same to me, and I'm wondering if it's only personal preference of whomever wrote whichever article I've read so far, or if there's any hidden traps there.
When you use new, there's an implicit value. When you don't use new, there isn't.
When a function called with new returns an object, then that's the value of the new expression. When it returns something else, that return value is ignored and the object implicitly constructed is the value of the expression.
So, yes, there can be a difference.
Implicit return only happens for single statement arrow functions, except When arrow function is declared with {}, even if it’s a single statement, implicit return does not happen:
link

Is it possible to call function.apply without changing the context?

In some Javascript code (node.js specifically), I need to call a function with an unknown set of arguments without changing the context. For example:
function fn() {
var args = Array.prototype.slice.call(arguments);
otherFn.apply(this, args);
}
The problem in the above is that when I call apply, I'm change the context by passing this as the first argument. I'd like to pass args to the function being called without changing the context of the function being called. I essentially want to do this:
function fn() {
var args = Array.prototype.slice.call(arguments);
otherFn.apply(<otherFn's original context>, args);
}
Edit: Adding more detail regarding my specific question. I am creating a Client class that contains a socket (socket.io) object among other info pertaining to a connection. I am exposing the socket's event listeners via the client object itself.
class Client
constructor: (socket) ->
#socket = socket
#avatar = socket.handshake.avatar
#listeners = {}
addListener: (name, handler) ->
#listeners[name] ||= {}
#listeners[name][handler.clientListenerId] = wrapper = =>
# append client object as the first argument before passing to handler
args = Array.prototype.slice.call(arguments)
args.unshift(this)
handler.apply(this, args) # <---- HANDLER'S CONTEXT IS CHANGING HERE :(
#socket.addListener(name, wrapper)
removeListener: (name, handler) ->
try
obj = #listeners[name]
#socket.removeListener(obj[handler.clientListenerId])
delete obj[handler.clientListenerId]
Note that clientListenerId is a custom unique identifier property that is essentially the same as the answer found here.
If I understand you correctly:
changes context
| n | y |
accepts array n | func() | func.call() |
of arguments y | ???????? | func.apply() |
PHP has a function for this, call_user_func_array. Unfortunately, JavaScript is lacking in this regard. It looks like you simulate this behavior using eval().
Function.prototype.invoke = function(args) {
var i, code = 'this(';
for (i=0; i<args.length; i++) {
if (i) { code += ',' }
code += 'args[' + i + ']';
}
eval(code + ');');
}
Yes, I know. Nobody likes eval(). It's slow and dangerous. However, in this situation you probably don't have to worry about cross-site scripting, at least, as all variables are contained within the function. Really, it's too bad that JavaScript doesn't have a native function for this, but I suppose that it's for situations like this that we have eval.
Proof that it works:
function showArgs() {
for (x in arguments) {console.log(arguments[x]);}
}
showArgs.invoke(['foo',/bar/g]);
showArgs.invoke([window,[1,2,3]]);
Firefox console output:
--
[12:31:05.778] "foo"
[12:31:05.778] [object RegExp]
[12:31:05.778] [object Window]
[12:31:05.778] [object Array]
Simply put, just assign the this to what you want it to be, which is otherFn:
function fn() {
var args = Array.prototype.slice.call(arguments);
otherFn.apply(otherFn, args);
}
'this' is a reference to your function's context. That's really the point.
If you mean to call it in the context of a different object like this:
otherObj.otherFn(args)
then simply substitute that object in for the context:
otherObj.otherFn.apply(otherObj, args);
That should be it.
If you bind the function to an object and you use everywhere the bound function, you can call apply with null, but still get the correct context
var Person = function(name){
this.name = name;
}
Person.prototype.printName = function(){
console.log("Name: " + this.name);
}
var bob = new Person("Bob");
bob.printName.apply(null); //window.name
bob.printName.bind(bob).apply(null); //"Bob"
One way that you can work around the change of context that can happen in JavaScript when functions are called, is to use methods that are part of the object's constructor if you need them to be able to operate in a context where this is not going to mean the parent object, by effectively creating a local private variable to store the original this identifier.
I concede that - like most discussions of scope in JavaScript - this is not entirely clear, so here is an example of how I have done this:
function CounterType()
{
var counter=1;
var self=this; // 'self' will now be visible to all
var incrementCount = function()
{
// it doesn't matter that 'this' has changed because 'self' now points to CounterType()
self.counter++;
};
}
function SecondaryType()
{
var myCounter = new CounterType();
console.log("First Counter : "+myCounter.counter); // 0
myCounter.incrementCount.apply(this);
console.log("Second Counter: "+myCounter.counter); // 1
}
These days you can use rest parameters:
function fn(...args) {
otherFn(...args);
}
The only downside is, if you want to use some specific params in fn, you have to extract it from args:
function fn(...args) {
let importantParam = args[2]; //third param
// ...
otherFn(...args);
}
Here's an example to try (ES next version to keep it short):
// a one-line "sum any number of arguments" function
const sum = (...args) => args.reduce((sum, value) => sum + value);
// a "proxy" function to test:
var pass = (...args) => sum(...args);
console.log(pass(1, 2, 15));
I'm not going to accept this as an answer, as I'm still hoping for something more suitable. But here's the approach I'm using right now based upon the feedback on this question so far.
For any class that will be calling Client.prototype.addListener or Client.prototype.removeListener, I did added the following code to their constructor:
class ExampleClass
constructor: ->
# ...
for name, fn of this
this[name] = fn.bind(this) if typeof(fn) == 'function'
message: (recipient, body) ->
# ...
broadcast: (body) ->
# ...
In the above example, message and broadcast will always be bound to the new ExampleClass prototype object when it's instantiated, allowing the addListener code in my original question to work.
I'm sure some of you are wondering why I didn't just do something like the following:
example = new ExampleClass
client.addListener('message', example.bind(example))
# ...
client.removeListener('message', example.bind(example))
The problem is that every time .bind( ) is called, it's a new object. So that means that the following is true:
example.bind(example) != example.bind(example)
As such, the removeListener would never work successfully, thus my binding the method once when the object is instantiated.
Since you seem to want to be using the bind function as it is defined in Javascript 1.8.5, and be able to retrieve the original this object you pass the bind function, I recommend redefining the Function.prototype.bind function:
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
/** here's the additional code **/
fBound.getContext = function() {
return oThis;
};
/**/
return fBound;
};
Now you can retrieve the original context that you called the bind function with:
function A() {
return this.foo+' '+this.bar;
}
var HelloWorld = A.bind({
foo: 'hello',
bar: 'world',
});
HelloWorld(); // returns "hello world";
HelloWorld.getContext(); // returns {foo:"hello", bar:"world"};
I was just reminded of this question after a long time. Looking back now, I think what I was really trying to accomplish here was something similar to how the React library works with its automatic binding.
Essentially, each function is a wrapped bound function being called:
function SomeClass() {
};
SomeClass.prototype.whoami = function () {
return this;
};
SomeClass.createInstance = function () {
var obj = new SomeClass();
for (var fn in obj) {
if (typeof obj[fn] == 'function') {
var original = obj[fn];
obj[fn] = function () {
return original.apply(obj, arguments);
};
}
}
return obj;
};
var instance = SomeClass.createInstance();
instance.whoami() == instance; // true
instance.whoami.apply(null) == instance; // true
Just push properties directly to the function's object and call it with it's own "context".
function otherFn() {
console.log(this.foo+' '+this.bar); // prints: "hello world" when called from rootFn()
}
otherFn.foo = 'hello';
otherFn.bar = 'world';
function rootFn() {
// by the way, unless you are removing or adding elements to 'arguments',
// just pass the arguments object directly instead of casting it to Array
otherFn.apply(otherFn, arguments);
}

How can jQuery do method chaining? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
how does jquery chaining work?
This is a normal thing you would see in a jQuery code:
$("div.selected").html("Blah.");
So, in the above code, in the function $(), it has a function called html(). And what I don't understand is, what I normally will do is:
funcA("blah"); //normal function, cool.
funcA.funcB("blah"); //normal function in an object, still cool.
and now this is confusing:
funcA("blah").funcB("blah") //huh??
How can funcB knows the arguments in funcA?
How can jQuery achieve this?
Thanks.
//function returning an object is a possibility. bar has access to elem because of
// the shared scope
function foo ( elem ) {
return {
bar : function () {
return elem.id;
}
};
}
In this one, the foo function returns an object containing whatever methods you wish. So when you call foo, you receive this:
{
bar : function () {
return elem.id;
}
}
elem is present from your call to foo. If you were to add a console.log( elem ) at the top of bar, you'd see that it's the same thing as what you passed to foo.
//this is kinda how jQuery does it:
var foo = (function() {
function foo ( elem ) {
this.elem = elem;
}
foo.prototype.bar = function () {
return this.elem.id;
};
return function ( elem ) {
return new foo( elem );
};
}());
This is a little more complex, and actually divided into two.
function foo ( elem ) {
this.elem = elem;
}
foo.prototype.bar = function () {
return this.elem.id;
};
Who doesn't love prototypical inheritance mixed with classical inheritance names? Anyway...functions act as both regular functions and as constructors. Meaning, when called with the new keyword, two special things happen:
this inside of the foo refers to a freshly made copy of foo.prototype
foo.prototype is returned (unless foo returns an object)
Note that foo.prototype isn't a magic value. It's just like any other object property.
So, inside the foo function/constructor, we're merely setting foo.prototype.elem, but not directly. Think of it like this (a little inaccurate, but it'll do): foo.prototype is the blueprint of a product. Whenever you wish to make more, you use the blueprint - duplicate what's inside, pass it along. Inside of foo, this refers to such a replication of the blueprint.
However, by explicitly setting values on foo.prototype, we're altering the blueprint itself. Whenever foo is called, it'll be called with this altered blueprint.
Finally, once foo is finished, the replication (the duplicated blueprint, but after foo has done stuff with it) is returned. This replication contains the original blueprint, and everything else we might have added - in this example, elem.
var foo = (function() {
...
return function ( elem ) {
return new foo( elem );
};
}());
We create a nameless function and immediately execute it.
(function () {
console.log( 'meep' );
}());
//is the equivalent of:
var something = function () {
console.log( 'meep' );
};
something();
something = undefined; //we can no longer use it
//and of this
function () {
console.log( 'meep' );
}(); //<--notice the parens
//however, it's considered good practice to wrap these self-executing-anonymous-functions
// in parens
Like all other functions, they can return values. And these values can be captured into variables.
var answer = (function () {
return 42;
}());
answer ==== 42;
var counter = (function () {
var c = 0;
return function () {
return c++;
};
}());
//counter is now a function, as a function was returned
counter(); //0
counter(); //1
counter(); //2...
So:
var foo = (function () {
...
return function ( elem ) {
...
};
}());
Returns a function which receives an argument, and that function is now assigned to foo.
The insides of the function:
return new foo( elem );
Is to ensure the special conditions I've spoken about above - it ensures that a new copy of the blueprint is manufactured, by explicitly doing the new operation. This can actually be replicated like this:
function foo ( elem ) {
this.elem = elem;
}
foo.prototype.bar = function () {...};
As long as you always call foo with the new keyword.
When you do funcA("blah").funcB("blah"), then funcB is called on whatever funcA returns. So you have funcA return some object that has a funcB, which is then called.
In the case of jQuery, most jQuery functions return the jQuery object, so function calls can be chained as much as you like. Many jQuery functions are designed to modify the contents of the jQuery object that is returned. So in your example, it's not the case that the call to html() "knows about" what was passed to the $() function. Rather, the $() function returns a jQuery object that points to the DOM elements that match the given selector. Further calls to functions on that jQuery object, then, will affect those selected elements.
Most functions in jquery return a jquery object which contains a set of elements. html doesn't know the arguments of $() exactly, it's more that the result of $() has a set of elements which are created based on the parameter passed to $().
In your example of funcA and funcB though, you could easily have funcA return an object which has a function named funcB. This object could also contain the value passed to funcA and then a call to funcB could "know" that value as well.
http://jsfiddle.net/ScENm/
function funcA(arg1) {
var enclosedVariable= arg1;
return {
funcB: function () {
alert(enclosedVariable);
}
};
}
Here is a quick and dirty example. ^^
funcA takes an argument and saves it then returns an object containing a single function. It has been "enclosed" and now funcB has access to this.
Technically you don't even have to save it... arg1 is available to funcB as well.
You should research chaining, it's what you're describing. You can google "jQuery chaining" to get started. Also check out jQuery's pluging tutorial for some more info
A function isn't anything special, you can return a function inside an object. For a quick example:
function $() {
return {
html: function() {
}
};
}
$().html(); // You just called the function!
jQuery doesn't have anything special in it. When you call a function in jQuery that doesn't return a value, it usually returns the jQuery object it was called on, like so:
var obj = {
doSomething: function() {
return this;
},
doSomethingElse: function() {
alert('Hi!');
}
};
obj.doSomething().doSomethingElse(); // Alerts "Hi!"
because again, it's just an object.
Chaining is generally done on the basis of the object that a method should return. If object A be an instance of class A and a method in it returns object A then the returned object can again be applied to the same class and this can be arranged in a chaining fashion. Or say object of class A returns object of class B then, the returned object can be applied to the method of class B.
objectOfA->methodOfA(arg)->methodOfB(args);
In this case if objectOfA->methodOfA(arg) returns object of class B and hence the method of class B can be called upon it and chained as above.
In your case,
$('div.selected').html('Blah ..')
Here $('div.selected') return a jquery element object(or array of object); upon which the method .html() can be applied since the method is only applicable to element object of jquery. It is just chaining as other programming languages do.
In case of PHP this case looks like,
$class->method1(argument)->method(2)
In this case, if class A has two methods method1 and method2 and method1 return the instance of its own then method 2 is again applicable to it.
This can be related to a function as well. Lets us suppose I have a function as such;
def function1(name):
return name
def function2(arg):
print len(name)
Now, this two functions can be chained simply as,
function2(function1('My Name is blah ...'))
Since the function1 returns a value, the type of the value must match to the input argument of function2 and this is how object work.

Categories

Resources