0

I've got a school assignment of creating an app and one of the restrictions were that only one global variable was allowed, named "App". So I need to put the whole JS inside this variable.

I thought of doing something like:

App = function() { this.test = () => alert("test"); }

And then calling it with App.test().

But this doesn't work, the error I'm getting is:

Uncaught TypeError: App.test is not a function at HTMLLIElement.onclick (index.html:25)

Am I doing something wrong?

Andy
  • 61,948
  • 13
  • 68
  • 95
Nir Tzezana
  • 2,275
  • 3
  • 33
  • 56
  • Possible duplicate of [JavaScript module pattern with example](https://stackoverflow.com/questions/17776940/javascript-module-pattern-with-example) – yuriy636 Aug 12 '17 at 16:12

5 Answers5

5

You need to define your app in a variable as an object and then you can use those members of the object such as:

// Object creation
window.App = {};

Then you add more properties like functions or variables and use it later inside of that variable.

window.App.test = function() {
   alert('test');
}

window.App.variable = 'my variable';

console.log( App.test() );
console.log( App.variable );

Another thing is you can omit the word window from App.

Crisoforo Gaspar
  • 3,740
  • 2
  • 21
  • 27
3

To be able to use your function that contains this.test..., you'll need to use it as a "constructor function" because this in a function declaration means "instance property", meaning you will need to explicitly create an instance of App with the new keyword:

    // Declare the global
    var App = function() { this.test = () => alert("test"); }
    
    // Make an instance of an object via the constructor function
    var myApp = new App();
    
    // Invoke the functionality via the instance
    myApp.test()

Or, set up App as an object, connect that object to the Global window object and set test as a property of App all without any instance properties (this references), which avoids having to make the explicit instance:

// Declare the global property as an Object
// and set up a "test" property that stores
// a function in that object:
window.App = { test: function(){alert("test");}}

// Invoke the functionality directly
App.test()
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
3

Keeping most of your approach as it is, you could return an object that has functions as properties.

App = function() { 
  return {
    test: () => alert("test"),
    test2: () => alert("test2")
  };
}

App().test();
App().test2();
Nisarg Shah
  • 14,151
  • 6
  • 34
  • 55
0

The test function is not defined before executing the App function:

App = () => test = () => alert("test")
<button onclick='App(); test()'>:</button>

App can be defined as object instead:

App = { test: () => alert("test") }
<button onclick='App.test()'>:</button>
Slai
  • 22,144
  • 5
  • 45
  • 53
0

Just to piggyback on to what the other answers have suggested, this technique is most commonly used (in browser developement) when you "namespace" some JS code. Namespacing is useful because it helps the developer reduce global variable pollution by adding all their code under one namespace under window.

This also helps the developer modularise the code.

Here's a pattern you might see from time to time that adds code to a single namespace under window.

// This first function is what's known as an Immediately-invoked
// function expression (IIFE). `window` is passed in as an argument
// to the function - all other declared variables are local to the scope
// of the function so you don't get anything leaking to global.
// PS, the semi-colon is there before the opening parenthesis to prevent
// any errors appearing if you minimise your code
;(function (window) {

  // Here we declare something new to add to the namespace
  // It could be another object, a string, an array, or a constructor
  // like Model
  function Model() {...}

  // If namespace `window.app` doesn't exist instantiate it with
  // an empty object. If it _does_ exist it probably means that another
  // module like this one has already been added to the namespace.
  window.app = window.app || {};

  // Then assign your new module as a property under that namespace
  window.app.Model = Model;

})(window);

You can then use it later something like this:

var model = new app.Model();
var game = new Game(model);

For further reading: Addy Osmani on namespacing.

Andy
  • 61,948
  • 13
  • 68
  • 95