What is 'typeof define === 'function' && define['amd']' used for?

What is 'typeof define === 'function' && define['amd']' used for?

What purpose does the following code serve? What does factory function do here? Here root is window object. Is factory a default java script function? In what kind of scenarios this type of code can be used. This code is from toggle.js from Simon Tabor. Zepto and ender are libraries. Is this mostly used in libraries.

   if (typeof define === 'function' && define['amd']) {
        define(['jquery'], factory);
     } else {
      factory(root['jQuery'] || root['Zepto'] || root['ender'] || root['$']|| $);
    }

 

回答:

This code checks for the presence of require.js, a JavaScript dependency management library.

If 'define' is not undefined and it is a function and 'amd' (asynchronous module definition) is also defined then the code assumes that require.js is in play.

If this is so then it defines 'factory' and passes jQuery to it as a dependency. Otherwise it sets up the dependencies that the code needs by attaching them to the root object.

As for what 'factory' is: it is not defined by the Javascript framework, it will be a function in the same file most likely. It will take the parameter jQuery.

 

Why is function(global, factory) used in so many JS libraries?

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?

 

回答:

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.

 

IIFE

An IIFE (Immediately Invoked Function Expression) is a JavaScript function that runs as soon as it is defined.

(function () {
    statements
})();

It is a design pattern which is also known as a Self-Executing Anonymous Function and contains two major parts:

  1. The first is the anonymous function with lexical scope enclosed within the Grouping Operator (). This prevents accessing variables within the IIFE idiom as well as polluting the global scope.
  2. The second part creates the immediately invoked function expression () through which the JavaScript engine will directly interpret the function.

 

Examples:

The function becomes a function expression which is immediately executed. The variable within the expression can not be accessed from outside it.

(function () {
    var aName = "Barry";
})();
// Variable aName is not accessible from the outside scope
aName // throws "Uncaught ReferenceError: aName is not defined"

Assigning the IIFE to a variable stores the function's return value, not the function definition itself.

var result = (function () {
    var name = "Barry";
    return name;
})();
// Immediately creates the output:
result; // "Barry"
  1. Learn about it
    1. Quick example (at the end of the "Functions" section, right before "Custom objects")
  2. Wikipedia articles
    1. IIFE
  3. Glossary
    1. Function
    2. Self-Executing Anonymous Function

 

posted @ 2019-06-28 15:31  ChuckLu  阅读(3200)  评论(0编辑  收藏  举报