Какой-либо способ определить методы считывания для ленивых переменных в массивах JavaScript?

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

То, что я закончил тем, что делал для объектов, было

Object.prototype.lazy = function(var_name, value_function) {
  this.__defineGetter__(var_name, function() {
    var saved_value = value_function();
    this.__defineGetter__(var_name, function() {
      return saved_value;
    });
    return saved_value;
  });
}

lazy('exampleField', function() {
  // the code that returns the value I want
});

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

Object.prototype.lazy_push = function(value_function) {
  if(!this.length)
    this.length = 0;
  this.lazy(this.length++, value_function);
}

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

ОБНОВЛЕНИЕ: следующая функция работает, только если value_function возвращает примитивный тип данных.

Array.prototype.lazy_push = function(value_function) {
  var a = this,
  i = this.length;
  this.push({
    toString: function() {
      return a[i] = value_function();
    }
  });
}

При попытке продвинуть, говорят, что объект, который имеет свойства в нем, Вы не сможете получить доступ к свойствам, пока Вы не получите доступ к объекту непосредственно. Этого не происходит с методами set, вот почему я хочу некоторый синтаксис установки для JavaScript. На данный момент я буду использовать поддельный массив, который является достаточно, для какого я делаю.

13
задан Community 23 May 2017 в 11:53
поделиться

4 ответа

Хорошо, если я не неправильно понял ваш вопрос, я считаю, что нашел простое решение, которое не требует так называемой функции "lazy_push".

Следуя методу из моего предыдущего ответа, вы создаете класс MyArray:

function MyArray(){
     this.object = [];
 }

MyArray.prototype.push = function(what){
     this.object.push(what);
}

Теперь важной частью является функция получения, мы создадим функцию getIdx () для получения значения из массива. Затем функция использует оператор typeof, чтобы определить, является ли возвращаемое значение функцией. Если это так, вернуть значение, возвращенное функцией, если нет, вернуть исходное значение.

Код имеет больше смысла:

MyArray.prototype.getIdx = function(which){
     if(typeof this.object[which] == 'function'){
         alert("a function");
         //NOTICE THE '()' AT THE END OF THE NEXT LINE!!!
         return this.object[which]();
     }
     return this.object[which];
 }

Надеюсь, если я не полностью отвечу на ваш вопрос, вы сможете понять это отсюда.

<--------- Мой исходный пост ------------->

Не совсем ответ, но несколько важных моментов.

  1. В Javascript нет реальных массивов, массив - это просто расширенный объект (как и все в JS).

  2. В идеале вы никогда не должны добавлять функции прототипа к собственным объектам в JS, вы можете случайно перезаписать существующее свойство, или создать запутанные ошибки в дальнейшем. Например, добавление к прототипу Object добавит к каждому отдельному объекту в JS (а это все), вам нужно быть абсолютно уверенным, что вы хотите, чтобы каждый тип в JS имел это свойство. Это просто опасно, потому что, если вы случайно перезапишете фактические функции Array () или Object (), вы сломаете javascript в браузере, точка, обновление страницы не исправит этого.

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

     // создайте конструктор,
    // с объектной переменной, которая содержит объект, который вы хотите расширить
    function MyArray () {
    this.object = [];
    }
    
    // создаем функции, которые ссылаются на собственные функции объекта
    MyArray.prototype.push = function (what) {
    this.object.push (что);
    }
    
    // И т. Д. ... И т. Д. .... И т. Д. .....
    

Написание всех методов доступа для собственных функций Object не обязательно весело, но это обеспечивает безопасность механизма Javascript.

2
ответ дан 2 December 2019 в 02:05
поделиться

Нет. К сожалению, это большая проблема.

1
ответ дан 2 December 2019 в 02:05
поделиться

Bleh . Это большая проблема, что вы не можете перегрузить оператор индексатора в JavaScript. Ну что ж. Нам просто нужно проявить творческий подход и придумать другое решение. Это хорошо (и весело). : -)

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

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

Итак, я размещаю свой проект на CodePlex, где я использую очень похожую на jQuery технику для определения свойств (автономные функции получения / установки), очень похожую на ту, которую вы используете. Для решения, которое я придумал, я просто экстраполировал из уже существующего моего кода. Вот мой подход к отложенной загрузке индексов массива. С самого начала ...

Давайте рассмотрим свойство с именем «PageSize». Вот как это свойство будет использоваться с моей техникой:

var MyClass = function() { }; // MyClass constructor.

var instance = new MyClass();
instance.PageSize(5);

alert(instance.PageSize());

Обратите внимание, что свойство - это единственная функция, где предоставление значения в качестве первого параметра вызывает установщик, а отсутствие параметра вызывает геттер. Свойство «PageSize» может быть определено как часть класса MyClass следующим образом:

MyClass.prototype.PageSize = function(v) { return this.GetSetProperty("PageSize", v, myFunctionThatDoesLazyLoading); };

Функция свойства - это просто оболочка вокруг вызова метода GetSetProperty, который выполняет фактическое получение и настройку. Вот фрагмент функции GetSetProperty:

Object.prototype.GetSetProperty = function(name, value, loadFunction) {
    if (!this.Properties)
    {
        this.Properties = {};
    }

if (value)
{
    this.Properties[name] = value;
}
else
{       
    if (!this.Properties[name] && loadFunction)
    {
        this.Properties[name] = loadFunction();
    }

    return this.Properties[name]; // This will return "undefined" if property doesn't exist or the loadFunction wasn't provided.
}
};

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

Object.prototype.GetSetProperty = function(name, value, loadFunction, index) {
  if (!this.Properties)
  {
    this.Properties = {};
  }

  if (typeof index === "number" && this.Properties[name] && this.Properties[name].constructor == Array)
  {
    return this.GetSetArrayProperty(name, index, value, loadFunction);
  }
  else 
  {
    value = index;
  }

  if (value)
  {
    this.Properties[name] = value;
  }
  else
  {    
    if (!this.Properties[name] && loadFunction)
    {
      this.Properties[name] = loadFunction();
    }

    return this.Properties[name]; // This will return "undefined" if property doesn't exist or the loadFunction wasn't provided.
  }
};


Object.prototype.GetSetArrayProperty = function(name, index, value, loadFunction) {
  if (value)
  {
    this.Properties[name][index] = value;
  }
  else
  {
    if (!this.Properties[name][index] && loadFunction)
    {
      this.Properties[name][index] = loadFunction();
    }

    return this.Properties[name][index];
  }
};

Объявление прототипа необходимо изменить следующим образом:

MyClass.prototype.PageSize = function(i, v) { return this.GetSetProperty("PageSize", v, myFunctionThatDoesLazyLoading, i); };

Каждый, кто читает это, может получить доступ к рабочему набору. кода здесь: http://jsbin.com/ajawe/edit

Вот полный список кода с тестами:

Object.prototype.GetSetProperty = function(name, value, loadFunction, index) {
  if (!this.Properties)
  {
    this.Properties = {};
  }

  if (typeof index === "number" && this.Properties[name] && this.Properties[name].constructor == Array)
  {
    return this.GetSetArrayProperty(name, index, value, loadFunction);
  }
  else 
  {
    value = index;
  }

  if (value)
  {
    this.Properties[name] = value;
  }
  else
  {    
    if (!this.Properties[name] && loadFunction)
    {
      this.Properties[name] = loadFunction();
    }

    return this.Properties[name]; // This will return "undefined" if property doesn't exist or the loadFunction wasn't provided.
  }
};


Object.prototype.GetSetArrayProperty = function(name, index, value, loadFunction) {
  if (value)
  {
    this.Properties[name][index] = value;
  }
  else
  {
    if (!this.Properties[name][index] && loadFunction)
    {
      this.Properties[name][index] = loadFunction();
    }

    return this.Properties[name][index];
  }
};


// Here's a nifty function that declares the properties for you.
Function.prototype.CreateProperty = function(propertyName, loadFunction) {
  eval("this.prototype['" + propertyName.toString() + "'] = function(i, v) { return this.GetSetProperty('" + propertyName.toString() + "', v, " + eval(loadFunction) + ", i); };");
};




var myFunctionThatDoesLazyLoading = function() {
  return "Ahoy!";
};


var MyClass = function() { }; // MyClass constructor.
MyClass.prototype.PageSize = function(i, v) { return this.GetSetProperty("PageSize", v, myFunctionThatDoesLazyLoading, i); };

var instance = new MyClass();
alert(instance.PageSize()); // PageSize is lazy loaded.

instance.PageSize(5); // PageSize is re-assigned.
alert(instance.PageSize()); // Returns the new value.

instance.PageSize([1, 2, 3]); // PageSize is re-assigned to have an Array value.
alert(instance.PageSize(2)); // Returns the value at index 2 of the Array value.

instance.PageSize(2, "foo"); // Re-assigns the value at index 2.
alert(instance.PageSize(2)); // Returns the new value at index 2.

MyClass.CreateProperty("NewProp", function() { return ["a", "b", "c"]; }); // Demo of the CreateProperty function.
alert(instance.NewProp());
alert(instance.NewProp(1));
1
ответ дан 2 December 2019 в 02:05
поделиться

Мне не особенно нравится этот ответ, но не могли бы вы сохранить свою «переменную» в виде строки выражения, а затем использовать eval (), когда она вам понадобится? Не идеально, но он компактен ...

var x = 10, arr = [];
arr.push("x + 10");
alert(eval(arr[0]));
x = 20;
alert(eval(arr[0]));

Я тестировал его, и он работает, даже если не совсем то, что вы ищете.

1
ответ дан 2 December 2019 в 02:05
поделиться
Другие вопросы по тегам:

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