Статические переменные в JavaScript

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

553
задан Rajat 08 окт. '09 в 7:31
источник поделиться

36 ответов

  • 1
  • 2

Если вы исходите из объектно-ориентированного языка на основе классов (например, Java, С++ или С#), я предполагаю, что вы пытаетесь создать переменную или метод, связанные с "типом", но не с экземпляром.

Пример, использующий "классический" подход, с функциями конструктора, возможно, может помочь вам понять концепции базового 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 рассматривает функции как первоклассный объектов, поэтому, являясь объектом, вы можете назначить свойства функции.

743
ответ дан CMS 08 окт. '09 в 7:49
источник поделиться

Вы можете воспользоваться тем фактом, что функции 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.

Что дает вам тот же результат - за исключением того, что на этот раз возвращается значение с добавленным значением, а не отображается.

465
ответ дан Pascal MARTIN 08 окт. '09 в 7:37
источник поделиться

Вы выполняете это через IIFE (сразу вызываемое выражение функции):

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

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

incr(); // returns 1
incr(); // returns 2
60
ответ дан khoomeister 30 марта '13 в 13:02
источник поделиться

вы можете использовать arguments.callee для хранения "статических" переменных (это полезно и для анонимной функции):

function () {
  arguments.callee.myStaticVar = arguments.callee.myStaticVar || 1;
  arguments.callee.myStaticVar++;
  alert(arguments.callee.myStaticVar);
}
36
ответ дан gpilotino 06 нояб. '09 в 14:19
источник поделиться
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();
24
ответ дан jim_zike_huang 28 февр. '12 в 23:08
источник поделиться

Я видел пару подобных ответов, но я хотел бы упомянуть, что этот пост описывает это лучше всего, d хотел бы поделиться им с вами.

Вот код, взятый из него, который я изменил, чтобы получить полный пример, который, надеюсь, дает пользу сообществу, потому что он может использоваться как шаблон дизайна для классов.

Он также отвечает на ваш вопрос:

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 ...'

И свойства/функции объекта просто:

// 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 хранится внутри функции.

Вы даже можете определить getters и seters. Взгляните на этот фрагмент кода (где 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 в третьем параметре, например. 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, свойство readonly b и свойство write-only 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]"

Подробнее о прототипах здесь. Если вы хотите сделать больше наследования, я предлагаю изучить этот.


Серия статей Я уже упоминал выше, рекомендуется читать, они включают также следующие темы

  • Функции
  • Объекты
  • Прототипы
  • Выполнение новых функций конструктора
  • Подъемно
  • Автоматическая точка с запятой
  • Статические свойства и методы

Примечание, что автоматическая точка с запятой "функция" JavaScript (как упоминается в 6.) очень часто ответственный за причинение странных проблем в вашем коде. Следовательно, я бы предпочел рассматривать это как ошибку, а не как функцию.

Если вы хотите больше узнать, здесь - довольно интересная статья MSDN об этих темах, некоторые из них описанные там, предоставляют еще более подробную информацию.

Что такое интересно читать (также охватывающие темы, упомянутые выше), являются те статьи из MDN JavaScript Guide:


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

Для вашего удобства здесь приведен код выше в одном полном фрагменте кода:

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>

Примечание.. Удобный способ использования классов и компиляции их в JavaScript - TypeScript. Вот площадка, где вы можете найти несколько примеров, показывающих, как это работает. Даже если вы не используете TypeScript на данный момент, вы можете посмотреть, потому что вы можете сравнить TypeScript с результатом JavaScript в бок о бок. Большинство примеров просты, но есть и пример Raytracer, который вы можете попробовать мгновенно. Я рекомендую особенно изучать примеры "Использование классов", "Использование наследования" и "Использование общих", выбирая их в combobox - это красивые шаблоны, которые вы можете мгновенно использовать в JavaScript.

21
ответ дан Matt 10 сент. '13 в 14:53
источник поделиться

Обновленный ответ:

В 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 есть объекты.

16
ответ дан Max Heiber 27 марта '15 в 4:09
источник поделиться

Следующий пример и пояснения приведены в книге Professional JavaScript for Web Developers 2nd Edition от Николаса Закаса. Это ответ, который я искал, поэтому я подумал, что было бы полезно добавить его здесь.

(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(). Используя этот шаблон, переменная name становится статической и будет использоваться для всех экземпляров. Это означает, что вызов setName() в одном экземпляре затрагивает все другие экземпляры. Вызов setName() или создание нового экземпляра Person задает переменную имени для нового значения. Это заставляет все экземпляры возвращать одинаковое значение.

13
ответ дан Nate 13 дек. '11 в 11:26
источник поделиться

Если вы используете новый синтаксис класса, вы можете сделать следующее:

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

    console.log(MyClass.myStaticVariable);

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

Это эффективно создает статическую переменную в JavaScript.

5
ответ дан Automatico 22 февр. '17 в 19:11
источник поделиться

Если вы хотите объявить статические переменные для создания констант в своем приложении, я нашел следующий как наиболее упрощенный подход

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;
4
ответ дан Hemant 03 апр. '13 в 1:05
источник поделиться

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

var nextCounter = (function () {
  var counter = 0;
  return function() {
    var temp = counter;
    counter += 1;
    return temp;
  };
})();
4
ответ дан funroll 08 февр. '15 в 6:34
источник поделиться

Вы можете создать статическую переменную в 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
3
ответ дан Sнаđошƒаӽ 31 июля '16 в 9:16
источник поделиться

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

var my_id = 123;

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

Object.defineProperty(window, 'my_id', {
    get: function() {
            return 123;
        },
    configurable : false,
    enumerable : false
});
3
ответ дан JoolzCheat 16 марта '12 в 6:56
источник поделиться

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

Вот пример, показывающий, как создать статический var 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 static! :)

MyClass.staticVar = 12;
console.log(class1.constructor.staticVar); // 12
console.log(class2.constructor.staticVar); // 12
3
ответ дан COil 24 марта '17 в 13:02
источник поделиться

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

var thisIsGlobal = 1;

function foo() {
    var thisIsNot = 2;
}

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

var foo = { bar : 1 }

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

2
ответ дан Andrew Hare 08 окт. '09 в 7:33
источник поделиться

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

var x = 0;

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

setInterval(draw, 1000);

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

2
ответ дан Kerim 08 апр. '17 в 15:39
источник поделиться

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

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);
2
ответ дан Stratboy 24 нояб. '13 в 14:20
источник поделиться

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

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

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

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

Приветствия, Грег E

2
ответ дан Greg E 07 апр. '13 в 12:58
источник поделиться

Источник: - static

введите описание изображения здесь

Ключевое слово статическое определяет статический метод для класса.

Синтаксис

static methodName() {...}

Описание

Статические вызовы методов выполняются непосредственно в классе и не подлежат вызову в экземплярах класса. Статические методы часто используются для создания служебных функций.

class StaticMethodCall {
  static staticMethod() {
    const str = 'Static method has been called';
    console.log(str);
    return str;
  }
  static anotherStaticMethod() {
    console.log(`${this.staticMethod()} from another static method`);
  }
}
StaticMethodCall.staticMethod(); 
// 'Static method has been called'

StaticMethodCall.anotherStaticMethod(); 
// 'Static method has been called from another static method'
1
ответ дан Tushar Gupta 05 дек. '17 в 14:34
поделиться

Классы уровня окна сортируются как статика в том смысле, что вы можете использовать прямую ссылку, и они доступны для всех частей вашего приложения.

0
ответ дан Bostone 08 окт. '09 в 7:34
источник поделиться

Если вы хотите использовать прототип, тогда есть способ

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

Выполняя это, вы сможете получить доступ к переменной счетчика из любого экземпляра, и любое изменение свойства будет немедленно отражено!

0
ответ дан charlie 09 мая '14 в 9:25
источник поделиться

В JavaScript нет термина или ключевого слова static, но мы можем поместить такие данные непосредственно в объект функции (как и в любом другом объекте).

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
0
ответ дан Satyapriya Mishra 31 марта '16 в 20:44
источник поделиться

Для частных статических переменных я нашел этот способ:

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
0
ответ дан Martin Wantke 25 окт. '16 в 15:42
источник поделиться

Итак, что я вижу с другими ответами, так это то, что они не учитывают фундаментальное архитектурное требование статического атрибута в объектно-ориентированном программировании.

Объектно-ориентированное программирование на самом деле имеет два разных стиля: один - "основанный на классе" (С++, С#, 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
});

Во-вторых, даже если вы это сделаете, этот атрибут будет доступен для редактирования из любой другой части вашего собственного script, так что может быть, что ошибка в вашем коде записывает атрибут на одном из дочерние объекты и отделяют его от родительского прототипа, поэтому, если вы измените родительский атрибут, он больше не будет каскадироваться и изменить статический атрибут для дочернего объекта. См. этот jsfiddle. В разных сценариях мы могли либо Object.freeze(obj) остановить любые изменения дочернего объекта, либо мы могли бы настроить сеттер и getter метод в конструкторе и доступ к закрытию, оба из них имеют связанные сложности.

Мне кажется, что нет идеального аналога между основанной на классе идеей "статического атрибута" и этой реализации Javascript. Поэтому я думаю, что в конечном итоге может быть лучше использовать другой код кода, который больше подходит Javascript. Например, центральный хранилище данных или кеш или даже выделенный вспомогательный объект для хранения всех необходимых статических переменных.

0
ответ дан lindsaymacvean 11 нояб. '15 в 6:01
источник поделиться

В JavaScript все либо является примитивным типом, либо объектом. Функции - объекты — (пары ключевых значений).

Когда вы создаете функцию, вы создаете два объекта. Один объект, который представляет собой функцию, а другую, которая представляет прототип функции.

Функция в основном в этом смысле является объектом со свойствами:

function name, 
arguments length 
and the functional prototype.

Итак, где установить статическое свойство: Два места, либо внутри объекта функции, либо внутри объекта прототипа функции.

Вот фрагмент, который создает этот конец, даже создает экземпляры двух экземпляров, используя ключевое слово new JavaScript.

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

Основная идея заключается в том, что экземпляры i1 и i2 используют одни и те же статические свойства.

0
ответ дан prosti 07 февр. '17 в 21:16
источник поделиться

Попробуйте следующее:

Если мы определяем свойство и переопределяем его получатели и сеттеры для использования свойства Function Object, то в теории вы можете иметь статическую переменную в javascript

например:

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.
0
ответ дан user2959417 09 нояб. '16 в 21:57
источник поделиться

Следует отметить две основные особенности: в спецификации EcmaScript 5

  • JavaScript не имеет концепцию classes.
  • JavaScript содержит концепцию функции.

Давайте возьмем эту функцию/класс под названием Foo и попробуем установить для нее статическую переменную.

function Foo() {

}

Согласно второму пункту, о котором я упоминал ранее, класс является функцией в JavaScript. Если мы хотим создать новый экземпляр (объект) этого класса/функции, мы будем использовать его следующим образом.

new Foo();

Но поскольку нам нужно создать статическую переменную (переменную класса/класса), переменная непосредственно должна привязываться к функции Foo

Есть три способа сделать это

  • Привязать статическую переменную непосредственно к функции Foo (это автоматически получает привязки к объекту proto)

Foo.staticVariableName = 'staticValue';

  1. Привяжите статическую переменную к объекту dunder proto (__proto__) в функции Foo. (Плохо: потому что есть проблема с производительностью)

Foo.__ proto __. staticVariableName = 'staticValue';

  1. Привязать статическую переменную к прототипу конструктора функции Foo (та же ссылка будет создана для объекта dunder proto)

Foo.constructor.prototype.staticVariableName = 'staticValue';

В приведенных выше способах вы можете просто получить доступ к Foo.staticVariableName.

Примечание: не привязывать непосредственно staticVariable к объекту прототипа в функции Foo

Foo.prototype.staticVariableName = 'staticValue';

Затем это staticVariableName будет доступно только при создании нового объекта функции Foo

Чтобы понять, как эта работа по связыванию __proto__ вы можете сослаться на эту диаграмму Схема цепочек прототипов JavaScript

0
ответ дан noelyahan 04 мая '17 в 9:48
источник поделиться

Работая с веб-сайтами 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
ответ дан Todd L 13 марта '14 в 0:02
источник поделиться

Я не видел эту идею ни в одном из ответов, поэтому просто добавляю ее в список. Если это дубликат, просто дайте мне знать, и я удалю его и переадресую другое.

На моем веб-сайте я создал своего рода супер-глобальный. Поскольку у меня есть несколько js файлов, загружаемых на каждую загрузку страницы и десятки других js файлов, которые загружаются только на некоторые страницы, я помещаю всю "глобальную" функцию в одну глобальную переменную.

В верхней части моих первых включенных "глобальных" файлов есть объявление

var cgf = {}; // Custom global functions.

Затем я обрабатываю несколько глобальных вспомогательных функций

cgf.formBehaviors = function()
{
    // My form behaviors that get attached in every page load.
}

Тогда, если мне нужна статическая переменная, я просто храню ее вне области видимости, например, вне документа, готового или вне приложения поведения. (Я использую 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;
}

Это, конечно, глобальный, а не статический, но поскольку он повторно инициализируется при каждой загрузке страницы, он выполняет ту же цель.

0
ответ дан danielson317 12 февр. '16 в 19:45
источник поделиться

Функция/классы допускает только один конструктор для области своего объекта. 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 похоже на сохранение копии всех локальных переменных его родительской функции с помощью внутренних функций.

      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

ES6 Классы: классы ES2015 - это простой сахар над образцом OO на основе прототипа. Наличие единой удобной декларативной формы упрощает использование классов классов и поощряет интероперабельность. Классы поддерживают наследование на основе прототипов, супер вызовы, экземпляры и статические методы и конструкторы.

Пример: см. мою предыдущую запись.

0
ответ дан Yash 24 авг. '17 в 17:09
источник поделиться
  • 1
  • 2

Другие вопросы по меткам