What is this code construct wrapping the parts of a library and what is it useful for?
Asked Answered
S

6

39

I imitated a library and was able to write following code. This code created 'c' object to which 'a' function is assigned. So, to call 'a', I will have to write c.a().

Also, I was able to add more functions to this 'c' object. I want to understand what is happening in this code. It doesn't look like normal object oriented programming. What is this type of javascript programming called?

var c = (function(c) {
    if (c === undefined) {
        c = {};
    }

    function a() {
        alert(1);
    }
    c.a = a;
    return c;
}(c));
Spallation answered 15/1, 2015 at 9:48 Comment(4)
@abelenky triple equals prevents type coercion in JavaScript. '1'==1 =true '1'===1 = falseManama
So many upvotes for a question that will never help anyone else, and that is asking about four questions at once, all of which have been asked for. Have a downvote.Issi
I didn't know module pattern before, learned only after posting this question. If we could modify the title of the question to something meaningful so that people can come to this question and learn, it would be great. May be then, people might not need to ask repeated question.Spallation
@Spallation I changed the title, trying to make it more useful. If you don't like it, you may revert my edit.Cobham
D
42

It's a module pattern. You'll see many variants of that pattern, so it's essential to understand what really happens, you can't just imitate one.

The point of this piece of code is to complete an object c (typically your global library). You probably have many similar pieces of code in your application, all building pieces of c, probably each of those in its own file.

In case the library object c, which is passed as argument to the function, doesn't exist yet ( c === undefined ), it is created. This makes it possible to not depend of the execution order or of a preexecuted file.

The right part of the assignment is an IIFE (Immediately Invoked Function Expression), that is a function which is immediately called. The advantage of this construction is that it creates a scope in which variables (for example the a function) can be declared without polluting the external (global) scope. Here the point is moot as a is externalized anyway but a module typically depends on several internal (private) functions and variables.

A detail that might need an explanation : all those files look like they define a new variable c but there's no problem here, even if the files are concatenated : a var statements doesn't define a new variable if it already exists (a variable is defined for the whole scope, here globally, even before the point of declaration).

Another way to write this would have been

var c = c || {}; // ensure the c variable is defined, and initialize its value it if necessary

(function() { // let's use an IIFE to have a protected scope and not pollute the global one
  function a() {
    alert(1);
  }
  c.a = a; // let's augment c
})();

This one is probably clearer as

  • it explicitly separates the two steps (c initialization and c completion using an IIFE)
  • it doesn't depend on two c variables with the same name
  • it is less verbose
Digger answered 15/1, 2015 at 9:53 Comment(2)
"pollute global scope", nice phraseBreathing
I like this answer more as it also explains why I would want to use it. Being a pure Node dev, this pattern was completely unknown to me.Necaise
J
36

Here's the same code with added comments on what every line does, and what happens when we pass it.

//Here, we're defining a function that will return an object.
//its only parameter is named 'c'
//this is confusing, since the parameter has the same name as the global definition of the function.

//the var c definition is the global definition. the function parameter is not.
//so every reference to anything named 'c' inside the function definition is local. 
var c = (function(c) 
{
  //if c (the c we passed as a parameter) is not yet defined
  if (c === undefined) {
    //define c as an object
    c = {};
  }

  //define a function
  function a() {
    alert(1);
  }
  //attach it to the object
  c.a = a;

  //return the object
  return c;
}(c)); // call the constructor we just defined, using the global definition of `c`.
       // the first time we pass this point, c as a variable is still undefined.
Jaella answered 15/1, 2015 at 9:56 Comment(3)
Can you please specify which cs are global and which are local. Specifically in the if(c === undefined){c={}}Obit
I feel I need to downvote for the first comment paragraph. Neither is this a class-style constructor function, nor does it get passed to itself, nor does it have a name at all. This sounds as if you haven't understood yourself what's going on…Nitro
@Nitro i agree that the wording could be better. bear with me.Jaella
T
13
var c = (function(c) {
    if (c === undefined) {
        c = {};
    }

    function a() {
        alert(1);
    }
    c.a = a;
    return c;
}(c));

Let us take it step by step.

var c =

initializing a variable named c. Note that at this point, if a variable named as c is already initialized, c would refer to that value only until we reach the end of this declaration.

( .... )

This means that whatever is inside should be treated as an expression.

function(c)

means that this "expression" is a function which takes an argument. This argument would henceforth be referred by the name c until the function is over. Any variable with the name c which was declared outside the function scope would thus not be accessible directly here. Although if it is in the global scope, and the global scope happens to be the window object, it can referred to as window.c.

if (c === undefined) { ... }

checks if the argument passed to it is undefined or not. Would return true if it is undefined, and thus execute what ever is inside the if block.

c = {}

set the variable c to an empty object. So if the argument was (passed or) undefined, we define it ourselves here (and we define it to an empty object....).

function a() { alert(1); }

declared a function with the name a calling which willl result in alerting the numeral 1. Note that this is just a function declaration. We haven't called the function yet.

c.a = a

The argument c is now assigned a property named a which refers to the function a we just created.

return c

break out of the function with the return value as the final value of c, after undergoing the changes we did to the argument passed.

(fun...}(c))

call the function that we just created, and pass to it as an argument the present value of c. since we called the function as an expression, the result of this expression would be whatever is the return value of the function. And our function returns an object (which we passed to it), after assigning a property to it.

Since this expression was equated to the variable c, the return value of the expression (which is the return value of the function), is now held with the variable c.

If you read all this properly, you would know that the variable c would now hold an object, which would have a property a which is a function which alerts the number 1. And that object also retains the properties it might have had before.

If we de-uglify this code to make it readable just by making the variable names descriptive:

var myObject = (function(someObject) {
    if (someObject === undefined) {
        someObject = {};
    }
    function alertOne () {
        alert(1);
    }
    someObject.alertOne = alertOne;
    return someObject;
}(myObject));

This show is an episode from the series module revealing pattern, which tells us how to add additional properties to an object, which was declared previously, in an elegant manner without polluting the global scope. Starring Immediately Invoked Function Expressions (IIFEs).

Toenail answered 15/1, 2015 at 21:39 Comment(0)
W
5

Why at the end, we wrote (c)) again?

This is named immediately invoked function.

(function(received argument){

     //some code here.......

})(passed argument)  //<-- here the function is invoked 

c is the passed argument. The function is invoked immediately when it is created. This type of declaration is used to keep variables private and to keep the global namespace clean.

The pattern in your code is used to create modules.

............Now come to your code :............

if passed argument is undefined : .............

Firstly, ...}(c)) this part of the immediately invoked function is invoked.It is passed with an argument called c which is not defined yet. (function(c){... part receive this c argument .

Here at first passed argument c is undefined.So if(c==undefined) is triggered .At this point using c={} statement,undefined object c is assigned an empty object.

Here function a() { //... } is a private method created inside a module.It can't be accessed globally.

Private method a is is made globally available by assigning it to c using c.a=a statement.Thus when the object will return you can call this method on global context.

Thus newly created empty object c is assigned a method called a.Then it returns and var c receive this object.

if passed argument is not undefined : ............

But if passed c is not undefined say,if an object is passed,then no new object is created .I mean if if(c==undefined) is falsy.So , it is not executed.I mean no new empty object is created.Then Passed object is assigned a new method called a using c.a=a

It is simple as that.

The code below is much simpler version of your code. It will automatically send an empty object if it is initially undefined.So you don't have to take the trouble of checking whether it is undefined or not.It is called loose augmentation.

var c = (function(c) {

    function a() {
        alert(1);
    }
    c.a = a;
    return c;
}(c || {} ));
Wallsend answered 15/1, 2015 at 9:56 Comment(0)
A
4

This article written by Ben Cherry helped me understand this type of pattern: http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html

Excerpt from the article:

Anonymous Closures

This is the fundamental construct that makes it all possible, and really is the single best feature of JavaScript. We’ll simply create an anonymous function, and execute it immediately. All of the code that runs inside the function lives in a closure, which provides privacy and state throughout the lifetime of our application.

(function () {
    // ... all vars and functions are in this scope only
    // still maintains access to all globals
}());

Notice the () around the anonymous function. This is required by the language, since statements that begin with the token function are always considered to be function declarations. Including () creates a function expression instead.

Global Import

JavaScript has a feature known as implied globals. Whenever a name is used, the interpreter walks the scope chain backwards looking for a var statement for that name. If none is found, that variable is assumed to be global. If it’s used in an assignment, the global is created if it doesn’t already exist. This means that using or creating global variables in an anonymous closure is easy. Unfortunately, this leads to hard-to-manage code, as it’s not obvious (to humans) which variables are global in a given file.

Luckily, our anonymous function provides an easy alternative. By passing globals as parameters to our anonymous function, we import them into our code, which is both clearer and faster than implied globals. Here’s an example:

(function ($, YAHOO) {
    // now have access to globals jQuery (as $) and YAHOO in this code
}(jQuery, YAHOO));

Module Export

Sometimes you don’t just want to use globals, but you want to declare them. We can easily do this by exporting them, using the anonymous function’s return value. Doing so will complete the basic module pattern, so here’s a complete example:

var MODULE = (function () {
    var my = {},
        privateVariable = 1;

    function privateMethod() {
        // ...
    }

    my.moduleProperty = 1;
    my.moduleMethod = function () {
        // ...
    };

    return my;
}());

Notice that we’ve declared a global module named MODULE, with two public properties: a method named MODULE.moduleMethod and a variable named MODULE.moduleProperty. In addition, it maintains private internal state using the closure of the anonymous function. Also, we can easily import needed globals, using the pattern we learned above

Amphitryon answered 15/1, 2015 at 9:57 Comment(2)
While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes.Fortyish
Added an excerpt from the linked article as suggest by @a-lAmphitryon
M
1

What you are doing is declaring an anonymous function and then calling it with a parameter called c and assigning it to a variable also called c, which is very confusing :-)

Renaming variables this is what you have:

var result=(function (input_parameter){...} (parameter_used_to_call_my_function));

The final (c) you ask about is the parameter to call the function. It's easier to see if you use a longer syntax:

var my_function=function(input_parameter){...};
var result=my_function(result);

It is also worth noting that you are calling my_function using result (although you called it c) as a parameter, which is also the name of the variable you just created to store the return value of the function. JS goes along with this because it is not strict with how you handle variables, but this is a confusing way to write code. You are declaring a variable and passing it (the variable with that name, which at that point should not exist) as a parameter to your function just in case it was declared earlier (and taking care of that case inside the function, which at least is consistent).

What happens inside my_function is that you check is your parameter had a previous value (what I explained if the previous paragraph); if it was undefined you initialize it to an empty object. Then you append the a function to input_parameter and return it.

I don't know if there is a name for this type of programming, but using the same variable name for different things doesn't look like a good idea :-)

Maitilde answered 15/1, 2015 at 12:40 Comment(3)
"What you are doing is declaring a function called c". The first sentence is completely wrong. You just misread the code.Cobham
If you read the rest of the sentence it is correct. If the word "declaring" is what you consider innacurate, you are declaring it, just in the very limited scope of the assignation instruction.Maitilde
no, the function isn't called c. And the rest of your answer looks like you're a little lost about what really happens. I'd suggest you read a little about IIFE (see link in my answer), or maybe newuser's answer.Cobham

© 2022 - 2024 — McMap. All rights reserved.