Pull to refresh

Comments 27

var counterFunction = function() {
  var counter = 0;
  return function() {
    alert(++counter);
  }
}
в том, что нельзя просто взять и посмотреть значение это счётчика… нужно ковыряться с отладчиком или мутить какую-то логику внутри функции…
имел ввиду

var counterFunction = (function() {
  var counter = 0;
  return function() {
    alert(++counter);
  }
})();

Можно и вот так:

var counterFunction = (function(counter){
    return function(){
        alert(++counter);
    }
})(0)
можно и замыканиями, только Internet Explorer имеет два отдельных сборщика мусора: один для Javascript и другой для объектов DOM. При выгрузке страницы браузер просматривает и удаляет весь код Javascript и все объекты DOM со страницы. Утечка памяти происходит, когда имеются циклические ссылки из объекта DOM в Javascript и снова на объект DOM или из Javascript-->Dom-->Javascript. Internet Explorer запутывается и не удаляет объекты при циклической ссылке. Плюс счетчик это просто пример. Есть более выгодные применения статических переменных
А можно подробней про утечку памяти? Может кто статью подскажет?
Замечаю, если игру с аяксом(пример www.weewar.com) оставить влюченой на пару часов, то Firefox занимает все больше и больше памяти (у меня до 600мб доходило).
function someFunc() {
    arguments.callee.staticVar = (typeof arguments.callee.staticVar == 'undefined')? («start value»): arguments.callee.staticVar;
}
А какова цель? Если нужно разделяемое между всем объектами свойство, то можно и прототип зайдествовать (это одна из его сущностей). Можно и в конструкторе хранить, только по идее, объект, после того, как был порождён, может уже не иметь связи с конструктором — конструктор может издохнуть, и это не отобразиться на объекте и его прототипе.
Есть небольшая разница в области видимости.
обьявление в прототипе разделит свойство для всех экземпляров.
обьявление в конструкторе и есть замыкание, которое живет не зависимо от конструктора после создания экземпляра. И область видимости — только данный экземпляр.
> обьявление в прототипе разделит свойство для всех экземпляров.

Ну, это можно считать разновидностью static-а — свойство одно на все экземпляры.

> обьявление в конструкторе и есть замыкание

В смысле, объявление свойством функции? Нет, это не замыкание, это обычное свойство функции.

> которое живет не зависимо от конструктора после создания экземпляра

Замыкание может жить не зависимо от жизни порождаемого контекста. А экземпляр-то тут при чём? Конструктор порождает экземпляры, экземпляры имеют связь с конструктором через [[Prototype]].constructor. Объявляя свойство в конструкторе, это то же самое, что [[Prototype]].constructor.нашеСвойство; и с этой точки зрения, появляется лишь лишнее промежуточное свойство .constructor, чтобы достучаться до .нашеСвойство (если было бы в прототипе, — [[Prototype]].нашеСвойство). Однако, если объекты сами будут иметь такое свойство, то протоип уже не подойдёт, т.к. будет сразу найдено родное свойство.

> И область видимости — только данный экземпляр.

Какой данный эземпляр? Объявляя свойство в конструкторе — вы просто объявляется свойство в конструкторе, независимом объекте. Порождаемые конструктором объекты, после порождения уже могут быть не связаны с конструктором. Поэтому, в качестве этого хранилища может абсолютно любой объект, но конструктор — да, наиболее подходящий (по смыслу). Хранение в прототипе привёл в качестве альтернативы (хотя, здесь расшаривается только на чтение, после первой записи, объекты будет уже иметь своё такое свойство).
> обьявление в прототипе разделит свойство для всех экземпляров.

Ну, это можно считать разновидностью static-а — свойство одно на все экземпляры.


С точки зрения классического классового ООП — это и есть реализация static :)

> обьявление в конструкторе и есть замыкание

В смысле, объявление свойством функции? Нет, это не замыкание, это обычное свойство функции.


зачем свойство? просто переменная, доступная методам через замыкание, в котором сохранен контекст функции-конструктора.

Похоже мы по-разному используем обьекты в JS.
> зачем свойство? просто переменная, доступная методам через замыкание, в котором сохранен контекст функции-конструктора.

Я просто подумал, что вы говорите про:

function A() {}
A.staticProperty = 10;

а не про:

function A() {
  var counter = 0;
  return function() {
    alert(++counter);
  };
}

Кстати, этот второй случай — лишь создание внутреннего замыкания; в качестве же конструктора такую функцию уже не использовать (т.к возвращается не объект и не this, а функция), поэтому, это вряд ли может подойти под определение static в плане расшаривания свойств между экземплярами конструктора. Да, переменная counter будет шарится между вызовами замкнутой анонимной функции (через [[Scope]]), но только это не относится к созданию экземпляров и расшаренного между ними («статического») свойства.

Если в качестве конструктора использовать эту возвращённую функцию — то тоже смысла мало, counter будет доступен только в пределах этого анонимного конструктора.

Ещё можно такой вариант использовать — хранить не в самом прототипе, в скопе обрамляющей функции при описании прототипа. Получится, что переменная также расшарена между всеми экзеплярами, но ещё и недоступна снаружи:

function A() {} // конструктор

A.prototype = (function () { // обрамляющий контекст

  // расшаренное "статическое" свойство
  var sharedProperty = 10;

  // сам прототип
  return {

    constructor: A,

    getSharedProperty: function () {
      return sharedProperty;
    },

    setSharedProperty: function (newValue) {
      sharedProperty = newValue;
    }
  };
})();

var a = new A;
var b = new A;

alert(a.getSharedProperty()); // 10
alert(b.getSharedProperty()); // 10

b.setSharedProperty(20);

alert(a.getSharedProperty()); // 20
alert(b.getSharedProperty()); // 20

Кстати, этот второй случай — лишь создание внутреннего замыкания; в качестве же конструктора такую функцию уже не использовать (т.к возвращается не объект и не this, а функция), поэтому, это вряд ли может подойти под определение static в плане расшаривания свойств между экземплярами конструктора. Да, переменная counter будет шарится между вызовами замкнутой анонимной функции (через [[Scope]]), но только это не относится к созданию экземпляров и расшаренного между ними («статического») свойства.

Если в качестве конструктора использовать эту возвращённую функцию — то тоже смысла мало, counter будет доступен только в пределах этого анонимного конструктора.


Вот такой вариант думаю будет нагляднее:

var o1 = new obj();
o1.increment();

function obj() {
var counter=0;
this.increment = function() {
counter++;
}
}


И в итоге counter, равно как и .increment будет у каждого свой, это уж точно не «статическая переменная».
да, это совсем не static в том смысле в котором он значит в классовом ООП. Это скорее private.
Ага, пожалуй. Только этот private тоже до конца не скрыт (в некоторых реализациях можно свободно менять var-ы из замкнутого контекста). Вот здесь немного писал об этом.
и чем это лучше чем свойство в windows, то бишь «глобальная переменная»?
Тем, что эта переменная доступна лишь в области видимости фнукции, в которй определена.
Мда?

alert(counterFunction.counter);
counterFunction();
alert(counterFunction.counter);


выдает undefined и 0
и можно свободно делать counterFunction.counter=100 снаружи, например.
т.е. только вариант с замыканием самый правильный?
если надо ограничить область видимости — то имхо да.

А вообще статическая переменная в JS классически используется через замыкание. Самый избитый пример var t=this;
Спасибо, ошибся.

Собственно вижу что переменная counter есть ничто иное как
window.counterFunction.counter
Sign up to leave a comment.

Articles