JavaScript中的静态variables
我如何在Javascript中创build静态variables?
如果您来自基于类的强types的面向对象语言(如Java,C ++或C#),我假设您正在尝试创build与“types”关联的variables或方法,而不是与实例关联。
一个使用“古典”方法的例子,使用构造函数也许可以帮助你理解基本的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
是在MyClass对象(这是一个函数)中定义的,并且与其创build的实例无关,JavaScript把函数当作第一类对象 ,所以作为一个对象,可以给函数赋予属性。
你可能会利用这个事实,JSfunction也是对象 – 这意味着他们可以有属性。
例如,引用在(现在消失的)文章中给出的例子Javascript中的静态variables :
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); }
如果你多次调用这个函数,你会看到计数器正在递增。
这可能是一个更好的解决scheme,比使用全局variables处理全局名称空间更好。
这里是另一个可能的解决scheme,基于闭包: 窍门在JavaScript中使用静态variables :
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.
哪一个会得到相同的结果 – 除了这次,递增的值被返回,而不是显示。
你通过一个IIFE(立即调用的函数expression式)来做到这一点:
var incr = (function () { var i = 1; return function () { return i++; } })(); incr(); // returns 1 incr(); // returns 2
你可以使用arguments.callee存储“静态”variables(这在匿名函数中也是有用的):
function () { arguments.callee.myStaticVar = arguments.callee.myStaticVar || 1; arguments.callee.myStaticVar++; alert(arguments.callee.myStaticVar); }
function Person(){ if(Person.count == undefined){ Person.count = 1; } else{ Person.count ++; } console.log(Person.count); } var p1 = new Person(); var p2 = new Person(); var p3 = new Person();
我已经看到了几个类似的答案,但是我想提一下这个post最好的描述,所以我想和大家分享一下。
下面是一些代码,我已经修改了一些代码,希望能给社区带来好处,因为它可以用作类的devise模板。
它也回答你的问题:
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 + ' ...'); };
考虑到这个例子,你可以像下面这样访问静态属性/函数 :
// access static properties/functions Podcast.FILE_EXTENSION; // 'mp3' Podcast.download('Astronomy cast'); // 'Downloading Astronomy cast ...'
而对象的属性/function简单如下:
// access object properties/functions var podcast = new Podcast(); podcast.title = 'The Simpsons'; console.log(podcast.toString()); // Title: The Simpsons console.log(podcast.immutableProp()); // 123
请注意 ,在podcast.immutableProp()中,我们有一个闭包:对_somePrivateVariable的引用保留在函数内部。
你甚至可以定义getter和setter 。 看看这个代码片断(其中d
是你想声明一个属性的对象的原型, y
是一个私有variables在构造函数之外不可见):
// getters and setters var d = Date.prototype; Object.defineProperty(d, "year", { get: function() {return this.getFullYear() }, set: function(y) { this.setFullYear(y) } });
它通过get
和set
函数定义属性d.year
– 如果你没有指定set
,那么属性是只读的,不能被修改(注意如果你设置它,你不会得到一个错误,但是它没有效果)。 每个属性都具有writable
, writable
configurable
(允许在声明后更改)和enumerable
(允许使用它作为枚举器)的属性,每个属性默认为false
。 你可以在第三个参数中通过defineProperty
来设置它们,比如enumerable: true
。
这个语法也是有效的:
// getters and setters - alternative syntax var obj = { a: 7, get b() {return this.a + 1;}, set c(x) {this.a = x / 2} };
它定义了一个可读/可写属性a
,一个只读属性b
和一个只写属性c
,通过它可以访问属性a
。
用法:
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
笔记:
为了避免您忘记new
关键字时的意外行为,build议您将以下内容添加到functionPodcast
:
// instantiation helper function Podcast() { if(false === (this instanceof Podcast)) { return new Podcast(); } // [... same as above ...] };
现在,下面的两个实例都将按预期工作:
var podcast = new Podcast(); // normal usage, still allowed var podcast = Podcast(); // you can omit the new keyword because of the helper
'new'语句创build一个新的对象并复制所有的属性和方法,即
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
使用return
语句可以返回一个自定义对象,该类保护内部依赖的类但需要暴露的对象。 这在文章系列的第2章(对象)中有进一步的解释。
你可以说a
和b
从Podcast
inheritance。 现在,如果你想添加一个方法到播客,适用于所有这些后, a
和b
已经instanciated? 在这种情况下,使用.prototype
如下所示:
Podcast.prototype.titleAndLink = function() { return this.title + " [" + this.link + "]"; };
现在再次调用a
和b
:
console.log(a.titleAndLink()); // "a [http://www.astronomycast.com]" console.log(b.titleAndLink()); // "An Astronomy Cast [http://www.astronomycast.com]"
你可以在这里find关于原型的更多细节。 如果你想做更多的inheritance,我build议看看这个 。
我上面提到的文章系列 强烈推荐阅读,他们还包括以下主题:
- function
- 对象
- 原型
- 强化构造函数的新function
- 吊装
- 自动分号插入
- 静态属性和方法
请注意 ,JavaScript中的自动分号插入 “特性”(如6.中所提到的)通常是导致代码中出现奇怪问题的原因。 因此,我宁愿将它视为一个错误而不是一个特征。
如果你想阅读更多, 这里是一个非常有趣的关于这些主题的MSDN文章 ,其中一些描述那里提供了更多的细节。
有趣的是,阅读 (也包括上面提到的主题)是MDN JavaScript指南中的那些文章:
- 重新介绍JavaScript
- 使用对象
那些正在使用IE浏览器 (除非您使用F12打开开发者工具并打开控制台选项卡,否则没有用于JavaScript的控制台)的用户可能会发现以下代码段很有用。 它允许你使用console.log(msg);
如以上示例中所使用的。 只需将其插入Podcast
function即可。
为了您的方便,下面是一个完整的单一代码片段中的代码:
var console = { log:function(msg) { var tmp=document.getElementById("logging").innerHTML; if (tmp!="") tmp+="<br/>"; document.getElementById("logging").innerHTML=tmp+msg; } }; 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="logging"></div>
更新回答:
在ECMAScript 6中 ,您可以使用static
关键字创build静态函数:
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类不会为静态引入任何新的语义。 你可以在ES5中做同样的事情:
//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
您可以分配给Foo
的属性,因为在JavaScript中函数是对象。
下面的例子和解释来自Nicholas Zakas的专业JavaScript for Web Developers第二版。 这是我正在寻找的答案,所以我认为这将在这里添加它是有帮助的。
(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
此示例中的Person
构造函数可以访问私有variables名称, getName()
和setName()
方法也是如此。 使用这个模式,名称variables变成静态的,并将在所有实例中使用。 这意味着在一个实例上调用setName()
会影响所有其他实例。 调用setName()
或创build一个新的Person
实例将namevariables设置为一个新的值。 这会导致所有实例返回相同的值。
如果您正在使用新的类语法,那么现在可以执行以下操作:
class MyClass { static get myStaticVariable() { return "some static variable"; } } console.log(MyClass.myStaticVariable); aMyClass = new MyClass(); console.log(aMyClass.myStaticVariable, "is undefined");
如果你想声明静态variables在你的应用程序中创build常量,那么我发现以下是最简单的方法
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;
还有其他类似的答案,但是没有一个对我很有吸引力。 以下是我最终的结果:
var nextCounter = (function () { var counter = 0; return function() { var temp = counter; counter += 1; return temp; }; })();
如果你想做一个全局静态variables:
var my_id = 123;
用下面的代码replacevariables:
Object.defineProperty(window, 'my_id', { get: function() { return 123; }, configurable : false, enumerable : false });
您可以在JavaScript中创build一个静态variables,如下所示。 这里count
是静态variables。
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
您可以使用Person
函数或任何实例将值分配给静态variables:
// 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
关于ECMAScript 2015引入的class
。其他答案还不完全清楚。
下面是一个示例,展示如何使用ClassName
创build静态var staticVar
。 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
要访问静态variables,我们使用.constructor
属性,该属性返回对创build该类的对象构造函数的引用。 我们可以在两个创build的实例上调用它:
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
JavaScript中最接近静态variables的是全局variables – 这只是一个在函数或对象文本范围外声明的variables:
var thisIsGlobal = 1; function foo() { var thisIsNot = 2; }
你可以做的另一件事是将全局variables存储在像这样的对象字面值中:
var foo = { bar : 1 }
然后访问像这样的变种: foo.bar
。
还有另一种方法,在浏览这个线程之后解决了我的需求。 这取决于你想用“静态variables”来达到的目的。
全局属性sessionStorage或localStorage允许将数据存储在会话的整个生命周期中,或者在明确清除之前无限期地存储数据。 这允许数据在你的页面/应用程序的所有窗口,框架,标签面板,popup窗口等之间共享,并且比一个代码段中的简单“静态/全局variables”更强大。
它避免了顶级全局variables(如Window.myglobal)的范围,生命周期,语义,dynamic等方面的麻烦。 不知道它有多高效,但是对于数量适中的数据并不重要。
轻松地访问“sessionStorage.mydata =任何东西”和类似的检索。 参见“JavaScript:权威指南,第六版”,David Flanagan,ISBN:978-0-596-80552-4,第20章,第20.1节。 这很容易通过简单的search,或在您的O'Reilly Safaribook订阅(相当于黄金的重量)作为PDF下载。
干杯,格雷格E
为了浓缩这里的所有类的概念,testing一下:
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
那么,另一种看待这些事情的最佳实践的方法就是看看咖啡文本是如何翻译这些概念的。
#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);
在JavaScript中,variables默认是静态的。 例如 :
var x = 0; 函数draw(){ 警报(X); // X + = 1; } setInterval(draw,1000);
x的值每1000毫秒增加1
它会打印1,2,3等等
窗口级别的variables就像静态的一样,你可以使用直接引用,这些variables可以被你的应用程序的所有部分使用
Javascript中没有这样的静态variables。 这种语言是基于原型的面向对象,所以没有类,而是从对象“复制”自己的原型。
您可以使用全局variables或原型(向原型添加属性)来模拟它们:
function circle(){ } circle.prototype.pi=3.14159
使用jQuery的MVC网站,我喜欢确保某些事件处理程序中的AJAX操作只能在前一个请求完成后才能执行。 我使用“静态”jqXHR对象variables来实现这一点。
给出以下button:
<button type="button" onclick="ajaxAction(this, { url: '/SomeController/SomeAction' })">Action!</button>
我通常使用这样的IIFE作为我的点击处理程序:
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);
如果你想使用原型,那么有一种方法
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);
这样做,你将能够从任何实例访问计数器variables,任何财产的变化将立即反映出来!
所以我看到的其他答案是他们没有解决面向对象编程中静态属性的基本架构要求。
面向对象编程实际上有两种不同的风格,一种是基于类(C ++,C#,Java等),另一种是“原型的”(Javascript)。 在基于类的语言中,“静态属性”应该与类相关联,而不是实例化的对象。 这个概念实际上在Javascript这样的原型语言中更加直观,因为您只需将属性赋值为父级原型的值即可。
function MyObject() {}; MyObject.prototype.staticAttribute = "some value";
并从这个构造函数实例化的每一个对象访问它,像这样…
var childObject1 = new MyObject(); // Instantiate a child object var childObject2 = new MyObject(); // Instantiate another child object console.log(childObject.staticAttribute); // Access the static Attribute from child 1 console.log(childObject.staticAttribute); // Access the static Attribute from child 2
现在,如果继续并更改MyObject.prototype.staticAttribute
则更改将级联到立即inheritance它的子对象。
然而,有一些“陷阱”可能会严重破坏这个属性的“静态”性质,或者只是留下安全漏洞。
首先确保从Global名称空间隐藏构造函数,方法是将其封装在另一个函数(如jQuery ready方法)中
$(document).ready(function () { function MyObject() { // some constructor instructions }; MyObject.prototype.staticAttribute = "some value"; var childObject = new MyObject(); // instantiate child object console.log(childObject.staticAttribute); // test attribute });
第二,最后,即使你这样做,该属性仍然可以从你自己的脚本的任何其他部分编辑,所以可能是你的代码中的错误写在子对象之一的属性上,并分离它从父级原型,所以如果你改变父级属性,它不会级联和更改子对象的静态属性。 看到这个jsfiddle。 在不同的场景中,我们可以使用Object.freeze(obj)
来停止对子对象的任何修改,或者我们可以在构造函数中设置一个setter和getter方法,并访问一个闭包,这两个都有相关的复杂性。
在我看来,“静态属性”的基于类的概念和这个Javascript实现之间没有完美的类比。 所以我认为,从长远来看,使用更友好的Javascript代码模式可能会更好。 如中央数据存储或caching,甚至是一个专门的帮助对象来保存所有必要的静态variables。
我没有在任何答案中看到这个想法,所以只是把它添加到列表中。 如果这是一个重复只是让我知道,我会删除它,并upvote其他。
我在我的网站上创build了一个超级全球。 由于我有几个加载在每个页面加载的js文件和几十个只加载在一些页面上的其他js文件,我把所有的“全局”函数放到一个全局variables中。
在我的第一个包括“全球”文件的顶部是声明
var cgf = {}; // Custom global functions.
然后我delcare几个全球帮手function
cgf.formBehaviors = function() { // My form behaviors that get attached in every page load. }
然后,如果我需要一个静态variables,我只是将其存储在范围之外,如文档之外准备好或行为附件外。 (我使用jQuery,但它应该在JavaScript中工作)
cgf.first = true; $.on('click', '.my-button', function() { // Don't allow the user to press the submit twice. if (cgf.first) { // first time behavior. such as submit } cgf.first = false; }
这当然是一个全球性的,而不是一个静态的,但是当它在每个页面加载时被重新初始化,它实现了相同的目的。
在JavaScript中,没有术语或关键字静态,但我们可以将这些数据直接放入函数对象(就像其他对象一样)。
function f() { f.count = ++f.count || 1 // f.count is undefined at first alert("Call No " + f.count) } f(); // Call No 1 f(); // Call No 2
对于私有静态variables,我发现这样:
function Class() { } Class.prototype = new function() { _privateStatic = 1; this.get = function() { return _privateStatic; } this.inc = function() { _privateStatic++; } }; var o1 = new Class(); var o2 = new Class(); o1.inc(); console.log(o1.get()); console.log(o2.get()); // 2
试试这个:
如果我们定义一个属性并覆盖它的getter和setter来使用Function Object属性,那么理论上你可以在JavaScript中有一个静态variables
例如:
function Animal() { if (isNaN(this.totalAnimalCount)) { this.totalAnimalCount = 0; } this.totalAnimalCount++; }; Object.defineProperty(Animal.prototype, 'totalAnimalCount', { get: function() { return Animal['totalAnimalCount']; }, set: function(val) { Animal['totalAnimalCount'] = val; } }); var cat = new Animal(); console.log(cat.totalAnimalCount); //Will produce 1 var dog = new Animal(); console.log(cat.totalAnimalCount); //Will produce 2 and so on.
在JavaScript中,一切都是原始types或对象。 函数是对象 – (键值对)。
当你创build一个函数时,你创build了两个对象。 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);
There are two main things to note, In EcmaScript 5 specification
- JavaScript does not have a concept called classes .
- JavaScript only contains a concept called functions .
Lets take this function/class called Foo and try to set a static variable to it.
function Foo() { }
According to the 2nd points I mentioned earlier class is a function in JavaScript. If we want to create a new instance (object) of this class/function, We use it like this.
new Foo();
But because we need to create a static variable (function/class level variable) the variable directly needs to bind to the Foo function
There are three ways of doing this
- Bind the static variable directly to the Foo function (this automatically get binds to proto object)
Foo.staticVariableName = 'staticValue';
- Bind the static variable to the dunder proto (
__proto__
) object in Foo function. (Bad: because there is a performance issue)
Foo.__proto__.staticVariableName = 'staticValue';
- Bind the static variable to Foo function constructor's prototype (same link will be created to the dunder proto object)
Foo.constructor.prototype.staticVariableName = 'staticValue';
In above ways you can simply access Foo.staticVariableName
.
Note : Don't directly bind the staticVariable to the prototype object in Foo function
Foo.prototype.staticVariableName = 'staticValue';
Then this staticVariableName will be only available when you create a new Foo function object
To understand how this __proto__
linking work you can refer this diagram JavaScript Prototype Chain Diagram
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
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.