24

In so many JavaScript libraries, I see global, factory as parameters of functions.
Eg:

jQuery:

( function( global, factory ) {

    "use strict";

    if ( typeof module === "object" && typeof module.exports === "object" ) {
//...

Vue.js:

(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  typeof define === 'function' && define.amd ? define(factory) :
  (global = global || self, global.Vue = factory());
}(this, function () { 'use strict';

  /*  */

// ...

There probably are much more examples...

My question is: Why is the global and factory used as parameters so often and what are they?

Angshu31
  • 1,172
  • 1
  • 8
  • 19
  • 3
    Those specific names are probably the output of some module bundler, but look up “JavaScript UMD” for a good starting point. – Ry- Feb 23 '20 at 17:50
  • 2
    It's the [UMD pattern](https://github.com/umdjs/umd) header – Bergi Feb 23 '20 at 17:50
  • You have some missing code to fully explain jQuery but you can clearly see that `factory` is `function () { 'use strict'; /* */ ...` – slebetman Feb 23 '20 at 17:51
  • 1
    @slebetman I'm afraid I don't get what you're trying to say. – Angshu31 Feb 23 '20 at 17:57
  • 1
    You can see in your own code example, `global` is `this` and `factory` is `function () {...`. The code declares a function, for our purposes let's give it a name `foo` - `function foo (global, factory) {...}`. Then it calls it `foo(this, function () { 'use strict' ...`. But it does so without giving it a name like we did so it looks like this: `(function (global, factory) {...}( this, function () {'use strict'; ...})`. It is basically an IIFE – slebetman Feb 23 '20 at 18:02
  • @slebetman if the function is declared without a name how does it get called? will the function get called immediately when we import the script? – Zennichimaro Jan 25 '22 at 02:05
  • ah nvm, it is immediately called, the term is IIFE (Immediately Invoked Function Expression), sorry this is first time I hear it – Zennichimaro Jan 25 '22 at 02:12

3 Answers3

26

As mentioned by several people in the comments, the real answer is that this is the structure of UMD modules.

I'm writing this as an answer primarily because it's hard to illustrate this in comments. But you can clearly see what the code is doing in your Vue.js example:

    ┌──────────────────┐       ┌──────────────────┐
    │                  ▼       ▼                  │
    │    (function (global, factory) {            │
    │                                             │
    │                                             │
    │        /* deleted for clarity */            │
    │                 ┌───────────────────────────┘
    │                 │
    │    }(this, function () { 'use strict';
    │       │
    └───────┘
             /* */

         })

So basically it is an IIFE. You can rewrite this construct more clearly if you give the anonymous functions names:

// rename function () { 'use strict' ...
function Vue () { 'use strict';
    /* */
}

// rename function (global, factory) ...
function UMD (global, factory) {
    /* deleted for clarity */ 
}

UMD(this, Vue);

So global is basically this which when referenced from outside of any function points to the global object (window in browsers and not named in node.js) and factory is a function that creates the Vue.js object (or jQuery in the case of jQuery). Basically factory is the implementation of the library.

This structure is written in such a way as not to create any unnecessary variables or functions in the global scope and thus avoid polluting the global scope and avoid variable/function name clashes with other libraries.

As for why it assigns this to global? That's because window is (was?) a completely unprotected variable in global scope (that's why node.js does not give it a name) and any 3rd party code can overwrite it with a different thing or modify it. If you want the original global object of the browser while using unknown 3rd party code you need to use this this trick.

jdlm
  • 6,327
  • 5
  • 29
  • 49
slebetman
  • 109,858
  • 19
  • 140
  • 171
  • Thanks, that makes a lot of sense. – Angshu31 Feb 23 '20 at 18:24
  • Thanks for the nice explanation, can you explain more of your last paragraph? How come you can still get the original global obj with the `this` trick, if `window` is already polluted then `this` will also be polluted right? and shouldn't the renamed code become `UMD(window, Vue);` instead if we want to pass in the `window`? – Zennichimaro Jan 25 '22 at 02:10
  • 1
    @Zennichimaro Not quite. The global object is an internal C++ construct. In environments like Rhino and Nodejs the global object has no name. In Browsers the `window` variable is a pointer to the global object. Now, browsers could have just made it a regular pointer thus modifying `window` would modify the global object but it looks like `window` just inherits from the global object. If you replace `window.getElementById()` for example the `this` trick will get the original `getElementById()` function because `getElementById()` is actually a global function, not just a property of `window` – slebetman Jan 25 '22 at 05:13
  • 1
    @Zennichimaro Basically, there is a scope mechanism that C++ implements internally as objects and the global scope is the C++ global object. Javascript exposes all members of the global scope (and thus object) to the `window` variable (which itself belongs to global scope). It looks like `window` is not used by C++ internally to represent global scope. – slebetman Jan 25 '22 at 05:15
4

i created tiny lib for better understand by slebetman answare

   (function (global, factory) {            
    typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
    typeof define === 'function' && define.amd ? define(factory) :
    global.tinylib= factory();         

    } (this,function() {

// your code shoud place here
    }))

eg: this is simple i created library

(function (global, factory) {            
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = 
factory() :
    typeof define === 'function' && define.amd ? define(factory) :
    global.tinylib = factory();         

    } (this,function() {
 -----------------------------------------mylibrary code start------------------    
 var tinylib= (function(el) {
 var obj={}
 var myelement=el

 obj.setColor=(color)=>{
 myelement.style.color=color;
  }
    return obj;
 -----------------------------------------mylibrary code end------------------    

  })
 return tinylib;
    }))

Usage of created Library

import {tinylib} from 'tinylib'

initialize:

var lib=tinylib(document.getElementById('color')) //now we use lib variable whenever we want to invoke example showen below

usage:

lib.setColor('red')
Balaji
  • 9,657
  • 5
  • 47
  • 47
1

In addition to the other answers, I thought that it may be worth mentioning that esbuild is adding support soon for the 'global' and 'factory' ('umd') syntax.

https://github.com/evanw/esbuild/issues/507

Jorvy
  • 69
  • 4
  • 1
    This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. - [From Review](/review/late-answers/32720294) – Geshode Sep 20 '22 at 07:38