Как я вычисляю переменную в JavaScript, если и только если он используется?

Это - то, что я делаю прямо сейчас.

var foo = function() {
  var x = someComplicatedComputationThatMayTakeMoreTime();
  this.foo = function() { return x; };
  return x;
}

Это работает, но только если нечто называют как функция как так

foo();

Но что, если я хочу назвать его как нормальную переменную со значением? Я мог изменить код, чтобы быть

var foo = function() {
  var x = someComplicatedComputationThatMayTakeMoreTime();
  this.foo = x;
  return x;
}

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

Это даже возможно в JavaScript?

BTW, это для расширения Chrome/Firefox, таким образом, совместимость IE не имеет значения.

Законченное использование toString, потому что методы считывания не позволяют мне переопределять целый атрибут, функция, должно быть связано с ним. И toString имеет более чистый синтаксис.

9
задан Daniel Vassallo 24 April 2010 в 23:35
поделиться

8 ответов

Как насчет использования toString?

var foo = function() {
  function someComplicatedComputationThatMayTakeMoreTime() {
        //your calculations
  }
  return {
      toString: function() { 
           return someComplicatedComputationThatMayTakeMoreTime(); 
      }
  }
}

Подробнее о преобразованиях объектов в примитивы в JavaScript

РЕДАКТИРОВАТЬ на основе комментариев. Используйте синглтон (я думаю, он называется):

myObject.prop = (function(){ 
                  function someComplicatedComputationThatMayTakeMoreTime() {
                   //your calculations
                  }
                  return { 
                    toString: function() { 
                     return someComplicatedComputationThatMayTakeMoreTime(); 
                    } 
                  } 
                })()
7
ответ дан 4 December 2019 в 11:04
поделиться

Если бы не существовало только Internet Explorer, вы могли бы использовать геттеры и сеттеры, как описано Джоном Ресигом в этой статье блога:

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

4
ответ дан 4 December 2019 в 11:04
поделиться

Я бы порекомендовал вариант ответа ChaosPandion , но с закрытием.

var myProperty = (function () {
  var innerProperty = null;
  return function() {
    return (innerProperty = innerProperty ||  someComplicatedComputationThatMayTakeMoreTime());
  };
})();

, а затем используйте myProperty () каждый раз, когда вам нужно получить доступ к переменной.

1
ответ дан 4 December 2019 в 11:04
поделиться

Это непрактично в Интернете, потому что IE не поддерживает его, но вы можете посмотреть https: // developer .mozilla.org / en / defineGetter , где приведены примеры того, как это сделать.

Есть несколько способов сделать это, вот один пример:

var data = {};
data.__defineGetter__("prop",
                      (function () {
                           var value = null;
                           return function () {
                             if (null == value) {
                               value = getYourValueHere();
                             }
                             return value;
                           };
                        })());

и теперь вы можете использовать это как:

var a = data.prop;
var b = data.prop;
2
ответ дан 4 December 2019 в 11:04
поделиться

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

var myProperty = null;
function getMyProperty() {
    return (myProperty = myProperty ||  builder());
}
2
ответ дан 4 December 2019 в 11:04
поделиться

Использование функции - ваш лучший вариант на данный момент , однако новый стандарт JavaScript (ECMAScript 5th Ed.), Который сейчас , реализованный сейчас всеми основными поставщиками браузеров, дает вам метод для создания свойств доступа , где вы можете определить свойство с помощью get и набора функции, которые будут вызываться изнутри, не беспокоясь о том, чтобы рассматривать эти свойства как функции, например:

var obj = {};
Object.defineProperty(obj, 'foo', {
  get: function () { // getter logic
    return 'foo!';
  },
  set: function (value) {
    // setter logic
  }
});

obj.foo; // "foo!", no function call

Реализация этого нового стандарта для всех браузеров займет некоторое время (предварительная версия IE9 действительно меня разочаровала) , и я бы не рекомендовал вам использовать его в производственной среде, если у вас нет полного контроля над средой, в которой будет использоваться ваше приложение.

3
ответ дан 4 December 2019 в 11:04
поделиться

Вы можете определить геттер JavaScript. Из Apple JavaScript Coding Guidelines :

myObject.__defineGetter__( "myGetter", function() { return this.myVariable; } );
var someVariable = myObject.myGetter;

См. Сообщение Джона Ресига, Геттеры и сеттеры JavaScript , а также страницу Определение геттеров и сеттеров на сайте Центр разработчиков Mozilla для получения дополнительной информации.

0
ответ дан 4 December 2019 в 11:04
поделиться

Я бы использовал явное ленивое вычисление. Вот моя реализация, основанная на дубле Scheme:

var delay, lazy, force, promise, promiseForced, promiseRunning;

(function () {

  var getValue = function () {
    return this.value;
  };

  var RUNNING = {};

  var DelayThunk = function (nullaryFunc) {
    this.value = nullaryFunc;
  };
  DelayThunk.prototype.toString = function () {
    return "[object Promise]";
  };
  DelayThunk.prototype.force = function () {
    if (promiseRunning (this)) {
      throw new Error ("Circular forcing of a promise.");
    }
    var nullaryFunc = this.value;
    this.value = RUNNING;
    this.value = nullaryFunc ();
    this.force = getValue;
    return this.value;
  };

  var LazyThunk = function (nullaryFunc) {
    DelayThunk.call (this, nullaryFunc);
  };
  LazyThunk.prototype = new DelayThunk (null);
  LazyThunk.prototype.constructor = LazyThunk;
  LazyThunk.prototype.force = function () {
    var result = DelayThunk.prototype.force.call (this);
    while (result instanceof LazyThunk) {
      result = DelayThunk.prototype.force.call (result);
    }
    return force (result);
  };

  delay = function (nullaryFunc) {
    return new DelayThunk (nullaryFunc);
  };

  lazy = function (nullaryFunc) {
    return new LazyThunk (nullaryFunc);
  };

  force = function (expr) {
    if (promise (expr)) {
      return expr.force ();
    }
    return expr;
  };

  promise = function (expr) {
    return expr instanceof DelayThunk;
  };

  promiseForced = function (expr) {
    return expr.force === getValue || !promise (expr);
  };

  promiseRunning = function (expr) {
    return expr.value === RUNNING || !promise (expr);
  };

}) ();

Пример синтаксиса:

var x = lazy (function () { return expression; });
var y = force (x);

var z = delay (function () { return expression; });
var w = force (z);

Значения примечания сохраняются после оценки, поэтому повторное форсирование не приведет к дополнительным вычислениям.

Пример использования:

function makeThunk (x, y, z) {
  return lazy (function () {
    // lots of work done here
  });
}

var thunk = makeThunk (arg1, arg2, arg3);

if (condition) {
  output (force (thunk));
  output (force (thunk)); // no extra work done; no extra side effects either
}
0
ответ дан 4 December 2019 в 11:04
поделиться
Другие вопросы по тегам:

Похожие вопросы: