如何在Javascript中创建静态变量?
当前回答
试试这个:
如果我们定义一个属性并重写其getter和setter以使用Function Object属性,那么理论上可以在javascript中使用一个静态变量
例如:
函数Animal(){if(isNaN(this.totalAnimalCount)){this.totalAnimalCount=0;}this.totalAnimationCount++;};Object.defineProperty(动画原型,“totalAnimalCount”{获取:函数(){return Animal['totalAnimalCount'];},集合:函数(val){动物['totalAnimalCount']=val;}});var cat=新动画();console.log(cat.totalAnimationCount)//将产生1var dog=新动画();console.log(cat.totalAnimationCount)//将产生2等。
其他回答
函数的/类只允许其对象范围使用一个构造函数。函数提升、声明和表达式
使用Function构造函数创建的函数不会创建其创建上下文的闭包;它们总是在全局范围内创建的。var functionClass=函数(){var currentClass=形状;_继承(currentClass,superClass);function functionClass(){superClass.call(this);//与superClass构造函数链接。//实例变量列表。this.id=id;返回此;}}(特级)
闭包-闭包的副本是保存数据的函数。
每个闭包的副本都被创建到一个具有自己的自由值或引用的函数。每当您在另一个函数中使用函数时,都会使用闭包。JavaScript中的闭包就像innerFunctions维护其父函数的所有局部变量的副本。函数closureFun(参数){//结束于闭包内的局部变量var num=参数;num++;return函数(){console.log(num);}}var closure1=closureFun(5);var closure2=closureFun(777);closure1();//5.closure2();//777closure2();//778closure1();//6.
ES5函数类:使用Object.defineProperty(O,P,Attributes)
Object.defineProperty()方法直接在对象上定义新属性,或修改对象上的现有属性,然后返回对象。
使用“”创建了一些方法,以便每次都能轻松理解函数类。
'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;
}
下面的代码片段是测试每个实例都有自己的实例成员和公共静态成员的副本。
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
静态方法调用直接在类上进行,不能在类的实例上调用。但您可以从实例内部实现对静态成员的调用。使用语法: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类:ES2015类比基于原型的OO模式更简单。拥有一个方便的声明性表单可以使类模式更易于使用,并鼓励互操作性。类支持基于原型的继承、超级调用、实例和静态方法以及构造函数。
示例:参考我以前的帖子。
如果您来自基于类的静态类型的面向对象语言(如Java、C++或C#),我假设您试图创建与“类型”相关联的变量或方法,而不是与实例相关联的。
使用带有构造函数的“经典”方法的示例可能会帮助您了解基本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对象(这是一个函数)中定义,与它创建的实例无关,JavaScript将函数视为一级对象,因此作为一个对象,可以将财产分配给函数。
UPDATE:ES6引入了通过class关键字声明类的能力。它是现有的基于原型的继承的语法糖。
static关键字允许您轻松定义类中的静态财产或方法。
让我们看看上面用ES6类实现的示例:
类MyClass{//类构造函数,等效于//构造函数的函数体构造器(){const privateVariable=“private value”;//构造函数范围内的私有变量this.publicVariable='公共值';//公共财产this.privilegedMethod=函数(){//具有构造函数范围变量访问权限的公共方法console.log(privateVariable);};}//原型方法:publicMethod(){console.log(this.publicVariable);}//所有实例共享的静态财产static staticProperty='静态值';静态静态方法(){console.log(this.staticProperty);}}//我们可以将财产添加到类原型中MyClass.prototype.additionalMethod=函数(){console.log(this.publicVariable);};var myInstance=新建MyClass();myInstance.publicMethod();//“公共价值”myInstance.additionalMethod();//“公共价值”myInstance.privilegedMethod();//“私人价值”MyClass.staticMethod();//“静态值”
我通常使用这种方法有两个主要原因:
如果我想存储函数的本地值,我会使用“local.x”、“local.y”、“local.TempData”等。。。!
如果我想存储函数的静态值,我会使用“static.o”、“static.Info”、“static.count”等。。。!
[Update2]:方法相同,但使用IIFE方法!
[Update1]:通过预编辑脚本自动创建函数的“静态”和“本地”对象!
您可以使用static关键字在JavaScript中定义静态函数:
class MyClass {
static myStaticFunction() {
return 42;
}
}
MyClass.myStaticFunction(); // 42
在撰写本文时,您仍然无法在类中定义静态财产(函数除外)。静态财产仍然是第三阶段的建议,这意味着它们还不是JavaScript的一部分。然而,没有什么可以阻止您像分配给任何其他对象一样简单地分配给类:
class MyClass {}
MyClass.myStaticProperty = 42;
MyClass.myStaticProperty; // 42
最后一点:小心使用带有继承的静态对象-所有继承的类共享对象的相同副本。
所以我从其他答案中看到的是,它们没有解决面向对象编程中静态属性的基本架构要求。
面向对象编程实际上有两种不同的风格,一种是基于类的(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,则更改将级联到立即继承它的子对象。
然而,有一些“陷阱”可能会严重破坏此属性的“静态”特性,或者只留下安全漏洞。。。
首先,确保通过将构造函数封装在另一个函数(如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更友好的不同代码模式可能会更好。比如一个中央数据存储或缓存,甚至一个专用的帮助对象来保存所有必要的静态变量。