Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Function Cache (https://javascript.ru/forum/misc/52176-function-cache.html)

y0uix 06.12.2014 22:41

Function Cache
 
Всем привет!

Задача в том, что:

0) Создается некоторая функция, принимающая N аргументов;
1) Создается кэширующая функция, которая принимает вышеуказанную в качестве фунарга и дальше с возвращенным ей значением мы можем работать следующим образом:
- если такая функция-обертка вызывается с новым набором аргументов, то выполняется оригинальная функция;
- в противном случае, если вызов с такими аргументами уже был, то возвращается закэшированный результат, без вызова.

Вот оригинальное описание: "If you are calculating complex things or execute time-consuming API calls, you sometimes want to cache the results. In this case we want you to create a function wrapper, which takes a function and caches its results depending on the arguments, that were applied to the function."

Мой код:

function cache(func) {
  var cached_func = func,
      cached_func_data = [];
  
  return function() {
    var args_len = arguments.length,
        i,
        j;
    
    if (!cached_func_data.length) {
      return callCachedFunc(arguments);
    }
    
    for (i = 0; i < args_len; i++) {
      for (j = 0; j < cached_func_data[i].args.length; j++) {
        if (cached_func_data[i].args[i] === arguments[i]) {
          continue;
        }
        return cached_func_data[i].res;
      }
      return callCachedFunc(arguments);
    }
    
    function callCachedFunc(arguments) {
      var cache_obj = {};
      cache_obj.args = Array.prototype.slice.call(arguments);
      cache_obj.res = cached_func.apply(null, arguments);
      cached_func_data.push(cache_obj);
      return cache_obj.res;
    }
  }
}


Прошу провести ревью кода. Решение не полностью корректно, но я не могу пока что, к большому своему огорчению, найти ошибку.

Спасибо.

y0uix 06.12.2014 23:18

Вот пример использования:
var complexFunction = function(arg1, arg2) { /* complex calculation in here */ };
var cachedFunction = cache(complexFunction);

cachedFunction('foo', 'bar'); // complex function should be executed
cachedFunction('foo', 'bar'); // complex function should not be invoked again, instead the cached result should be returned
cachedFunction('foo', 'baz'); // should be executed, because the method wasn't invoked before with these arguments


Заранее благодарен за любые комментарии по делу.

nerv_ 07.12.2014 00:48

https://yadi.sk/i/er6gs7TEdCUGg

krutoy 07.12.2014 02:37

nerv_,
чушь собачья
a=Object.create({a: 1})
b=Object.create({a: 2})
fu=function(){
  var f=function(arg){return arg.a} 
  return function(){alert(JSON.stringify(arguments)); return f(arguments[0])}
}()

alert(fu(a))
alert(fu(b))

//  {"0":{}}
//  1
//  {"0":{}}
//  2

Закешировали, ага.

bes 07.12.2014 10:37

я вчера было уже хотел выложить вариант с двумя массивами, но вариант nerv_ c cache[stamp] дал понять, где настоящий скил :)

в качестве отработки при помощи FineReader-a извлёк код nerv_ (шутка :D )
function f(a, b, c) {
	return a * b + c;
};

function cacheFn(fn) {
	var cache = {};
	return function () {
		var stamp = JSON.stringify(arguments); 
		console.log(cache);
		if (!(stamp in cache)) {
			cache[stamp] = fn.apply(this, arguments);
			console.log("call: " + cache[stamp]);
		}
		console.log("cache: " + cache[stamp] + "\n\n");
		return cache[stamp];
	
	}
}

var cacheF = cacheFn(f);
cacheF(2, 2, "asdf");
cacheF(2, 2, "asdf");
cacheF(2, 3, "asdf");
cacheF(2, 3, "asdf");

Vlasenko Fedor 07.12.2014 12:35

if (!cache.hasOwnProperty(stamp)) {/*... */}

а так не лучше будет?

bes 07.12.2014 12:51

Цитата:

Сообщение от Poznakomlus (Сообщение 345234)
if (!cache.hasOwnProperty(stamp)) {/*... */}

а так не лучше будет?

лучше, потому что немного быстрее, но это из области незначительной оптимизации, а вот хранение информации в ключах объекта - это из области гениального :)

nerv_ 07.12.2014 13:49

Цитата:

Сообщение от bes
а вот хранение информации в ключах объекта - это из области гениального

стандартный прием)

Общепринятое название функции memorize (у меня на скрине опечатка, скопипастил название у lowdash), от memorization
https://lodash.com/docs#memoize

Читайте Стоян Стефанов - JavaScript. Шаблоны, там все есть

Ну, и, разумеется, такая функция принимает только примитивы + json like objects. Если очень хочется пихать объекты с циклическими ссылками, то массивы.

danik.js 07.12.2014 13:59

Цитата:

Сообщение от nerv_
Общепринятое название функции memorize

:no: http://en.wikipedia.org/wiki/Memoization

nerv_ 07.12.2014 14:12

danik.js, значит в книжке опечатка)

https://yadi.sk/i/IlMM8krQdCoLf

https://ru.wikipedia.org/wiki/%D0%9C...%D 0%B8%D1%8F

или в википедии опечатка, т.к. запоминание согласно переводчику гугла это memorization от слова memory (насколько я понимаю)
https://translate.google.ru/#en/ru/memorization

krutoy 07.12.2014 15:48

Цитата:

Сообщение от nerv_
Если очень хочется пихать объекты с циклическими ссылками, то массивы.

С какими чиклическими ссылками? Я выше показал, что с объектами ф-ция вообще работает некорректно, с любыми объектами. А учитывая то, что в js все есть объект, ф-ция не работает в общем случае. Не понимаю, откуда в треде столько поросячего восторга. Ставлю палец вниз:)

nerv_ 07.12.2014 16:15

krutoy, я рад, что ты открыл для себя функцию Object.create(). Жаль, что только ее :)

Цитата:

Сообщение от krutoy
Я выше показал, что с объектами ф-ция вообще работает некорректно

а я показал, куда тебе идти :D Шутка) Не показывал еще, но если будешь настаивать, то покажу)))

иди почитай что такое JSON

krutoy 07.12.2014 16:24

nerv_,
Я ничего не понял. Что не так в моем коде? JSON.stringify берет только верхнюю (ближний хеш) часть объекта, которая объектом, безусловно не является. И ты так и не ответил, причем тут циклические ссылки.

А Object.create тут не при чем, он взят в качестве примера. с юбым прототипом и их цепочкой, будет то же самое.

bes 07.12.2014 16:34

Цитата:

Сообщение от nerv_
стандартный прием)

ну мы-то люди простые, институтов не кончали :D
идём от очевидного, где-то надо хранить - в переменной, массиве, объекте, до ключа объекта не догадались :no:

krutoy 07.12.2014 16:38

Цитата:

Сообщение от bes
до ключа объекта не догадались

Ключ объекта в этом смысле является эквивалентом переменной. Все переменные в JS фактически также являются св-ми объекта, на считая некоторых деталей. Поэтому, мне тоже не понятно, чему ты удивляешься. Есть всего лишь строка, которая сслыается на объект.

bes 07.12.2014 16:41

Цитата:

Сообщение от krutoy
Ключ объекта в этом смысле является эквивалентом переменной. Все переменные в JS фактически также являются св-ми объекта, на считая некоторых деталей. Поэтому, мне тоже не понятно, чему ты удивляешься. Есть всего лишь строка, которая сслыается на объект.

ладно, будем считать, что тогда уже поздно было, мозг плохо работал :yes:

krutoy 07.12.2014 16:42

bes,
Это идет, видимо, от общего, превратного понимания JS, в массе. JS является чистейшим ООП языком, в стиле смолтока или селфа, то есть, ООП в хорошем смысле этого слова. В подобных семантиках, надо рассматривать ключ объекта, как предикат, определяющий, может ли объект принять данное сообщение, "знает" ли он данное определение.

krutoy 07.12.2014 16:45

bes,
Но, в целом, ф-ция -- говно, см мои комменты выше. Ее написал не "гений", как ты выразился, а, мягко говоря, чел далекий от понимания JS.

bes 07.12.2014 16:54

Цитата:

Сообщение от krutoy
bes,
Но, в целом, ф-ция -- говно, см мои комменты выше. Ее написал не "гений", как ты выразился, а, мягко говоря, чел далекий от понимания JS.

Цитата:

Сообщение от krutoy
JSON.stringify

так лучше?
Array.prototype.slice.call(arguments).toString()

krutoy 07.12.2014 17:04

Цитата:

Сообщение от bes
так лучше?

не думаю
f=function(arg){
    return [].slice.call(arguments).toString()
}

o1=Object.create({a: 1})
o2=Object.create({a: 2})

alert(f(o1))
alert(f(o2))
//  [object Object]
//  [object Object]

что мы будем сравнивать?
А если так
f=function(arg){
    return [].slice.call(arguments[0]).toString()
}

o1=Object.create({a: 1})
o2=Object.create({a: 2})

alert(f(o1))
alert(f(o2))

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

bes 07.12.2014 17:06

krutoy, возьми мой пример и покажи, что не так

krutoy 07.12.2014 17:19

Цитата:

Сообщение от bes
возьми мой пример и покажи, что не так

вот в этой строке
cache[stamp] = fn.apply(this, arguments);

в ключ записывается не объект, а лишь текстовое представление его "верхушки", первого хеша. В дальнейшем, когда ты делаешь проверку, у тебя следующий "отпечаток", при сравнении строк даст true, хотя объекты, записанные туда, могут быть другими.
o1={a: 1}
o2={a: 1}

textRepresent1=JSON.stringify(o1)
textRepresent2=JSON.stringify(o2)
console.log(
o1===o2,
textRepresent1===textRepresent2
)
//  false true

У тебя из кеша будет извлечено не то, что ты ожидаешь.

melky 07.12.2014 17:27

Цитата:

Сообщение от nerv_ (Сообщение 345144)

хакер :)

Цитата:

Сообщение от krutoy (Сообщение 345324)
bes,
Это идет, видимо, от общего, превратного понимания JS, в массе. JS является чистейшим ООП языком, в стиле смолтока или селфа, то есть, ООП в хорошем смысле этого слова. В подобных семантиках, надо рассматривать ключ объекта, как предикат, определяющий, может ли объект принять данное сообщение, "знает" ли он данное определение.

JS - мультипарадигменный язык.

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

ты взял этот способ из книги Фленегана?. (да, мы все его читали)

krutoy 07.12.2014 17:43

Цитата:

Сообщение от melky
мультипарадигменный

Этот базворд я слышал раз тысячу, но до сих пор не понял, что в него вкладывается. В частности, многие кукарекают о якобы, поддержке JS ФП, чего и близко нет в реальности (и не нужно), если следовать современной трактовке, где во главе угла иммутабельность.
Цитата:

Сообщение от melky
примитивам

А, если речь только лишь о примитивах, тогда ок, только тогда надо отдельно указывать, что массивы, регекпы, функции, объекты, объекты строк, объекты чисел и прочая и прочая, то есть, пости все, иными словами, запрешены в качестве аргументов.
Цитата:

Сообщение от melky
способ из книги Фленегана

Я ни о каком способе не писал, я лишь сказал, что ф-ция говно. А Фленагана я толком не читал, не люблю тягомотину.

krutoy 07.12.2014 17:49

Цитата:

Сообщение от melky
бахать "сикретные свойства" примитивам для того , чтобы их "опознать" - это уже не мемоизация, а геморизация.

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

и я не совсем понял, что ты имеешь в виду. Если ты расшитяешь именно примитив, то ты делаешь это так
String.prototype.foo=1

и, в этом случае, у тебя все строки будут иметь св-во foo. Если же ты делаешь
foo=new String("foo")
foo.foo=1
alert(foo.foo)
// 1

Ты расширяешь не примитив, а конкретный строковый объект.

bes 07.12.2014 18:07

Цитата:

Сообщение от krutoy (Сообщение 345330)
вот в этой строке
cache[stamp] = fn.apply(this, arguments);

в ключ записывается не объект, а лишь текстовое представление его "верхушки", первого хеша. В дальнейшем, когда ты делаешь проверку, у тебя следующий "отпечаток", при сравнении строк даст true, хотя объекты, записанные туда, могут быть другими.
o1={a: 1}
o2={a: 1}

textRepresent1=JSON.stringify(o1)
textRepresent2=JSON.stringify(o2)
console.log(
o1===o2,
textRepresent1===textRepresent2
)
//  false true

У тебя из кеша будет извлечено не то, что ты ожидаешь.

всё хорошо, но речь шла о том, что
Цитата:

Сообщение от y0uix
0) Создается некоторая функция, принимающая N аргументов;
1) Создается кэширующая функция, которая принимает вышеуказанную в качестве фунарга и дальше с возвращенным ей значением мы можем работать следующим образом:
- если такая функция-обертка вызывается с новым набором аргументов, то выполняется оригинальная функция;
- в противном случае, если вызов с такими аргументами уже был, то возвращается закэшированный результат, без вызова.

поэтому и пример ниже не рассчитан на решение тех задач, о которых ты говоришь
function f(obj) {
	return obj.a = 2;
};
function cacheFn(fn) {
	var cache = {};
	return function () {
		var stamp = JSON.stringify(arguments); 
		console.log(cache);
		if (!(stamp in cache)) {
			cache[stamp] = fn.apply(this, arguments);
			console.log("call: " + cache[stamp]);
		}
		console.log("cache: " + cache[stamp] + "\n\n");
		return cache[stamp];
	
	}
}
var cacheF = cacheFn(f);
var o1 = {a: 1}; 
var o2 = {a: 1}; 
cacheF(o1);
cacheF(o2);
console.log("o1:");
console.log(o1);
console.log("o2:");
console.log(o2);

krutoy 07.12.2014 18:09

Цитата:

Сообщение от bes
с новым набором аргументов

bes,
Цитата:

Сообщение от krutoy
только тогда надо отдельно указывать, что массивы, регекпы, функции, объекты, объекты строк, объекты чисел и прочая и прочая, то есть, почти все, иными словами, запрешены в качестве аргументов.


bes 07.12.2014 18:14

Цитата:

Сообщение от krutoy
Сообщение от krutoy
только тогда надо отдельно указывать, что массивы, регекпы, функции, объекты, объекты строк, объекты чисел и прочая и прочая, то есть, почти все, иными словами, запрешены в качестве аргументов.

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

krutoy 07.12.2014 18:18

bes,
Нет, ты опять не понял. Задача твоей кэширующей ф-ции в том, чтобы "понять", была ли данная функция (которая в замыкании), уже вызвана с данными аргументами. Именно этого она не делает, точней делает, но только с примитивами. Она не может по этой "псевдосигнатуре" объекта определить, был ли данный объект уже в качестве аргумента, или нет, потому что разные объекты могут давать одинаковый отпечаток.

o1=Object.create({b: 2})
o2=Object.create({b: 3})

o1.a=1
o2.a=1

f=function(o){return o.a+o.b}

function cacheFn(fn) {
    var cache = {};
    return function () {
        var stamp = JSON.stringify(arguments);
        console.log(cache);
        if (!(stamp in cache)) {
            cache[stamp] = fn.apply(this, arguments);
            console.log("call: " + cache[stamp]);
        }
        console.log("cache: " + cache[stamp] + "\n\n");
        return cache[stamp];
     
    }
}

theCache=cacheFn(f)
alert(theCache(o1))
alert(theCache(o2))
//  {}
//  call: 3
//  cache: 3
//  
//  
//  3
//  { '{"0":{"a":1}}': 3 }
//  cache: 3
//  
//  
//  3
//

bes 07.12.2014 20:12

Цитата:

Сообщение от krutoy (Сообщение 345344)
bes,
Нет, ты опять не понял. Задача твоей кэширующей ф-ции в том, чтобы "понять", была ли данная функция (которая в замыкании), уже вызвана с данными аргументами. Именно этого она не делает, точней делает, но только с примитивами. Она не может по этой "псевдосигнатуре" объекта определить, был ли данный объект уже в качестве аргумента, или нет, потому что разные объекты могут давать одинаковый отпечаток.

o1=Object.create({b: 2})
o2=Object.create({b: 3})

o1.a=1
o2.a=1

f=function(o){return o.a+o.b}

function cacheFn(fn) {
    var cache = {};
    return function () {
        var stamp = JSON.stringify(arguments);
        console.log(cache);
        if (!(stamp in cache)) {
            cache[stamp] = fn.apply(this, arguments);
            console.log("call: " + cache[stamp]);
        }
        console.log("cache: " + cache[stamp] + "\n\n");
        return cache[stamp];
     
    }
}

theCache=cacheFn(f)
alert(theCache(o1))
alert(theCache(o2))
//  {}
//  call: 3
//  cache: 3
//  
//  
//  3
//  { '{"0":{"a":1}}': 3 }
//  cache: 3
//  
//  
//  3
//

ок, показательный пример

nerv_ 07.12.2014 21:03

krutoy, не вижу смысла с тобой спорить. Ты уже показал себя на форуме :)

bes, мой полный ответ был здесь. По сути на этом тема должна быть исчерпана.
Даже если в функцию передается объект с параметрами, то:
1. либо он чистый [new Object()]
2. либо, в большинстве случаев его следует интерпретировать как чистый. Например:
foo({bar: 1});
foo({bar: 1}); // какой смысл от того, что это другой объект, если это всего лишь "объект с параметрами"?
т.е. просто глупо тут разницу показывать или нет смысла хранить в массиве ссылки на объекты (если реализация через массивы)

На все негодования кукарекония krutoy, опять-таки, мой ответ был по ссылке выше - смотрите исходники lowdash, там все есть. Для тех, кто кукарекает и не читает ссылки, а в частности krutoy, напишу примерный код того, как эта функция выглядит в lowdash:

var fn = function() {
    console.log(1);
};
var foo = memoize(fn);

foo({a:1}); // 1
foo({a:1}); //

var bar = memoize(fn, function() {
    return Date.now();
});

bar({a:1}); // 1
bar({a:1}); // 1

/**
 * @param {Function} fn
 * @param {Function} [identify]
 */
function memoize(fn, identify) {
    var cache = {};
    var getKey = identify || JSON.stringify;

    return function() {
        var key = getKey(arguments);
        if (!cache.hasOwnProperty(key)) {
            cache[key] = fn.apply(this, arguments);
        }
        return cache[key];
    };
}

krutoy 07.12.2014 21:28

Цитата:

Сообщение от nerv_
объект с параметрами

Ты, для начала, осиль значение слова параметр. А говорить, действительно, не о чем. Набор базвордов и отборного бреда.

melky 07.12.2014 21:54

Цитата:

Сообщение от krutoy
В частности, многие кукарекают о якобы, поддержке JS ФП, чего и близко нет в реальности (и не нужно), если следовать современной трактовке, где во главе угла иммутабельность.

в ФП во главе угла - функция. ну а иммутабельность и остальные плюхи капают с понятия "функция".

в JS с функциями все в порядке, кроме того, что они медленные.

учитывая моду на ФП (баззворд "функциональщина, йо"), в стандарте ES >= 7 я ожидаю появление плюх для комфортного написания кода в этой парадигме.

кстати, если ты так против ФП и иммутабельности - глянь React, Morearty и ClojureScript. это всё не спроста появилось.

... и не спроста оно всё такое "революционное"

лечись от ООП головного мозга :victory:

(написано как троллинг, но сим не является)

Цитата:

Сообщение от krutoy
А, если речь только лишь о примитивах, тогда ок, только тогда надо отдельно указывать, что массивы, регекпы, функции, объекты, объекты строк, объекты чисел и прочая и прочая, то есть, пости все, иными словами, запрешены в качестве аргументов.

ага, именно.
Цитата:

Сообщение от nerv_ (Сообщение 345272)
Ну, и, разумеется, такая функция принимает только примитивы + json like objects. Если очень хочется пихать объекты с циклическими ссылками, то массивы.

Sieg Heil, nerv_

Цитата:

Сообщение от bes
хранение информации в ключах объекта - это из области гениального

обычный хешмап. ты походу пропустил тему марума с задачками по JS - там гениальной жары было навалом :) сейчас эта тема удалена

krutoy 07.12.2014 22:05

Цитата:

Сообщение от melky
это всё не спроста появилось.

Не спроста. Любая функциональщина -- это дрочево под оптимизатор. Когда у тебя есть иммутабельность, ты можешь провернуть такой вот трюк, например
(function f(arg){return foo})(function_with_long_calculation())

Если ты знаешь, что функция function_with_long_calculation чистая, ты можешь редуцировать эту строку до foo в компилтайме.
И при таком раскладе, бредореализация кэширования нерва действительно могла бы работать. В JS это все ни к чему, это экстремально динамичный язык, тут делается упор на выразительность и мозги программиста. А то что ты приводишь, правильно, это мода, когда многие недоумки слышали звон, да не знают где он, но зато знают, что это модно, поэтому пишут ахинею.

В принципе, в JS наверняка код, написанный в ФП-стиле оптимизируется лучше, но это не значит, что надо на это дрочить постоянно.

krutoy 07.12.2014 22:46

Цитата:

Сообщение от nerv_
Ну, и, разумеется, такая функция принимает только примитивы + json like objects. Если очень хочется пихать объекты с циклическими ссылками, то массивы.

Во первых, покажи мне в стандарте, где есть понятие "json-like-objects", товарищ Петросян.
Про примитивы -- это еще вопрос, поскольку в JS любой примитив может быть вызван в объектном контексте.
Насчет массивов -- не п*ди, массивы -- это 100% объекты.

И наконец, 3-й раз спрашиваю, при чем тут циклические ссылки?

bes 07.12.2014 22:49

Цитата:

Сообщение от nerv_
bes, мой полный ответ был здесь. По сути на этом тема должна быть исчерпана.

Цитата:

Сообщение от nerv_
Ну, и, разумеется, такая функция принимает только примитивы + json like objects. Если очень хочется пихать объекты с циклическими ссылками, то массивы.

возможно не заметил/не обратил внимания

Цитата:

Сообщение от nerv_
Для тех, кто кукарекает и не читает ссылки

Цитата:

Сообщение от melky
обычный хешмап. ты походу пропустил тему марума с задачками по JS - там гениальной жары было навалом сейчас эта тема удалена

сколько у вас часов в сутках? :)

Цитата:

Сообщение от nerv_
Если очень хочется пихать объекты с циклическими ссылками, то массивы.

пойдёт?

function f(obj) {
	return obj.a + obj.b;
}

function isSame(args1, args2) {
	var len1 = args1.length;
	var len2 = args2.length;
	if ( len1 != len2 ) return false;
	for (var i = 0; i < len1; i++) {
		if ( args1[i] === args2[i] ) continue;
		return false;
	}
	return true;
}

function cacheFn(fn) {
	var cache = [];
	return function () {
		var len = cache.length;
		for (var i = 0; i < len; i++) {
			if ( isSame(cache[i].args, arguments) ) {
				console.log("cache: " + cache[i].res + "\n\n");
				return cache[i].res;
			}
		}
		cache.push( {args: arguments, res: fn.apply(this, arguments)} );
		console.log("call: " + cache[len].res + "\n\n")
		return cache[len].res;
	}
}

var cacheF = cacheFn(f);
var o1 = Object.create({b: 2})
var o2 = Object.create({b: 3})
o1.a = 1
o2.a = 1
cacheF(o1);
cacheF(o1);
cacheF(o2);
cacheF(o2);

krutoy 07.12.2014 22:53

Цитата:

Сообщение от bes
возможно не заметил/не обратил внимания

bes,
А ты и дальше не обращай, поскольку это тоже полуп*больство, см мой пост выше.
http://javascript.ru/forum/misc/5217...tml#post345384

krutoy 07.12.2014 22:58

Цитата:

Сообщение от bes
пойдёт?

Нет
function f(obj) {
    return obj.a + obj.b;
}
 
function isSame(args1, args2) {
    var len1 = args1.length;
    var len2 = args2.length;
    if ( len1 != len2 ) return false;
    for (var i = 0; i < len1; i++) {
        if ( args1[i] === args2[i] ) continue;
        return false;
    }
    return true;
}
 
function cacheFn(fn) {
    var cache = [];
    return function () {
        var len = cache.length;
        for (var i = 0; i < len; i++) {
            if ( isSame(cache[i].args, arguments) ) {
                console.log("cache: " + cache[i].res + "\n\n");
                return cache[i].res;
            }
        }
        cache.push( {args: arguments, res: fn.apply(this, arguments)} );
        console.log("call: " + cache[len].res + "\n\n")
        return cache[len].res;
    }
}
 
var cacheF = cacheFn(f);
var o1 = Object.create({b: 2})
var o2 = Object.create({b: 3})
o1.a = 1
o2.a = 1
cacheF(o1);
cacheF(o1);
cacheF(o2);
cacheF(o2);

o2.a = 10
cacheF(o2);
//  call: 3
//  
//  
//  cache: 3
//  
//  
//  call: 4
//  
//  
//  cache: 4
//  
//  
//  cache: 4

И не мучайся. В JS в общем случае, кэширование невозможно.

bes 08.12.2014 00:23

Цитата:

Сообщение от krutoy
И не мучайся. В JS в общем случае, кэширование невозможно.

хорошо, но давай двинемся на шаг дальше

function f(obj) {
	return obj.a + obj.b;
}

function isSame(args1, args2) {
	var len1 = args1.length;
	var len2 = args2.length;
	if ( len1 != len2 ) return false;
	for (var i = 0; i < len1; i++) {
		if ( args1[i] === args2[i] ) continue;
		return false;
	}
	return true;
}

function cacheFn(fn) {
	var cache = [];
	return function () {
		var len = cache.length;
		for (var i = 0; i < len; i++) {
			if ( isSame(cache[i].args, arguments) && JSON.stringify(arguments) == cache[i].strArg) {
				console.log("cache: " + cache[i].res + "\n\n");
				return cache[i].res;
			}
		}
		cache.push( {args: arguments, strArg: JSON.stringify(arguments), res: fn.apply(this, arguments)} );
		console.log("call: " + cache[len].res + "\n\n")
		return cache[len].res;
	}
}

var cacheF = cacheFn(f);
var o1 = Object.create({b: 2})
var o2 = Object.create({b: 3})
o1.a = 1
o2.a = 1
//cacheF(o1);
//cacheF(o1);
cacheF(o2);
cacheF(o2);

console.log("----");
o2.a = 10
cacheF(o2);
cacheF(o2);

console.log("****");
o2.b = 10;
cacheF(o2);
cacheF(o2);


есть ещё примеры? :)

krutoy 08.12.2014 00:42

Цитата:

Сообщение от bes
хорошо, но давай двинемся на шаг дальше

Слушай, честно, мне лень разбирать примеры "вечного двигателя":). Понять бессмысленность данной затеи легко. Смотри. В JS объект получается по ссылке. Легко понять, что закэшировать его можно только одним способом -- сохранив ссылку на него в кэше. Естественно, если объект меняется, то из кэша ты получаешь неактуальные значения. Этого понимания достаточно, чтобы прекратить эти нелепые попытки:)
Но это не значит, что мы не можем кэшировать какие то частные случаи. Например, можно часть объектов сделать неизмняемыми. чтоб они работали как простые хэши, можно работать с примитивами, не вызывая их в объектном контексте, и т.п. Это сделать легко.


Часовой пояс GMT +3, время: 10:25.