How can I create static variables in Javascript?
30 Answers
If you come from a class-based, statically typed object-oriented language (like Java, C++ or C#) I assume that you are trying to create a variable or method associated to a "type" but not to an instance.
An example using a "classical" approach, with constructor functions maybe could help you to catch the concepts of basic OO JavaScript:
function MyClass () { // constructor function
var privateVariable = "foo"; // Private variable
this.publicVariable = "bar"; // Public variable
this.privilegedMethod = function () { // Public Method
alert(privateVariable);
};
}
// Instance method will be available to all instances but only load once in memory
MyClass.prototype.publicMethod = function () {
alert(this.publicVariable);
};
// Static variable shared by all instances
MyClass.staticProperty = "baz";
var myInstance = new MyClass();
staticProperty
is defined in the MyClass object (which is a function) and has nothing to do with its created instances, JavaScript treats functions as first-class objects, so being an object, you can assign properties to a function.
UPDATE: ES6 introduced the ability to declare classes through the class
keyword. It is syntax sugar over the existing prototype-based inheritance.
The static
keyword allows you to easily define static properties or methods in a class.
Let's see the above example implemented with ES6 classes:
class MyClass {
// class constructor, equivalent to
// the function body of a constructor
constructor() {
const privateVariable = 'private value'; // Private variable at the constructor scope
this.publicVariable = 'public value'; // Public property
this.privilegedMethod = function() {
// Public Method with access to the constructor scope variables
console.log(privateVariable);
};
}
// Prototype methods:
publicMethod() {
console.log(this.publicVariable);
}
// Static properties shared by all instances
static staticProperty = 'static value';
static staticMethod() {
console.log(this.staticProperty);
}
}
// We can add properties to the class prototype
MyClass.prototype.additionalMethod = function() {
console.log(this.publicVariable);
};
var myInstance = new MyClass();
myInstance.publicMethod(); // "public value"
myInstance.additionalMethod(); // "public value"
myInstance.privilegedMethod(); // "private value"
MyClass.staticMethod(); // "static value"
You might take advantage of the fact that JS functions are also objects -- which means they can have properties.
For instance, quoting the example given on the (now vanished) article Static variables in Javascript:
function countMyself() {
// Check to see if the counter has been initialized
if ( typeof countMyself.counter == 'undefined' ) {
// It has not... perform the initialization
countMyself.counter = 0;
}
// Do something stupid to indicate the value
alert(++countMyself.counter);
}
If you call that function several time, you'll see the counter is being incremented.
And this is probably a much better solution than poluting the global namespace with a global variable.
And here is another possible solution, based on a closure : Trick to use static variables in javascript :
var uniqueID = (function() {
var id = 0; // This is the private persistent value
// The outer function returns a nested function that has access
// to the persistent value. It is this nested function we're storing
// in the variable uniqueID above.
return function() { return id++; }; // Return and increment
})(); // Invoke the outer function after defining it.
Which gets you the same kind of result -- except, this time, the incremented value is returned, instead of displayed.
I've seen a couple of similar answers, but I'd like to mention that this post describes it best, so I'd like to share it with you.
Here's some code taken from it, which I have modified to get a complete example which hopefully gives benefit to the community because it can be used as a design template for classes.
It also answers your question:
function Podcast() {
// private variables
var _somePrivateVariable = 123;
// object properties (read/write)
this.title = 'Astronomy Cast';
this.description = 'A fact-based journey through the galaxy.';
this.link = 'http://www.astronomycast.com';
// for read access to _somePrivateVariable via immutableProp
this.immutableProp = function() {
return _somePrivateVariable;
}
// object function
this.toString = function() {
return 'Title: ' + this.title;
}
};
// static property
Podcast.FILE_EXTENSION = 'mp3';
// static function
Podcast.download = function(podcast) {
console.log('Downloading ' + podcast + ' ...');
};
Given that example, you can access the static properties/function as follows:
// access static properties/functions
console.log(Podcast.FILE_EXTENSION); // 'mp3'
Podcast.download('Astronomy cast'); // 'Downloading Astronomy cast ...'
And the object properties/functions simply as:
// access object properties/functions
var podcast = new Podcast();
podcast.title = 'The Simpsons';
console.log(podcast.toString()); // Title: The Simpsons
console.log(podcast.immutableProp()); // 123
Note that in podcast.immutableProp(), we have a closure: The reference to _somePrivateVariable is kept inside the function.
You can even define getters and setters. Take a look at this code snippet (where d
is the object's prototype for which you want to declare a property, y
is a private variable not visible outside of the constructor):
// getters and setters
var d = Date.prototype;
Object.defineProperty(d, "year", {
get: function() {return this.getFullYear() },
set: function(y) { this.setFullYear(y) }
});
It defines the property d.year
via get
and set
functions - if you don't specify set
, then the property is read-only and cannot be modified (be aware you will not get an error if you try to set it, but it has no effect). Each property has the attributes writable
, configurable
(allow to change after declaration) and enumerable
(allow to use it as enumerator), which are per default false
. You can set them via defineProperty
in the 3rd parameter, e.g. enumerable: true
.
What is also valid is this syntax:
// getters and setters - alternative syntax
var obj = { a: 7,
get b() {return this.a + 1;},
set c(x) {this.a = x / 2}
};
which defines a readable/writable property a
, a readonly property b
and a write-only property c
, through which property a
can be accessed.
Usage:
console.log(obj.a); console.log(obj.b); // output: 7, 8
obj.c=40;
console.log(obj.a); console.log(obj.b); // output: 20, 21
Notes:
To avoid unexpected behaviour in case you've forgotten the new
keyword, I suggest that you add the following to the function Podcast
:
// instantiation helper
function Podcast() {
if(false === (this instanceof Podcast)) {
return new Podcast();
}
// [... same as above ...]
};
Now both of the following instantiations will work as expected:
var podcast = new Podcast(); // normal usage, still allowed
var podcast = Podcast(); // you can omit the new keyword because of the helper
The 'new' statement creates a new object and copies all properties and methods, i.e.
var a=new Podcast();
var b=new Podcast();
a.title="a"; b.title="An "+b.title;
console.log(a.title); // "a"
console.log(b.title); // "An Astronomy Cast"
Note also, that in some situations it can be useful to use the return
statement in the constructor function Podcast
to return a custom object protecting functions the class internally relies on but which need to be exposed. This is explained further in chapter 2 (Objects) of the article series.
You can say that a
and b
inherit from Podcast
. Now, what if you want to add a method to Podcast that applies to all of them after a
and b
have been instanciated? In this case, use the .prototype
as follows:
Podcast.prototype.titleAndLink = function() {
return this.title + " [" + this.link + "]";
};
Now call a
and b
again:
console.log(a.titleAndLink()); // "a [http://www.astronomycast.com]"
console.log(b.titleAndLink()); // "An Astronomy Cast [http://www.astronomycast.com]"
You can find more details about prototypes here. If you want to do more inheritance, I suggest looking into this.
The article series I've mentioned above are highly recommended to read, they include also the following topics:
- Functions
- Objects
- Prototypes
- Enforcing New on Constructor Functions
- Hoisting
- Automatic Semicolon Insertion
- Static Properties and Methods
Note that the automatic semicolon insertion "feature" of JavaScript (as mentioned in 6.) is very often responsible for causing strange issues in your code. Hence, I would rather regard it as a bug than as a feature.
If you want to read more, here is a quite interesting MSDN article about these topics, some of them described there provide even more details.
What is interesting to read as well (also covering the topics mentioned above) are those articles from the MDN JavaScript Guide:
If you want to know how to emulate c# out
parameters (like in DateTime.TryParse(str, out result)
) in JavaScript, you can find sample code here.
Those of you who are working with IE (which has no console for JavaScript unless you open the developer tools using F12 and open the console tab) might find the following snippet useful. It allows you to use console.log(msg);
as used in the examples above. Just insert it before the Podcast
function.
For your convenience, here's the code above in one complete single code snippet:
let console = { log: function(msg) {
let canvas = document.getElementById("log"), br = canvas.innerHTML==="" ? "" : "<br/>";
canvas.innerHTML += (br + (msg || "").toString());
}};
console.log('For details, see the explaining text');
function Podcast() {
// with this, you can instantiate without new (see description in text)
if (false === (this instanceof Podcast)) {
return new Podcast();
}
// private variables
var _somePrivateVariable = 123;
// object properties
this.title = 'Astronomy Cast';
this.description = 'A fact-based journey through the galaxy.';
this.link = 'http://www.astronomycast.com';
this.immutableProp = function() {
return _somePrivateVariable;
}
// object function
this.toString = function() {
return 'Title: ' + this.title;
}
};
// static property
Podcast.FILE_EXTENSION = 'mp3';
// static function
Podcast.download = function(podcast) {
console.log('Downloading ' + podcast + ' ...');
};
// access static properties/functions
Podcast.FILE_EXTENSION; // 'mp3'
Podcast.download('Astronomy cast'); // 'Downloading Astronomy cast ...'
// access object properties/functions
var podcast = new Podcast();
podcast.title = 'The Simpsons';
console.log(podcast.toString()); // Title: The Simpsons
console.log(podcast.immutableProp()); // 123
// getters and setters
var d = Date.prototype;
Object.defineProperty(d, "year", {
get: function() {
return this.getFullYear()
},
set: function(y) {
this.setFullYear(y)
}
});
// getters and setters - alternative syntax
var obj = {
a: 7,
get b() {
return this.a + 1;
},
set c(x) {
this.a = x / 2
}
};
// usage:
console.log(obj.a); console.log(obj.b); // output: 7, 8
obj.c=40;
console.log(obj.a); console.log(obj.b); // output: 20, 21
var a=new Podcast();
var b=new Podcast();
a.title="a"; b.title="An "+b.title;
console.log(a.title); // "a"
console.log(b.title); // "An Astronomy Cast"
Podcast.prototype.titleAndLink = function() {
return this.title + " [" + this.link + "]";
};
console.log(a.titleAndLink()); // "a [http://www.astronomycast.com]"
console.log(b.titleAndLink()); // "An Astronomy Cast [http://www.astronomycast.com]"
<div id="log"></div>
Notes:
Some good tips, hints and recommendations about JavaScript programming in general you can find here (JavaScript best practices) and there ('var' versus 'let'). Also recommended is this article about implicit typecasts (coercion).
A convenient way to use classes and compile them into JavaScript is TypeScript. Here is a playground where you can find some examples showing you how it works. Even if you're not using TypeScript at the moment, you can have a look because you can compare TypeScript with the JavaScript result on a side-by-side view. Most examples are simple, but there is also a Raytracer example which you can try out instantly. I recommend especially looking into the "Using Classes", "Using Inheritance" and "Using Generics" examples by selecting them in the combobox - these are nice templates you can instantly use in JavaScript. Typescript is used with Angular.
To achieve encapsulation of local variables, functions etc in JavaScript, I suggest to use a pattern like the following (JQuery uses the same technique):
<html>
<head></head>
<body><script>
'use strict';
// module pattern (self invoked function)
const myModule = (function(context) {
// to allow replacement of the function, use 'var' otherwise keep 'const'
// put variables and function with local module scope here:
var print = function(str) {
if (str !== undefined) context.document.write(str);
context.document.write("<br/><br/>");
return;
}
// ... more variables ...
// main method
var _main = function(title) {
if (title !== undefined) print(title);
print("<b>last modified: </b>" + context.document.lastModified + "<br/>");
// ... more code ...
}
// public methods
return {
Main: _main
// ... more public methods, properties ...
};
})(this);
// use module
myModule.Main("<b>Module demo</b>");
</script></body>
</html>
Of course, you can - and should - put the script code in a separate *.js
file; this is just written inline to keep the example short.
Self-invocing functions (also known as IIFE = Immediately Invoked Function Expression) are described in more detail here.
Updated answer:
In ECMAScript 6, you can create static functions using the static
keyword:
class Foo {
static bar() {return 'I am static.'}
}
//`bar` is a property of the class
Foo.bar() // returns 'I am static.'
//`bar` is not a property of instances of the class
var foo = new Foo()
foo.bar() //-> throws TypeError
ES6 classes don't introduce any new semantics for statics. You can do the same thing in ES5 like this:
//constructor
var Foo = function() {}
Foo.bar = function() {
return 'I am static.'
}
Foo.bar() // returns 'I am static.'
var foo = new Foo()
foo.bar() // throws TypeError
You can assign to a property of Foo
because in JavaScript functions are objects.
The following example and explanation are from the book Professional JavaScript for Web Developers 2nd Edition by Nicholas Zakas. This is the answer I was looking for so I thought it would be helpful to add it here.
(function () {
var name = '';
Person = function (value) {
name = value;
};
Person.prototype.getName = function () {
return name;
};
Person.prototype.setName = function (value) {
name = value;
};
}());
var person1 = new Person('Nate');
console.log(person1.getName()); // Nate
person1.setName('James');
console.log(person1.getName()); // James
person1.name = 'Mark';
console.log(person1.name); // Mark
console.log(person1.getName()); // James
var person2 = new Person('Danielle');
console.log(person1.getName()); // Danielle
console.log(person2.getName()); // Danielle
The Person
constructor in this example has access to the private variable name, as do the getName()
and setName()
methods. Using this pattern, the name variable becomes static and will be used among all instances. This means calling setName()
on one instance affects all other instances. Calling setName()
or creating a new Person
instance sets the name variable to a new value. This causes all instances to return the same value.
If you are using the new class syntax then you can now do the following:
class MyClass {
static get myStaticVariable() {
return "some static variable";
}
}
console.log(MyClass.myStaticVariable);
aMyClass = new MyClass();
console.log(aMyClass.myStaticVariable, "is undefined");
This effectively creates a static variable in JavaScript.
If you want to declare static variables for creating constants in your application then I found following as most simplistic approach
ColorConstants = (function()
{
var obj = {};
obj.RED = 'red';
obj.GREEN = 'green';
obj.BLUE = 'blue';
obj.ALL = [obj.RED, obj.GREEN, obj.BLUE];
return obj;
})();
//Example usage.
var redColor = ColorConstants.RED;
About the class
introduced by ECMAScript 2015. The other answers are not totally clear.
Here is an example showing how to create a static var staticVar
with the ClassName
.var
synthax:
class MyClass {
constructor(val) {
this.instanceVar = val;
MyClass.staticVar = 10;
}
}
var class1 = new MyClass(1);
console.log(class1.instanceVar); // 1
console.log(class1.constructor.staticVar); // 10
// New instance of MyClass with another value
var class2 = new MyClass(3);
console.log(class1.instanceVar); // 1
console.log(class2.instanceVar); // 3
To access the static variable we use the .constructor
property that returns a reference to the object constructor function that created the class.
We can call it on the two created instances:
MyClass.staticVar = 11;
console.log(class1.constructor.staticVar); // 11
console.log(class2.constructor.staticVar); // 11 <-- yes it's static! :)
MyClass.staticVar = 12;
console.log(class1.constructor.staticVar); // 12
console.log(class2.constructor.staticVar); // 12
In addition to the rest, there's currently a draft (stage-2 proposal) on ECMA Proposals that introduces static
public fields in classes. (private fields were considered)
Using the example from the proposal, the proposed static
syntax will look like this:
class CustomDate {
// ...
static epoch = new CustomDate(0);
}
and be equivalent to the following which others have highlighted:
class CustomDate {
// ...
}
CustomDate.epoch = new CustomDate(0);
You can then access it via CustomDate.epoch
.
You can keep track of the new proposal in proposal-static-class-features
.
Currently, babel supports this feature with the transform class properties plugin which you can use. Additionally, though still in progress, V8
is implementing it.
You can create a static variable in JavaScript like this below. Here count
is the static variable.
var Person = function(name) {
this.name = name;
// first time Person.count is undefined, so it is initialized with 1
// next time the function is called, the value of count is incremented by 1
Person.count = Person.count ? Person.count + 1 : 1;
}
var p1 = new Person('User p1');
console.log(p1.constructor.count); // prints 1
var p2 = new Person('User p2');
console.log(p2.constructor.count); // prints 2
You can assign values to the static variable using either the Person
function, or any of the instances:
// set static variable using instance of Person
p1.constructor.count = 10; // this change is seen in all the instances of Person
console.log(p2.constructor.count); // prints 10
// set static variable using Person
Person.count = 20;
console.log(p1.constructor.count); // prints 20
There are 4 ways to emulate function-local static variables in Javascript.
Method 1: Using function object properties (supported in old browsers)
function someFunc1(){
if( !('staticVar' in someFunc1) )
someFunc1.staticVar = 0 ;
alert(++someFunc1.staticVar) ;
}
someFunc1() ; //prints 1
someFunc1() ; //prints 2
someFunc1() ; //prints 3
Method 2: Using a closure, variant 1 (supported in old browsers)
var someFunc2 = (function(){
var staticVar = 0 ;
return function(){
alert(++staticVar) ;
}
})()
someFunc2() ; //prints 1
someFunc2() ; //prints 2
someFunc2() ; //prints 3
Method 3: Using a closure, variant 2 (also supported in old browsers)
var someFunc3 ;
with({staticVar:0})
var someFunc3 = function(){
alert(++staticVar) ;
}
someFunc3() ; //prints 1
someFunc3() ; //prints 2
someFunc3() ; //prints 3
Method 4: Using a closure, variant 3 (requires support for EcmaScript 2015)
{
let staticVar = 0 ;
function someFunc4(){
alert(++staticVar) ;
}
}
someFunc4() ; //prints 1
someFunc4() ; //prints 2
someFunc4() ; //prints 3
The closest thing in JavaScript to a static variable is a global variable - this is simply a variable declared outside the scope of a function or object literal:
var thisIsGlobal = 1;
function foo() {
var thisIsNot = 2;
}
The other thing you could do would be to store global variables inside an object literal like this:
var foo = { bar : 1 }
And then access the variabels like this: foo.bar
.
To condense all class concepts here, test this:
var Test = function() {
// "super private" variable, accessible only here in constructor. There are no real private variables
//if as 'private' we intend variables accessible only by the class that defines the member and NOT by child classes
var test_var = "super private";
//the only way to access the "super private" test_var is from here
this.privileged = function(){
console.log(test_var);
}();
Test.test_var = 'protected';//protected variable: accessible only form inherited methods (prototype) AND child/inherited classes
this.init();
};//end constructor
Test.test_var = "static";//static variable: accessible everywhere (I mean, even out of prototype, see domready below)
Test.prototype = {
init:function(){
console.log('in',Test.test_var);
}
};//end prototype/class
//for example:
$(document).ready(function() {
console.log('out',Test.test_var);
var Jake = function(){}
Jake.prototype = new Test();
Jake.prototype.test = function(){
console.log('jake', Test.test_var);
}
var jake = new Jake();
jake.test();//output: "protected"
});//end domready
Well, another way to take a look to best practices in these things, is to just see how coffeescript translates these concepts.
#this is coffeescript
class Test
#static
@prop = "static"
#instance
constructor:(prop) ->
@prop = prop
console.log(@prop)
t = new Test('inst_prop');
console.log(Test.prop);
//this is how the above is translated in plain js by the CS compiler
Test = (function() {
Test.prop = "static";
function Test(prop) {
this.prop = prop;
console.log(this.prop);
}
return Test;
})();
t = new Test('inst_prop');
console.log(Test.prop);
There's another approach, which solved my requirements after browsing this thread. It depends on exactly what you want to achieve with a "static variable".
The global property sessionStorage or localStorage allows data to be stored for the life of the session, or for an indefinite longer period until explicitly cleared, respectively. This allows data to be shared among all windows, frames, tab panels, popups etc of your page/app and is much more powerful than a simple "static/global variable" in one code segment.
It avoids all hassle with the scope, lifetime, semantics, dynamics etc of top-level global variables, ie Window.myglobal. Don't know how efficient it is, but that's not important for modest amounts of data, accessed at modest rates.
Easily accessed as "sessionStorage.mydata = anything" and retrieved similarly. See "JavaScript: The Definitive Guide, Sixth Edition", David Flanagan, ISBN: 978-0-596-80552-4, Chapter 20, section 20.1. This is easily downloadable as a PDF by simple search, or in your O'Reilly Safaribooks subscription (worth its weight in gold).
Function's / classes allows only single constructor for its object scope.
Function Hoisting, declarations & expressions
Functions created with the Function constructor do not create closures to their creation contexts; they always are created in the global scope.
var functionClass = function ( ) { var currentClass = Shape; _inherits(currentClass, superClass); function functionClass() { superClass.call(this); // Linking with SuperClass Constructor. // Instance Variables list. this.id = id; return this; } }(SuperClass)
Closures - closure's copies are function with preserved data.
- Each closure's copies are created to a function with their own free values or references, Whenever you use function inside another function, a closure is used.
A closure in JavaScript is like maintaining a copy of all the local variables of its parent function by the innerFunctions.
function closureFun( args ) { // Local variable that ends up within closure var num = args; num++; return function() { console.log(num); } } var closure1 = closureFun( 5 ); var closure2 = closureFun( 777 ); closure1(); // 5 closure2(); // 777 closure2(); // 778 closure1(); // 6
ES5 Function Classes: uses Object.defineProperty ( O, P, Attributes )
The Object.defineProperty() method defines a new property directly on an object, or modifies an existing property on an object, and returns the object.
Created some methods by using ``, So that every once can understand the function classes easily.
'use strict';
var Shape = function ( superClass ) {
var currentClass = Shape;
_inherits(currentClass, superClass); // Prototype Chain - Extends
function Shape(id) { superClass.call(this); // Linking with SuperClass Constructor.
// Instance Variables list.
this.id = id; return this;
}
var staticVariablesJOSN = { "parent_S_V" : 777 };
staticVariable( currentClass, staticVariablesJOSN );
// Setters, Getters, instanceMethods. [{}, {}];
var instanceFunctions = [
{
key: 'uniqueID',
get: function get() { return this.id; },
set: function set(changeVal) { this.id = changeVal; }
}
];
instanceMethods( currentClass, instanceFunctions );
return currentClass;
}(Object);
var Rectangle = function ( superClass ) {
var currentClass = Rectangle;
_inherits(currentClass, superClass); // Prototype Chain - Extends
function Rectangle(id, width, height) { superClass.call(this, id); // Linking with SuperClass Constructor.
this.width = width;
this.height = height; return this;
}
var staticVariablesJOSN = { "_staticVar" : 77777 };
staticVariable( currentClass, staticVariablesJOSN );
var staticFunctions = [
{
key: 'println',
value: function println() { console.log('Static Method'); }
}
];
staticMethods(currentClass, staticFunctions);
var instanceFunctions = [
{
key: 'setStaticVar',
value: function setStaticVar(staticVal) {
currentClass.parent_S_V = staticVal;
console.log('SET Instance Method Parent Class Static Value : ', currentClass.parent_S_V);
}
}, {
key: 'getStaticVar',
value: function getStaticVar() {
console.log('GET Instance Method Parent Class Static Value : ', currentClass.parent_S_V);
return currentClass.parent_S_V;
}
}, {
key: 'area',
get: function get() {
console.log('Area : ', this.width * this.height);
return this.width * this.height;
}
}, {
key: 'globalValue',
get: function get() {
console.log('GET ID : ', currentClass._staticVar);
return currentClass._staticVar;
},
set: function set(value) {
currentClass._staticVar = value;
console.log('SET ID : ', currentClass._staticVar);
}
}
];
instanceMethods( currentClass, instanceFunctions );
return currentClass;
}(Shape);
// ===== ES5 Class Conversion Supported Functions =====
function defineProperties(target, props) {
console.log(target, ' : ', props);
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
function staticMethods( currentClass, staticProps ) {
defineProperties(currentClass, staticProps);
};
function instanceMethods( currentClass, protoProps ) {
defineProperties(currentClass.prototype, protoProps);
};
function staticVariable( currentClass, staticVariales ) {
// Get Key Set and get its corresponding value.
// currentClass.key = value;
for( var prop in staticVariales ) {
console.log('Keys : Values');
if( staticVariales.hasOwnProperty( prop ) ) {
console.log(prop, ' : ', staticVariales[ prop ] );
currentClass[ prop ] = staticVariales[ prop ];
}
}
};
function _inherits(subClass, superClass) {
console.log( subClass, ' : extends : ', superClass );
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
}
subClass.prototype = Object.create(superClass && superClass.prototype,
{ constructor: { value: subClass, enumerable: false, writable: true, configurable: true } });
if (superClass)
Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
Below code snippet is to test about Each instance has their own copy of instance members and common static members.
var objTest = new Rectangle('Yash_777', 8, 7);
console.dir(objTest);
var obj1 = new Rectangle('R_1', 50, 20);
Rectangle.println(); // Static Method
console.log( obj1 ); // Rectangle {id: "R_1", width: 50, height: 20}
obj1.area; // Area : 1000
obj1.globalValue; // GET ID : 77777
obj1.globalValue = 88; // SET ID : 88
obj1.globalValue; // GET ID : 88
var obj2 = new Rectangle('R_2', 5, 70);
console.log( obj2 ); // Rectangle {id: "R_2", width: 5, height: 70}
obj2.area; // Area : 350
obj2.globalValue; // GET ID : 88
obj2.globalValue = 999; // SET ID : 999
obj2.globalValue; // GET ID : 999
console.log('Static Variable Actions.');
obj1.globalValue; // GET ID : 999
console.log('Parent Class Static variables');
obj1.getStaticVar(); // GET Instance Method Parent Class Static Value : 777
obj1.setStaticVar(7); // SET Instance Method Parent Class Static Value : 7
obj1.getStaticVar(); // GET Instance Method Parent Class Static Value : 7
Static method calls are made directly on the class and are not callable on instances of the class. But you can achieve the calls for static members from inside an instance.
Using syntax:
this.constructor.staticfunctionName();
class MyClass {
constructor() {}
static staticMethod() {
console.log('Static Method');
}
}
MyClass.staticVar = 777;
var myInstance = new MyClass();
// calling from instance
myInstance.constructor.staticMethod();
console.log('From Inside Class : ',myInstance.constructor.staticVar);
// calling from class
MyClass.staticMethod();
console.log('Class : ', MyClass.staticVar);
ES6 Classes: ES2015 classes are a simple sugar over the prototype-based OO pattern. Having a single convenient declarative form makes class patterns easier to use, and encourages interoperability. Classes support prototype-based inheritance, super calls, instance and static methods and constructors.
Example: refer my previous post.
You can define static functions in JavaScript using the static
keyword:
class MyClass {
static myStaticFunction() {
return 42;
}
}
MyClass.myStaticFunction(); // 42
As of this writing, you still can't define static properties (other than functions) within the class. Static properties are still a Stage 3 proposal, which means they aren't part of JavaScript yet. However, there's nothing stopping you from simply assigning to a class like you would to any other object:
class MyClass {}
MyClass.myStaticProperty = 42;
MyClass.myStaticProperty; // 42
Final note: be careful about using static objects with inheritance - all inherited classes share the same copy of the object.
In JavaScript everything is either a primitive type or an object. Functions are objects — (key value pairs).
When you create a function you create two objects. One object that represents the function itself and the other that represents the prototype of the function.
Function is basically in that sense an object with the properties:
function name,
arguments length
and the functional prototype.
So where to set the static property: Two places, either inside the function object or inside the function prototype object.
Here is a snippet that creates that end even instantiates two instances, using the new
JavaScript keyword.
function C () { // function
var privateProperty = "42";
this.publicProperty = "39";
this.privateMethod = function(){
console.log(privateProperty);
};
}
C.prototype.publicMethod = function () {
console.log(this.publicProperty);
};
C.prototype.staticPrototypeProperty = "4";
C.staticProperty = "3";
var i1 = new C(); // instance 1
var i2 = new C(); // instance 2
i1.privateMethod();
i1.publicMethod();
console.log(i1.__proto__.staticPrototypeProperty);
i1.__proto__.staticPrototypeProperty = "2";
console.log(i2.__proto__.staticPrototypeProperty);
console.log(i1.__proto__.constructor.staticProperty);
i1.__proto__.constructor.staticProperty = "9";
console.log(i2.__proto__.constructor.staticProperty);
The main idea is that instances i1
and i2
are using the same static properties.
I use static function variables a lot and it's a real shame JS doesn't have a built-in mechanism for that. Too often I see code where variables and functions are defined in an outer scope even though they're just used inside one function. This is ugly, error prone and just asking for trouble...
I came up with the following method:
if (typeof Function.prototype.statics === 'undefined') {
Function.prototype.statics = function(init) {
if (!this._statics) this._statics = init ? init() : {};
return this._statics;
}
}
This adds a 'statics' method to all functions (yes, just relax about it), when called it will add an empty object (_statics) to the function object and return it. If an init function is supplied _statics will be set to init() result.
You can then do:
function f() {
const _s = f.statics(() => ({ v1=3, v2=somefunc() });
if (_s.v1==3) { ++_s.v1; _s.v2(_s.v1); }
}
Comparing this to an IIFE which is the other correct answer, this has the disadvantage of adding one assignment and one if on every function call and adding a '_statics' member to the function, however there are a few advantages: the arguments are there at the top not in the internal function, using a 'static' in the internal function code is explicit with an '_s.' prefix, and it is overall simpler to look at and understand.
Summary:
In ES6
/ES 2015 the class
keyword was introduced with an accompanied static
keyword. Keep in mind that this is syntactic sugar over the prototypal inheritance model which javavscript embodies. The static
keyword works in the following way for methods:
class Dog {
static bark () {console.log('woof');}
// classes are function objects under the hood
// bark method is located on the Dog function object
makeSound () { console.log('bark'); }
// makeSound is located on the Dog.prototype object
}
// to create static variables just create a property on the prototype of the class
Dog.prototype.breed = 'Pitbull';
// So to define a static property we don't need the `static` keyword.
const fluffy = new Dog();
const vicky = new Dog();
console.log(fluffy.breed, vicky.breed);
// changing the static variable changes it on all the objects
Dog.prototype.breed = 'Terrier';
console.log(fluffy.breed, vicky.breed);
Working with MVC websites that use jQuery, I like to make sure AJAX actions within certain event handlers can only be executed once the previous request has completed. I use a "static" jqXHR object variable to achieve this.
Given the following button:
<button type="button" onclick="ajaxAction(this, { url: '/SomeController/SomeAction' })">Action!</button>
I generally use an IIFE like this for my click handler:
var ajaxAction = (function (jqXHR) {
return function (sender, args) {
if (!jqXHR || jqXHR.readyState == 0 || jqXHR.readyState == 4) {
jqXHR = $.ajax({
url: args.url,
type: 'POST',
contentType: 'application/json',
data: JSON.stringify($(sender).closest('form').serialize()),
success: function (data) {
// Do something here with the data.
}
});
}
};
})(null);
If you want to use prototype then there is a way
var p = function Person() {
this.x = 10;
this.y = 20;
}
p.prototype.counter = 0;
var person1 = new p();
person1.prototype = p.prototype;
console.log(person1.counter);
person1.prototype.counter++;
var person2 = new p();
person2.prototype = p.prototype;
console.log(person2.counter);
console.log(person1.counter);
Doing this you will be able to access the counter variable from any instance and any change in the property will be immediately reflected!!
someFunc = () => { MyClass.myStaticVariable = 1; }
. Then just create a static method to return the static member, e.g.static getStatic() { return MyClass.myStaticVariable; }
. Then you can just callMyClass.getStatic()
from outside the class to get hold of the static data ! – Pixel