Must memoized functions be defined as variables? - javascript

I've just asked this question (multiple errors while momoizing function inside another function) and I've got a nice answer... but! Just to understand a little more about JavaScript, I'd like to know if the momoized function can be written in this style:
function main () {
function memoized_f(){
//memoizing code
}
}
EDIT: Please notice I'm not asking what is the difference in the code above, I'm asking if it is possible to memoize the second one!
So, how to rewrite this?
function main() {
var create_node = (function() {
var memo;
console.log("memo: " + memo);
console.log("create_node")
function f() {
var value;
if (memo) {
value = memo.cloneNode();
console.log("clone node");
console.log(value);
} else {
var value = document.createElement("div");
value.innerHTML = "hello";
console.log("new node");
console.log("value: " + value);
memo = value;
}
return value;
}
return f;
})();
var collection = [];
for (var i = 0; i < 10; i++) {
collection.push(create_node());
};
// Display results
for (var i = 0; i < 10; i++) {
console.log(i + ". " + collection[i]);
}
}
main();

Since functions in javascript are an object, you can just use that function to memoize the value. I think it would make more sense in fib example, but here is your original post.
function main() {
// memoizing function
function create_node() {
var value;
// read from memo on function object
if (create_node.memo) {
value = create_node.memo.cloneNode();
value.innerHTML = 'cloned';
console.log("clone node");
console.log(value);
} else {
var value = document.createElement("div");
value.innerHTML = "hello";
console.log("new node");
console.log("value: " + value);
// retain memo on the function object
create_node.memo = value;
}
return value;
}
var collection = [];
for (var i = 0; i < 10; i++) {
collection.push(create_node());
};
// Display results
for (var i = 0; i < 10; i++) {
console.log(i + ". " + collection[i]);
document.getElementById('container').appendChild(collection[i]);
}
}
main();
<div id="container"></div>

Your actual memoized function is f. The (function(){ ... })() IIFE wrapping merely provides a an additional closure-layer to hide the variable memo so that it is visible only to f.
To repeat that: the (function(){...})() expression is not your memoized function. It is wrapping that restricts visibility of an inner variable and ultimately returns your memoized function f, which is defined inside of it. If you were okay with exposing memo to other code in main and not restrict its visibility to the memoized function only, you could eliminate the IIFE wrapping entirely and simply rename f to create_node:
function main() {
var memo;
function create_node() {
var value;
if (memo) { value = memo.cloneNode(); }
else {
var value = document.createElement("div");
value.innerHTML = "hello";
memo = value;
}
return value;
}
// use `create_node` as originally done
// NOTE that other code can manipulate `memo` now, though!
}
main();
If you like, you can supply the closure wrapping via a function declaration instead of IIFE:
function createMemoizedFunc() {
var memo;
function f() {
var value;
if (memo) { value = memo.cloneNode(); }
else {
var value = document.createElement("div");
value.innerHTML = "hello";
memo = value;
}
return value;
}
return f;
}
var create_node = createMemoizedFunc();

Related

Add custom function to objects

I want add new function after i have created objects . I try write some code but it not right.
//
Sorry my description don't clear. I want after i create an object i can add function for this object to do something. Hope someone can understand my english :(
http://fiddle.jshell.net/7LnLerdt/
function Add(a,b){
var _self = this;
var a = a;
var b = b;
}
Add.prototype.doAdd = function(){
var rs = this.a+this.b;
if(rs < 10){
this.lessThanTen();
}else{
this.moreThanTen();
}
};
Add.prototype.moreThanTen = function(callback) {
if(callback){
callback.call(this);
}
};
Add.prototype.lessThanTen = function(callback) {
if(callback){
callback.call(this);
}
};
var add = new Add();
add.moreThanTen(function(){
console.log("moreThanTen");
});
add.lessThanTen(function(){
console.log("lessThanTen")
});
add.doAdd();
The code where you are "assigning" callbacks is not how it works. It just executes the method, it does not magically just assign the callback. The callbacks would need to be passed into the doAdd method or you need to assign the callbacks in a different manner.
If you want to add properties to object use this code instead:
function Add(a,b){
this.a = a;
this.b = b;
}
If you want to add callbacks use this:
Add.prototype.addCallbacks(less, more) {
this.less = less;
this.more = more;
};
Add.prototype.moreThanTen = function(callback) {
if(this.more){
this.more.call(this);
}
};
Add.prototype.lessThanTen = function(callback) {
if(this.less){
this.less.call(this);
}
};
and then
var add = new Add();
add.addCallbacks(function(){
console.log("lessThanTen")
}, function(){
console.log("moreThanTen");
});
You have a couple of problems. First, using var will declare a local variable, so it will not be accessible outside that function. If you want to create a member variable, use this. instead (as jcubic pointed out).
function Add(a, b) {
this.a = a;
this.b = b;
}
Second, you are not adding the callbacks correctly. Your code is executing the callback immediately, but (I think) what you really want to do is save the callback and execute it later.
function Add(a, b) {
this.a = a;
this.b = b;
this.moreThanTenCallbacks = [];
this.lessThanTenCallbacks = [];
}
Add.prototype.moreThanTen = function(callback) {
moreThanTenCallbacks.push(callback);
};
Add.prototype.lessThanTen = function(callback) {
lessThanTenCallbacks.push(callback);
};
Add.prototype.executeCallback = function(callbacks) {
for (var i = 0; i < callbacks.length; ++i) {
if (callback) {
callback();
}
}
};
Add.prototype.doAdd = function() {
var rs = this.a + this.b;
if (rs < 10) {
this.executeCallback(this.lessThanTenCallbacks);
} else {
// NOTE: this will execute moreThanTen callbacks even if the result equals 10!
// Are you sure that is what you want?
this.executeCallback(this.moreThanTenCallbacks);
}
};

Writing a function to set some but not necessarily all parameters in another function

I had a coding interview test that asked the following question which I was not able to fully solve. I'm wondering the best way to do this following my approach -- also sorry this is long.
You are given a function to read in like this (not necessarily 2 parameters):
function add(a, b) {
return a + b;
}
The objective is to create a function to initialize some of those variables and again call the function to perform the calculation like, function setParam(func, params). To use this you would do the following:
_add = setParam(add, {b:9})
_add(10) // should return 19
My solution was to parse the function to see how many parameters there are, then set them using the given parameters but since I barely know javascript I was never able to actually return a function with only some variables set and others still undefined.
(attempt at solution)
function setParam(func, params) {
// varray is an array of the the varriables from the function, func
// ie varray = [a,b] in this test
var varray = /function[^\(]*\(([^\)]*)\)/.exec(func.toString())[1].split(',');
//creates an array, paramset, that has the variables in func defined
//where possible
// ex paramset = [a,9] if only b was set
var paramsset = []
for (i = 0; i < varray.length; i++) {
if (typeof(params[varray[i]]) == "undefined"){
paramsset[i] = varray[i];
} else {
paramsset[i] = params[varray[i]];
}
}
//////
// need to modify existing function and return with added parameters
// where I'm stuck as this doesn't work.
newfunc = (function(){
var _func = func;
return function() {
return _func.apply(this, paramsset);
}
})();
newfunc()
}
I'm sure I'm not doing this the correct way, but any help would be appreciated.
I'm certainly not advocating to go towards that solution, but I still implemented something to follow your initial's API design for fun. The signatures weak map is necessary in order to preserve the initial function's signature so that we can call setParams again on partially applied functions.
var setParams = (function () {
var signatures = new WeakMap();
return function (fn, paramsToApply) {
var signature = signatureOf(fn), newFn;
validateParams(paramsToApply, signature.params);
newFn = function () {
var params = appliedParamsFrom(arguments, paramsToApply, signature.indexes);
return fn.apply(this, params);
};
signatures.set(newFn, signature);
return newFn;
};
function signatureOf(fn) {
return signatures.has(fn)?
signatures.get(fn) :
parseSignatureOf(fn);
}
function parseSignatureOf(fn) {
return String(fn)
.match(/function.*?\((.*?)\)/)[1]
.replace(/\s+/g, '')
.split(',')
.reduce(function (r, param, index) {
r.indexes[param] = index;
r.params.push(param);
return r;
}, { indexes: {}, params: [] });
}
function validateParams(paramsToApply, actualParams) {
Object.keys(paramsToApply).forEach(function (param) {
if (actualParams.indexOf(param) == -1) throw new Error("parameter '" + param + "' could not be found in the function's signature which is: 'function (" + actualParams + ")'");
});
}
function appliedParamsFrom(args, paramsToApply, paramsIndex) {
var appliedParams = [],
usedIndexes = [],
argsIndex = 0,
argsLen = args.length,
argSpotIndex = 0;
Object.keys(paramsToApply).forEach(function (param) {
var index = paramsIndex[param];
appliedParams[index] = paramsToApply[param];
usedIndexes.push(index);
});
while (argsIndex < argsLen) {
if (usedIndexes.indexOf(argSpotIndex) == -1) {
appliedParams[argSpotIndex] = args[argsIndex++];
}
++argSpotIndex;
}
return appliedParams;
}
})();
function add(a, b) { return a + b; }
var addTo9 = setParams(add, { b: 9 });
var add10To9 = setParams(addTo9, { a: 10 });
document.write(addTo9(10) + ', ' + add10To9());
Now, note that JavaScript comes with the Function.prototype.bind function which allows to perform in-order partial function application. The first parameter to bind has nothing to do with arguments, it's to bind the this value.
function add(a, b) { return a + b; }
var addTo9 = add.bind(null, 9);
document.write(addTo9(10));
And finally, an implementation with a placholder if you need one:
var partial = (function (undefined) {
var PLACEHOLDER = {};
function partial(fn, partialArgs) {
return function () {
return fn.apply(this, applyPartialArgs(arguments, partialArgs));
};
}
Object.defineProperty(partial, 'PLACEHOLDER', {
get: function () { return PLACEHOLDER; }
});
return partial;
function applyPartialArgs(args, partialArgs) {
var appliedArgs = partialArgs.map(function (arg) {
return arg === PLACEHOLDER? undefined : arg;
}),
partialArgsLen = partialArgs.length,
argsLen = args.length,
argsIndex = 0,
argSpotIndex = 0;
while (argsIndex < argsLen) {
if (
partialArgs[argSpotIndex] === PLACEHOLDER ||
argSpotIndex >= partialArgsLen
) {
appliedArgs[argSpotIndex] = args[argsIndex++];
}
++argSpotIndex;
}
return appliedArgs;
}
})();
function add(a, b, c, d) {
return a + b + c + d;
}
var _ = partial.PLACEHOLDER;
var addTo9 = partial(add, [_, 5, _, 4]);
document.write(addTo9(5, 5));
I'm guessing that they might have been testing for knowledge of partial application. (not currying)
Edit: Edited based upon your comments. This is Crockford's curry function straight from his book.
function add(a, b) {
return a + b;
}
if (!Function.prototype.partial) {
Function.prototype.partial = function() {
var slice = Array.prototype.slice,
args = new Array(arguments.length),
that = this;
for (var i = 0; i < args.length; i++) {
args[i] = arguments[i];
}
return function() {
return that.apply(null, args.concat(slice.apply(arguments)));
}
};
}
var example = add.partial(4);
console.log(example(10)); // output 14
console.log(example(20)); // output 24
var example = adder(4) assigns example to be function with a closure with a (in this case 4). When example is called like in the console.log, it will in effect be returning "the value of a when example was assigned, plus this new number."
Walkthrough of the partial() function:
Converts arguments to an array
returns a function gets passed the arguments given, which can be called later. It has a closure with the previously assigned arguments.

What is wrong with my observable pattern?

I'm testing the observable pattern in javascript. My callbacks in the array never seem to execute. What is wrong with my syntax?
<script type="text/javascript">
var Book = function (value) {
var onChanging = [];
this.name = function () {
for (var i = 0; i < onChanging.length; i++) {
onChanging[i]();
}
return value;
}
this.addTest = function (fn) {
onChanging.push(fn);
}
}
var b = new Book(13);
b.addTest(function () { console.log("executing"); return true; });
b.name = 15;
</script>
From your code above it looks like you need to call your function name instead of assigning a value something like:
var b = new Book(13);
b.addTest(function () { console.log("executing"); return true; });
b.name(); //<-- Before b.name = 15
Setting b.name = 15 doesn't execute the function, it just overwrites the value of b.name.
You could use getters and setters to react to a changing value. See John Resig's blog post or the MDN reference
I edited your code to use them:
var Book = function (value) {
this.onChanging = [];
this._name = "";
}
Book.prototype = {
addTest: function (fn) {
this.onChanging.push(fn);
},
get name() {
return this._name;
},
set name(val) {
for (var i = 0; i < this.onChanging.length; i++) {
this.onChanging[i](val);
}
this._name = val;
}
};
var b = new Book(13);
b.addTest(function (val) {
console.log("executing", val);
return true;
});
b.name = 15;
b.name = 17;
working demo.
You can also make a more generic solution that can work for all your properties without having to define the getters and setters, a lot of frameworks use this approach.
Book = function () {
this._events = [];
this._rawdata = {};
}
Book.prototype = {
bind: function (fn) {
this._events.push(fn);
},
// pass the property, and it returns its value, pass the value and it sets it!
attr: function (property, val) {
if (typeof val === "undefined") return this._rawdata[property];
this._rawdata[property] = val;
for (var i = 0; i < this._events.length; i++)
// we pass out the val and the property
this._events[i](val, property);
}
};
b = new Book();
b.bind(function (val) {
console.log("executing", val);
return true;
});
b.attr("name","The Hobbit");
b.attr("SKU" ,1700109393901);
console.log(b.attr("name")); // --> The Hobbit
http://jsfiddle.net/wv4ch6as/
Of course you would want to change the binder so that you can bind onto properties not one bind for all properties, but I think this gets the idea.

Create an object with modified versions of all methods in a source object [duplicate]

This question already has answers here:
JavaScript closure inside loops – simple practical example
(44 answers)
Closed 8 years ago.
I want to create an object that has modified versions of all of the methods in a source object, but I'm having trouble using for...in.
If this is my source object:
var raw = {};
raw.add = function(a,b){return a + b;}
raw.sub = function(a,b){return a - b;}
raw.neg = function(a){return -a;}
raw.sqrt = function(a){return Math.sqrt(a);}
It works if I recreate the list of properties in an array of strings:
var mod2 = Object.create(raw);
var proplist = ["add", "sub", "neg", "sqrt"];
proplist.forEach(function(prop){
mod2[prop] = function(){
var arglist = [].slice.apply(arguments);
var out = [];
if(arglist.length == 1){
[].concat(arglist[0]).forEach(function(d){ out.push(raw[prop](d)); });
}
else if(arglist.length == 2){
[].concat(arglist[0]).forEach(function(d1){
[].concat(arglist[1]).forEach(function(d2){
out.push(raw[prop](d1,d2));
})
});
}
return out;
}
});
But my attempt to use for..in doesn't work, all of the methods in the new object will do "sqrt":
var modified = Object.create(raw);
for(prop in raw){
modified[prop] = function(){
var arglist = [].slice.apply(arguments);
var out = [];
if(arglist.length == 1){
[].concat(arglist[0]).forEach(function(d){ out.push(raw[prop](d)); });
}
else if(arglist.length == 2){
[].concat(arglist[0]).forEach(function(d1){
[].concat(arglist[1]).forEach(function(d2){
out.push(raw[prop](d1,d2));
})
});
}
return out;
}
}
What is the best way to iterate through the methods automatically?
The issue with your second implementation is that you are using prop in your new method (which will be called sometime later), but the for loop that creates prop has already run to completion by the time that method is called sometime later so prop is not the right value any more (it will always be the last property). I fixed that in my implementation by capturing prop in an IIFE (immediately invoked function expression) so it would be frozen separately for each pass through the for loop. Your first implementation doesn't have that problem because you're using .forEach() on the array of properties which uses a callback function which captures the value of prop for you automatically into a closure.
So here's the result with these changes to your implementation:
Add an IIFE to freeze the value of prop for use in the new methods.
Add an extra check to make sure the methods we're copying are not inherited and are functions.
Initialized raw to a plain object as I don't see any reason to use Object.create() here.
The code:
var raw = {};
raw.add = function(a,b){return a + b;}
raw.sub = function(a,b){return a - b;}
raw.neg = function(a){return -a;}
raw.sqrt = function(a){return Math.sqrt(a);}
var modified = {};
for (prop in raw) {
if (raw.hasOwnProperty(prop) && typeof raw[prop] === "function") {
(function (prop) {
modified[prop] = function () {
var arglist = [].slice.apply(arguments);
var out = [];
if (arglist.length == 1) {
[].concat(arglist[0]).forEach(function (d) {
out.push(raw[prop](d));
});
} else if (arglist.length == 2) {
[].concat(arglist[0]).forEach(function (d1) {
[].concat(arglist[1]).forEach(function (d2) {
out.push(raw[prop](d1, d2));
})
});
}
return out;
}
})(prop);
}
}
Working demo: http://jsfiddle.net/jfriend00/5LcLh/
<script>
var raw = {};
raw.add = function () { console.log('add default method'); }
raw.sub = function () { console.log('sub default method'); }
raw.neg = function () { console.log('neg default method'); }
raw.sqrt = function () { console.log('sqrt default method'); }
console.log('*****************');
console.log('before modifying');
console.log('*****************');
raw.add();
raw.sub();
raw.neg();
raw.sqrt();
var proplist = ["add", "sub", "neg", "sqrt"];
console.log('*****************');
console.log('after modifying');
console.log('*****************');
console.log('');
var modified = Object.create(raw);
for (prop in proplist) {
if (prop == 0)
console.log('rewriting methods and calling methods inside loop................');
modified[proplist[prop]] = function () { console.log(proplist[prop] + ' method modified, ' + proplist.length + ' argument passed') }
modified[proplist[prop]]();
}
console.log('');
console.log('trying call methods after loop is done................');
modified.add();
modified.sub();
modified.neg();
modified.sqrt();
console.log('...it is becaouse "prop" variable in loop holding last count number ' + prop);
</script>
thanks to arnold.NET.JS's response clarifying the problem, I see that closure is one way to do it:
var raw = {};
raw.add = function(a,b){return a + b;}
raw.sub = function(a,b){return a - b;}
raw.neg = function(a){return -a;}
raw.sqrt = function(a){return Math.sqrt(a);}
var mod = Object.create(raw);
for(prop in raw){
mod[prop] = (function(){
var propname = prop;
function f(){
var arglist = [].slice.apply(arguments);
var out = [];
if(arglist.length == 1){
[].concat(arglist[0]).forEach(function(d){ out.push(raw[propname](d)); });
}
else if(arglist.length == 2){
[].concat(arglist[0]).forEach(function(d1){
[].concat(arglist[1]).forEach(function(d2){
out.push(raw[propname](d1,d2));
})
});
}
return out;
}
return f;
})();
}

Why are my properties assigning incorrectly?

I created an ObservablePropertyList which is supposed to execute a callback when a property changes. The implementation is:
function ObservablePropertyList(nameCallbackCollection) {
var propertyList = {};
for (var index in nameCallbackCollection) {
var private_value = {};
propertyList["get_" + index] = function () { return private_value; }
propertyList["set_" + index] = function (value) {
// Set the value
private_value = value;
// Invoke the callback
nameCallbackCollection[index](value);
}
}
return propertyList;
}
And here's a quick test demonstration:
var boundProperties = BoundPropertyList({
TheTime: function (value) {
$('#thetime').text(value);
},
TheDate: function (value) {
$('#thedate').text(value);
}
});
var number = 0;
setInterval(function () {
boundProperties.set_TheTime(new Date());
boundProperties.set_TheDate(number++);
}, 500);
For some reason though, the properties are not being assigned correctly or something. That is, calling set_TheTime for some reason executes the callback for set_TheDate, almost as though it were binding everything to only the last item in the list. I can't for the life of me figure out what I'm doing wrong.
When using loops like that you need to wrap it in an enclosure
function ObservablePropertyList(nameCallbackCollection) {
var propertyList = {};
for (var index in nameCallbackCollection) {
(function(target){
var private_value = {};
propertyList["get_" + index] = function () { return private_value; }
propertyList["set_" + index] = function (value) {
// Set the value
private_value = value;
// Invoke the callback
target(value);
}
})(nameCallbackCollection[index]);
}
return propertyList;
}
You need to create a closure in order for each iteration of the for loop to have its own private_variable object. Otherwise, each iteration just overwrites the previous (since private_variable is hoisted to the top of its scope). I'd set it up like this:
var ObservablePropertyList = (function () {
"use strict";
var handleAccess = function (propList, key, callback) {
var privValue = {};
propList["get_" + key] = function () {
return privValue;
};
propList["set_" + key] = function (value) {
// Set the value
privValue = value;
// Invoke the callback
callback(value);
};
};
return function (coll) {
var propertyList = {}, index;
for (index in coll) {
handleAccess(propertyList, index, coll[index]);
}
return propertyList;
};
}());
var boundProperties = ObservablePropertyList({
TheTime: function (value) {
$('#thetime').text(value);
},
TheDate: function (value) {
$('#thedate').text(value);
}
}), number = 0;
setInterval(function () {
boundProperties.set_TheTime(new Date());
boundProperties.set_TheDate(number++);
}, 500);
DEMO: http://jsfiddle.net/PXHDT/

Categories

Resources