Статичні змінні в JavaScript


716

Як я можу створити статичні змінні у Javascript?


ми можемо визначити мітку або інший тег html за допомогою атрибута стилю "dispaly: none" та встановити змінне значення для цього значення та оперувати цим значенням. Не сприймай важко.
асгар

Найпростіше рішення, яке я знайшов: взагалі не визначати статичну змінну в класі. Коли ви хочете використовувати статичну змінну, просто визначте її там, а потім, наприклад someFunc = () => { MyClass.myStaticVariable = 1; }. Потім просто створіть статичний метод для повернення статичного елемента, наприклад static getStatic() { return MyClass.myStaticVariable; }. Тоді ви можете просто зателефонувати MyClass.getStatic()поза класом, щоб отримати статичні дані!
Піксель

Відповіді:


863

Якщо ви походите з класово-статично типово об'єктно-орієнтованої мови (наприклад, 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 розглядає функції як об'єкти першокласного , тому будучи об'єктом, ви можете призначити властивості функції.

ОНОВЛЕННЯ: ES6 представив можливість оголошення класів за classключовим словом. Це синтаксичний цукор над існуючим на основі прототипу успадкуванням.

staticКлючові слова дозволяють легко визначити статичні властивості і методи в класі.

Давайте подивимось на прикладі, що реалізується з класами ES6:

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"


5
Імовірно, privilegedMethodце не рівнозначно приватному методу в OO, тому що здається, що його можна викликати в екземплярі MyClass? Ви маєте на увазі привілейований доступ, оскільки він може отримати доступ privateVariable?
Dónal

3
Не this.constructorможна використовувати для доступу до статичних змінних з "методів екземпляра"? Якщо так, то варто додати його до відповіді.
Ciro Santilli 冠状 病毒 审查 六四 事件 法轮功

1
Ви також можете згадати статичні функції у своєму прикладі.
Девід Родрігес

18
привіт, я не впевнений, що я згоден з цим рядком // Статична змінна, якою поділяються всі екземпляри 'MyClass.staticProperty = "baz";' як на мене, що підказує, що ви можете знайти baz з "myInstance.staticProperty", що, звичайно, не можете.
fullstacklife

5
Можливо, воно повинно читати MyClass.prototype.staticProperty = "baz";або бути ще більш правильним принципам ОО, статичне властивість насправді слід визначати як анонімну функцію, MyClass.prototype.staticProperty = function () {return staticVar;}так що всі екземпляри мають доступ до однієї змінної, яка також може бути змінена за допомогою сеттера.
lindsaymacvean

535

Ви можете скористатися тим, що функції JS також є об'єктами - це означає, що вони можуть мати властивості.

Наприклад, цитуючи приклад, наведений у статті (що вже зникла) Статичні змінні у 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);
}

Якщо ви зателефонуєте до цієї функції кілька разів, ви побачите, що лічильник збільшується.

І це, мабуть, набагато краще рішення, ніж полірування глобального простору імен глобальною змінною.


І ось ще одне можливе рішення, засноване на закритті: Намагайтеся використовувати статичні змінні в 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.

Що дає вам такий самий результат - за винятком цього разу, замість відображення, повернене збільшене значення.


50
як ярлик, ви можете просто зробити, countMyself.counter = countMyself.counter || initial_value;якщо статична змінна ніколи не буде фальсиєю (false, 0, null або порожній рядок)
Kip

3
Трохи коротше і чіткіше: (функція () {var id = 0; функція uniqueID () {return id ++;};}) ();
Том Робінсон

3
Лічильник закриття відбувається дуже швидше, ніж у класі в Firefox. jsperf.com/static-counter-in-class-vs-in-closure
Sony Santos

Використовуйте ===для typeofперевірок ще ви отримаєте якийсь дивний примус.
роса

@SonySantos Ваш тест показує протилежне для Firefox 40
bartolo-otrit

96

Ви робите це через IIFE (негайно викликається вираз функції):

var incr = (function () {
    var i = 1;

    return function () {
        return i++;
    }
})();

incr(); // returns 1
incr(); // returns 2

21
Я б сказав, що це самий ідіоматичний спосіб зробити це в JavaScript. Шкода, що він не отримує занадто багато результатів завдяки іншим методам, які, ймовірно, більш приємні для людей, які походять з інших мов.

1
Я б перефразував слово "закриття", а не просто "IIFE".
zendka

39

ви можете використовувати argument.callee для зберігання "статичних" змінних (це корисно і в анонімній функції):

function () {
  arguments.callee.myStaticVar = arguments.callee.myStaticVar || 1;
  arguments.callee.myStaticVar++;
  alert(arguments.callee.myStaticVar);
}

3
Наскільки я можу зрозуміти, цей метод має одну (лише одну?) Перевагу перед способом Pascal MARTIN: ви можете використовувати його на анонімних функціях. Приклад цього був би чудовим
День

27
arguments.calleeзастаріло.
Питання Quolonel

Я весь час висміював JS весь час, але calleeздавався приємною річчю. Цікаво, чому хак вирішили знецінити це ...: |
user2173353

35

Я бачив пару подібних відповідей, але хочу зазначити, що цей пост найкраще описує його, тому я хотів би поділитися ним з вами.

Ось якийсь код, взятий з нього, який я змінив, щоб отримати повний приклад, який, сподіваємось, приносить користь спільноті, оскільки його можна використовувати як шаблон дизайну для класів.

Він також відповідає на ваше запитання:

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
console.log(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

Зауважте, що у podcast.immutableProp () ми маємо закриття : Посилання на _somePrivateVariable зберігається всередині функції.

Ви навіть можете визначити геттерів та сеттерів . Погляньте на цей фрагмент коду (де dпрототип об'єкта, для якого потрібно оголосити властивість, yє приватною змінною, не видно за межами конструктора):

// getters and setters
var d = Date.prototype;
Object.defineProperty(d, "year", {
    get: function() {return this.getFullYear() },
    set: function(y) { this.setFullYear(y) }
});

Він визначає властивість d.yearчерез getта setфункції - якщо ви не вказуєте set, то властивість доступна лише для читання і не може бути змінена (пам’ятайте, що ви не отримаєте помилку, якщо спробуєте встановити її, але це не має ефекту). Кожна властивість має атрибути writable, configurable(дозволяють зміни після декларації) і enumerable(дозволяють використовувати його як інтерв'юер), які за умовчанням false. Ви можете встановити їх за definePropertyдопомогою 3-го параметра, наприклад 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ключове слово, пропоную вам додати в функцію наступне Podcast:

// 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' створює новий об'єкт і копіює всі властивості та методи, тобто

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"

Зауважимо також, що в деяких ситуаціях може бути корисним використання returnоператора у функції конструктора Podcastдля повернення користувальницьких функцій захисту об'єкта, на який клавіатура покладається внутрішньо, але які потрібно піддавати впливу. Це пояснено далі у розділі 2 (Об'єкти) серії статей.

Ви можете сказати це aі bуспадкувати від Podcast. Тепер, якщо ви хочете , щоб додати метод до Podcast , який відноситься до всіх з них після того, як aі bбуло інстанціірован? У цьому випадку використовуйте .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]"

Більш детальну інформацію про прототипи ви можете знайти тут . Якщо ви хочете зробити більше спадщини, пропоную розібратися в цьому .


У серії статей я вже згадував вище, настійно рекомендується читати, вони включають в себе також такі питання:

  1. Функції
  2. Об'єкти
  3. Прототипи
  4. Застосування нового для функцій конструктора
  5. Підйомник
  6. Автоматичне вставлення крапки з комою
  7. Статичні властивості та методи

Зауважте, що функція автоматичного вставлення крапки з комою в JavaScript (як зазначено в 6.) дуже часто є причиною виникнення дивних проблем у вашому коді. Отже, я б швидше розглядав це як помилку, ніж як особливість.

Якщо ви хочете прочитати більше, тут є досить цікава стаття MSDN про ці теми, деякі з них, описані там, містять ще більше деталей.

Що цікаво також читати (також висвітлюючи вищезазначені теми) - це статті з посібника з JavaScript по MDN :

Якщо ви хочете знати, як емулювати outпараметри c # (наприклад, в DateTime.TryParse(str, out result)) у JavaScript, ви можете знайти зразок коду тут.


Тим із вас, хто працює з IE (у якого немає консолі для JavaScript, якщо ви не відкриєте інструменти для розробників за допомогою F12та відкрийте вкладку консолі), може бути корисний наступний фрагмент. Це дозволяє використовувати, console.log(msg);як було використано в прикладах вище. Просто вставте його перед Podcastфункцією.

Для вашої зручності, ось наведений вище код в одному повному фрагменті одного коду:


Примітки:

  • Деякі хороші поради, підказки та рекомендації щодо програмування JavaScript в цілому ви можете знайти тут (кращі практики JavaScript) і там ("var" порівняно з "дозволити") . Також рекомендується ця стаття про неявні типові передачі (примус) .

  • Зручним способом використання класів та компіляції їх у JavaScript є TypeScript. Ось майданчик, де ви можете знайти кілька прикладів, що показують, як це працює. Навіть якщо на даний момент ви не використовуєте TypeScript, ви можете ознайомитися, оскільки ви можете порівнювати TypeScript з результатом JavaScript на поданні збоку. Більшість прикладів прості, але є також приклад Raytracer, який можна спробувати миттєво. Рекомендую особливо вивчити приклади "Використання класів", "Використання успадкування" та "Використання загальної інформації", вибравши їх у комбінаційному вікні - це приємні шаблони, які ви можете миттєво використовувати в JavaScript. Друкарський текст використовується з кутовим.

  • Щоб досягти інкапсуляції локальних змінних, функцій тощо у JavaScript, я пропоную використовувати такий зразок, як наступний (JQuery використовує ту саму техніку):

<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:&nbsp;</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>

Звичайно, ви можете - і повинні - помістити код сценарію в окремий *.jsфайл; це просто написано в рядку, щоб приклад був коротким.

Тут викладено більш докладно функції самозвання (також відомі як IIFE = Виявлення функцій негайно викликаних функцій) .


28
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();

28

Оновлена ​​відповідь:

У ECMAScript 6 ви можете створювати статичні функції за допомогою staticключового слова:

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 функції є об'єктами.


Foo.bar;повертає призначену йому функцію, а не рядок, повернуту функцією, як випливає з коментаря.

Чи можете ви додати трохи інформації про те, як встановити (перезаписати) статичне значення в цих обох прикладах?
Загинув

1
@ В обох випадках "статична" властивість - це лише властивість функції, тому ви встановлюєте її та перезаписуєте так само, як і будь-яке інше властивість у JavaScript. В обох випадках ви можете встановити barвластивість Fooдля 3як це:Foo.bar = 3;
Макс Heiber


16

Наступний приклад та пояснення - з книги 2-го видання «Професійний JavaScript для веб-розробників» Ніколаса Закаса. Це відповідь, яку я шукав, тому я вважав, що було б корисно додати її сюди.

(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Конструктор в даному прикладі , має доступ до імені приватної змінної, як це роблять getName()і setName()методи. Використовуючи цей шаблон, змінна імені стає статичною і буде використовуватися серед усіх примірників. Це означає, що виклик setName()одного екземпляра впливає на всі інші випадки. Виклик setName()або створення нового Personпримірника встановлює змінну імені на нове значення. Це змушує всі екземпляри повертати однакове значення.


виглядає конструктор + прототип (гібрид)
Ганеш Кумар

2
Це розміщує об’єкт Person у глобальному просторі імен. Я не рекомендував би рішення.
Ghola

Я не думаю, що це справжня статична змінна, оскільки вона інстанціюється по-різному з кожним новим об'єктом. Статичний об'єкт повинен відповідати всім об'єктам, успадкованим від батьківського прототипу?
lindsaymacvean

1
@Ghola Тут наміром було пояснити, як створити статичну змінну. Належне розміщення імен та уникнення глобальних даних - це окрема тема, яка, можливо, додала складності відповіді. Користувач повинен визначити, як приєднати конструктор без забруднення. Якщо це досить добре для Ніколаса Закаса, це для мене досить добре.
Нейт

@lindsaymacvean Це статична змінна, оскільки єдине значення поділяється у всіх примірниках. Добре, щоб значення змінилося. Якщо один екземпляр змінить значення, це вплине на всі екземпляри. Мабуть, він би використовувався точно так само, як наведений вище приклад. Дозволити встановлення значення під час створення екземпляра - це просто показати, що це можливо. Більш імовірним випадком використання буде мати лише геттера і сетера або принаймні перевірити, щоб переконатися, що він встановлений на щось інше, ніж невизначене.
Нейт

15

Якщо ви використовуєте синтаксис нового класу, тепер ви можете зробити наступне:

    class MyClass {
      static get myStaticVariable() {
        return "some static variable";
      }
    }

    console.log(MyClass.myStaticVariable);

    aMyClass = new MyClass();
    console.log(aMyClass.myStaticVariable, "is undefined");

Це ефективно створює статичну змінну в JavaScript.


Це корисно при побудові статичних класів корисності!
Індолінг

1
Але тепер питання полягає в тому, як ви зберігаєте значення і дозволяєте змінювати його за допомогою сетера. Потрібно буде закриття або властивість, MyClassвизначена поза конструкцією класу.
трінкот


8

Якщо ви хочете оголосити статичні змінні для створення констант у вашій програмі, я знайшов наступний як найбільш спрощений підхід

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;

8

Про class представлений ECMAScript 2015. Інші відповіді не зовсім зрозумілі.

Ось приклад, що показує, як створити статичний var staticVarза допомогою ClassName. varsyntax:

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

7

Є й інші подібні відповіді, але жодна з них не дуже сподобалась мені. Ось що я закінчив:

var nextCounter = (function () {
  var counter = 0;
  return function() {
    var temp = counter;
    counter += 1;
    return temp;
  };
})();

7

На додаток до решти, наразі є проект ( пропозиція 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 підтримує цю функцію плагіном властивостей класу перетворення, який ви можете використовувати. Додатково, хоча це ще триває, V8його впроваджують .


6

Ви можете створити статичну змінну в 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

Це один з хороших підходів до оголошення статичної змінної та доступу до неї в JavaScript.
ArunDhwaj IIITH

5

Якщо ви хочете зробити глобальну статичну змінну:

var my_id = 123;

Замініть змінну нижче:

Object.defineProperty(window, 'my_id', {
    get: function() {
            return 123;
        },
    configurable : false,
    enumerable : false
});

4

Найбільш близьким у статичній змінній в JavaScript є глобальна змінна - це просто змінна, оголошена поза межами функції або літерального об'єкта:

var thisIsGlobal = 1;

function foo() {
    var thisIsNot = 2;
}

Інша річ, яку ви можете зробити, - це зберігати глобальні змінні всередині об'єкта буквально, як це:

var foo = { bar : 1 }

А потім отримати доступ до variabels як це: foo.bar.


цей допоміг мені завантажити декілька файлів ..... var foo = {counter: 1}; функція moreFiles () {fileName = "Файл" + foo.counter; foo.counter = foo.counter + 1;
veer7

4

Щоб ущільнити всі поняття класу тут, протестуйте це:

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);

4

У JavaScript змінні за замовчуванням є статичними . Приклад :

var x = 0;

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

setInterval(draw, 1000);

Значення x збільшується на 1 кожні 1000 мілісекунд.
Він надрукує 1,2,3 тощо


2
Це інший випадок. Ваш приклад стосується сфери застосування.
Challet

4

Є ще один підхід, який вирішив мої вимоги після перегляду цієї теми. Це залежить від того, чого саме ви хочете досягти за допомогою "статичної змінної".

Глобальна властивість sessionStorage або localStorage дозволяє зберігати дані протягом життя сеансу або на невизначений довший період до явного очищення відповідно. Це дозволяє обмінюватися даними між усіма вікнами, кадрами, панелями вкладок, спливаючими вікнами і т. Д. Вашої сторінки / програми і набагато потужніше, ніж проста "статична / глобальна змінна" в одному сегменті коду.

Це дозволяє уникнути будь-яких клопотів із сферою, терміном служби, семантикою, динамікою тощо глобальних змінних верхнього рівня, тобто Window.myglobal. Не знаєте, наскільки це ефективно, але це не важливо для скромних обсягів даних, доступ до яких здійснюється з помірними темпами.

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


2

Функції / класи дозволяють використовувати лише один конструктор для його об'єктної області. Function Hoisting, declarations & expressions

  • Функції, створені за допомогою конструктора функцій, не створюють закриття для контекстів їх створення; вони завжди створюються в глобальному масштабі.

      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 - це як підтримка копією всіх локальних змінних його батьківської функції внутрішніми функціями.

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

Приклад : див. Моє попереднє повідомлення.


2

Існує 4 способи емуляції локальних функціональних статичних змінних у Javascript.

Спосіб 1: Використання властивостей об'єктних функцій (підтримується в старих браузерах)

function someFunc1(){
    if( !('staticVar' in someFunc1) )
        someFunc1.staticVar = 0 ;
    alert(++someFunc1.staticVar) ;
}

someFunc1() ; //prints 1
someFunc1() ; //prints 2
someFunc1() ; //prints 3

Спосіб 2: Використання закриття, варіант 1 (підтримується в старих браузерах)

var someFunc2 = (function(){
    var staticVar = 0 ;
    return function(){
        alert(++staticVar) ;
    }
})()

someFunc2() ; //prints 1
someFunc2() ; //prints 2
someFunc2() ; //prints 3

Спосіб 3: Використання закриття, варіант 2 (також підтримується у старих браузерах)

var someFunc3 ;
with({staticVar:0})
    var someFunc3 = function(){
        alert(++staticVar) ;
    }

someFunc3() ; //prints 1
someFunc3() ; //prints 2
someFunc3() ; //prints 3

Спосіб 4: Використання закриття, варіант 3 (потрібна підтримка EcmaScript 2015)

{
    let staticVar = 0 ;
    function someFunc4(){
        alert(++staticVar) ;
    }
}

someFunc4() ; //prints 1
someFunc4() ; //prints 2
someFunc4() ; //prints 3

2

Ви можете визначити статичні функції в JavaScript за допомогою staticключового слова:

class MyClass {
  static myStaticFunction() {
    return 42;
  }
}

MyClass.myStaticFunction(); // 42

З цього написання ви все ще не можете визначити статичні властивості (крім функцій) у класі. Статичні властивості все ще є пропозицією на етапі 3 , а це означає, що вони ще не є частиною JavaScript. Однак, ніщо не заважає вам просто привласнити клас, як ви хотіли, до будь-якого іншого об’єкта:

class MyClass {}

MyClass.myStaticProperty = 42;

MyClass.myStaticProperty; // 42

Підсумкове зауваження: будьте обережні щодо використання статичних об'єктів з успадкуванням - всі успадковані класи мають спільну копію об'єкта .


1

У 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

1

Я багато використовую змінні статичних функцій, і справді соромно, що JS не має вбудованого механізму для цього. Занадто часто я бачу код, де змінні та функції визначаються у зовнішній області, хоча вони просто використовуються всередині однієї функції. Це некрасиво, схильний до помилок і просто просить неприємностей ...

Я придумав наступний метод:

if (typeof Function.prototype.statics === 'undefined') {
  Function.prototype.statics = function(init) {
    if (!this._statics) this._statics = init ? init() : {};
    return this._statics;
  }
}

Це додає метод "статики" до всіх функцій (так, просто розслабтеся про це), коли його буде викликано, він додасть порожній об'єкт (_statics) до об'єкта функції та поверне його. Якщо функція init буде надана, _statics буде встановлено як результат init ().

Потім ви можете зробити:

function f() {
  const _s = f.statics(() => ({ v1=3, v2=somefunc() });

  if (_s.v1==3) { ++_s.v1; _s.v2(_s.v1); }
} 

Порівнюючи це з IIFE, що є іншою правильною відповіддю, на це є недоліком додавання однієї задачі та однієї, якщо під час кожного виклику функції та додавання члена '_statics' до функції, проте є кілька переваг: аргументи є на вгорі, не у внутрішній функції, використання "статичного" у внутрішньому коді функції є явним "_s". префікс, і в цілому простіше подивитися і зрозуміти.


1

Підсумок:

У ES6/ ES 2015 classключове слово було введено із супроводжуваним staticключовим словом. Майте на увазі, що це синтаксичний цукор над прототипною моделлю успадкування, яку втілює javsccript. staticКлючове слово працює наступним чином для методів:

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);


2
Він просив статичну змінну, а не статичну функцію.
Конрад Хьоффнер

1

Я використав прототип і таким чином він працював:

class Cat extends Anima {
  constructor() {
    super(Cat.COLLECTION_NAME);
  }
}

Cat.COLLECTION_NAME = "cats";

або за допомогою статичного геттера:

class Cat extends Anima {
  constructor() {
    super(Cat.COLLECTION_NAME);
  }

  static get COLLECTION_NAME() {
    return "cats"
  }
}

0

Параметри рівня вікон подібні до статики в тому сенсі, що ви можете використовувати прямий посилання, і вони доступні для всіх частин вашої програми


3
Значно кращий опис таких варіантів - "глобальний", а не статичний.
Патрік М

0

У Javascript немає такої речі, як статична змінна. Ця мова орієнтована на прототип, орієнтована на об'єкт, тому існують не класи, а прототипи, з яких об'єкти "копіюються".

Ви можете імітувати їх глобальними змінними або прототипуванням (додавання властивості до прототипу):

function circle(){
}
circle.prototype.pi=3.14159

Цей метод працює, але ви шліфуєтеFunction.prototype
Dan

@Dan: Наскільки я розумію, це було б просто для кола, а не для функції. Принаймні, це те, що Chrome намагається сказати мені: function circle() {}| circle.prototype| circle.prototype.pi = 3.14| circle.prototype| Function.prototype| Function.__proto__(якщо це саме ви мали на увазі)
Актау

0

Працюючи з веб-сайтами MVC, які використовують jQuery, я хочу переконатися, що дії AJAX у певних обробниках подій можуть бути виконані лише після завершення попереднього запиту. Для цього я використовую "статичну" об'єктну змінну jqXHR.

Дано таку кнопку:

<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);

0

Якщо ви хочете використовувати прототип, то є спосіб

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);

Зробивши це, ви зможете отримати доступ до змінної лічильника з будь-якого примірника, і будь-яка зміна властивості буде негайно відображена !!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.