Статические переменные в JavaScript - PullRequest
662 голосов
/ 08 октября 2009

Как я могу создать статические переменные в Javascript?

Ответы [ 38 ]

8 голосов
/ 24 марта 2017

О class, представленном ECMAScript 2015. Другие ответы не совсем ясны.

Вот пример, показывающий, как создать статическую переменную staticVar с 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

Для доступа к статической переменной мы используем свойство .constructor, которое возвращает ссылку на функцию конструктора объекта, которая создала класс. Мы можем вызвать его на двух созданных экземплярах:

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
6 голосов
/ 31 июля 2016

Вы можете создать статическую переменную в JavaScript, как показано ниже. Здесь count - статическая переменная.

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, либо любой из экземпляров:

// 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
6 голосов
/ 08 февраля 2015

Есть и другие похожие ответы, но ни один из них мне не понравился. Вот что я закончил:

var nextCounter = (function () {
  var counter = 0;
  return function() {
    var temp = counter;
    counter += 1;
    return temp;
  };
})();
5 голосов
/ 16 марта 2012

Если вы хотите создать глобальную статическую переменную:

var my_id = 123;

Заменить переменную следующим:

Object.defineProperty(window, 'my_id', {
    get: function() {
            return 123;
        },
    configurable : false,
    enumerable : false
});
5 голосов
/ 08 апреля 2017

В JavaScript переменные статические по умолчанию. Пример :

var x = 0;

function draw() {
    alert(x); //
    x+=1;
}

setInterval(draw, 1000);

Значение x увеличивается на 1 каждые 1000 миллисекунд
Напечатает 1,2,3 пр.

4 голосов
/ 24 ноября 2013

Чтобы сжать все понятия классов здесь, проверьте это:

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

Ну, еще один способ взглянуть на лучшие практики в этих вещах, это просто посмотреть, как coffeescript переводит эти понятия.

#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);
4 голосов
/ 07 апреля 2013

Есть другой подход, который решил мои требования после просмотра этой темы. Это зависит от того, чего именно вы хотите достичь с помощью «статической переменной».

Глобальное свойство sessionStorage или localStorage позволяет хранить данные в течение всей жизни сеанса или в течение неопределенного более длительного периода, пока не будет явно очищено, соответственно. Это позволяет обмениваться данными между всеми окнами, фреймами, панелями вкладок, всплывающими окнами и т. Д. Вашей страницы / приложения и является гораздо более мощным, чем простая «статическая / глобальная переменная» в одном сегменте кода.

Это позволяет избежать хлопот, связанных с областью действия, временем жизни, семантикой, динамикой и т. Д. Глобальных переменных верхнего уровня, например Window.myglobal. Не знаю, насколько это эффективно, но это не важно для скромных объемов данных, доступ к которым осуществляется с умеренной скоростью.

Легко доступен как "sessionStorage.mydata = что-нибудь" и извлекается аналогично. Увидеть «JavaScript: Полное руководство, шестое издание», Дэвид Фланаган, ISBN: 978-0-596-80552-4, глава 20, раздел 20.1. Его легко загрузить в формате PDF с помощью простого поиска или в подписке O'Reilly Safaribooks (на вес золота).

4 голосов
/ 08 октября 2009

В JavaScript ближе всего к статической переменной является глобальная переменная - это просто переменная, объявленная вне области действия функции или литерала объекта:

var thisIsGlobal = 1;

function foo() {
    var thisIsNot = 2;
}

Другая вещь, которую вы могли бы сделать, это хранить глобальные переменные внутри литерала объекта следующим образом:

var foo = { bar : 1 }

А затем получите доступ к переменным следующим образом: foo.bar.

3 голосов
/ 08 февраля 2018

В дополнение к остальным, в настоящее время существует черновик ( предложение этапа 2 ) по предложениям ECMA , который вводит static публичные поля в классах. ( были рассмотрены частные поля )

Используя пример из предложения, предлагаемый синтаксис static будет выглядеть следующим образом:

class CustomDate {
  // ...
  static epoch = new CustomDate(0);
}

и эквивалентно следующему, которое другие выделили:

class CustomDate {
  // ...
}
CustomDate.epoch = new CustomDate(0);

Вы можете получить к нему доступ через CustomDate.epoch.

Вы можете отслеживать новое предложение в proposal-static-class-features.


В настоящее время babel поддерживает эту функцию с помощью плагина свойств класса преобразования *1029*, который вы можете использовать. Кроме того, V8, хотя все еще находится в процессе реализации, .

1 голос
/ 24 августа 2017

Функции / классы допускают только один конструктор для своей области видимости. Function Hoisting, declarations & expressions

  • Функции, созданные с помощью конструктора Function, не создают замыканий для своих контекстов создания; они всегда создаются в глобальной области видимости.

      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)
    

Закрытия - копии закрытия являются функцией с сохраненными данными.

  • Копии каждого замыкания создаются функцией с их собственными свободными значениями или ссылками. Когда вы используете функцию внутри другой функции, используется замыкание.
  • Закрытие в JavaScript похоже на сохранение копии всех локальных переменных своей родительской функции с помощью 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 : использует Object.defineProperty (O, P, Атрибуты)

Метод 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 - это простой сахар по сравнению с шаблоном ОО на основе прототипа. Наличие единой удобной декларативной формы облегчает использование шаблонов классов и способствует взаимодействию. Классы поддерживают наследование на основе прототипов, супер вызовы, экземпляры и статические методы и конструкторы.

Пример : см. Мой предыдущий пост.

...