var modularpattern = (function () {
var sum = 0;
return {
add: function () {
sum = sum + 1;
return sum;
},
}
} ());
var c = modularpattern;
c.add(); // 1
var d = modularpattern;
d.add(); // 2 but I want to be 1
console.log(modularpattern.add()); // alerts: 3
Is it possible to have more objects not only one? I want to have private fields but at the same time also having more that just one object?
Yes, that's easily possible by dropping the IIFE invocation to get a normal function instead. Only it's called factory pattern then, no longer module.
function factory() {
var sum = 0;
return {
add: function () {
sum = sum + 1;
return sum;
}
}
}
var c = factory();
c.add(); // 1
var d = factory();
d.add(); // 1
console.log(c.add()); // logs: 2
You can use the module pattern to create a factory which uses the module pattern to create more objects. Using your original example, it would look something like this:
var moduleFactory = (function() {
return {
create: function() {
return (function() {
var sum = 0;
return {
add: function() {
sum = sum + 1;
return sum;
}
}
})();
}
}
}
)();
var c = moduleFactory.create();
console.log(c.add()); //1
var d = moduleFactory.create();
console.log(d.add()); //1
Related
I am trying to cache 'func.apply(this, func)' value so that it can be looked up later rather than running the function again. The problem is that I don't know how or what to use as the key.
Is there a way to assign an key of a function that can be looked up later?
Code example:
var m = function(func) {
var cached = {};
return function() {
var key = ''; // how do I get or create the key of func.apply(this, func)?
if (cached[key]) {
return cached[key];
}
cached[key] = func.apply(this, arguments);
return cached[key];
};
};
The m() function should return a function that, when called, will check if it has already computed the result for the given argument and return that value instead if possible.
What are you looking for is called Memoization
See: Implementing Memoization in JavaScript
Here are an example:
var myFunction = (function() {
'use strict';
var functionMemoized = function() {
// set the argumensts list as a json key
var cacheKey = JSON.stringify(Array.prototype.slice.call(arguments));
var result;
// checks whether the property was cached previously
// also: if (!(cacheKey in functionMemoized.cache))
if (!functionMemoized.cache.hasOwnProperty(cacheKey)) {
// your expensive computation goes here
// to reference the paramaters passed, use arguments[n]
// eg.: result = arguments[0] * arguments[1];
functionMemoized.cache[cacheKey] = result;
}
return functionMemoized.cache[cacheKey];
};
functionMemoized.cache = {};
return functionMemoized;
}());
Why do you need an object with an index. Just store the result/key.
var m = function(func) {
var result=null;
return function() {
if (result===null) {
result = func.apply(this, arguments);
}
return result;
}
};
But I am not sure that is what you want. If the function returns different values based on arguments, than you want to use a key based off the arguments.
var m = function(func) {
var results = {};
return function() {
var key = [].slice.call(arguments).join("-");
if (results[key]===undefined) {
results[key] = func.apply(this, arguments);
}
return results[key];
}
};
var multiply = function (a,b) {
return a * b;
}
var mult = m(multiply);
console.log(mult(2,5)); //runs calculation
console.log(mult(2,5)); //uses cache
If you send the value of the function as a string, you can use that as the index with one minor modification
var m = function(func, scope) {
return function() {
var cached = {};
var index = func; // how do I get or create the index of func.apply(this, func)?
scope = scope || this;
if (!cached[index]) {
func = scope[func]; //Get the reference to the function through the name
cached[index] = func.apply(this, func);
}
return cached[index];
};
};
This does depend on if the index exists in the this object reference. Otherwise you should use a different scope.
I am trying to understand why the variable index is being updated ( added and subtracted ) when my function returns an object.
var init = (function() {
var index = 0;
return function() {
return {
subtract: index -= 1,
add: index = index + 1,
getIndex: index
}
}
})();
console.log(init().getIndex); // 1
console.log(init().add); // 2
console.log(init().getIndex); //2
Instead 0 is returned. This is because when the object is returned all of the properties in that returned object are execute. SO my question is how do i prevent that from happening.
I highly doubt it returns 0. It should return undefined:
var f = init();
// f is now the returned function. Therefore:
f.getIndex; // should be undefined
f().getIndex; // should be 1
Therefore, the to get the expected output, change your code to:
console.log(init()().getIndex); // 1
console.log(init()().add); // 2
console.log(init()().getIndex); //2
var init = (function() {
var index = 0;
return function() {
return {
subtract: function() { return --index; },
add: function() { return ++index; },
getIndex: function() { return index; }
}
}
})();
console.log(init().getIndex()); // 0
console.log(init().add()); // 1
console.log(init().getIndex()); // 1
subtract, add and getIndex aren't being initiated as functions. They are receiving the values -1, 0 and 0.
To return operations set
var init = (function() {
var index = 0;
return {
subtract: function () { index -= 1 },
add: function () { index + 1 }, // Should probably be += here
getIndex: function () { return index; }
}
}();
Function count() return 1, 2, 3... How to create constructor function Count?
var count = new Count();
count(); // 1
count(); // 2
function Count() {
var c = 1;
return function() {
return c++;
}
};
var count = new Count(); // count is now a function that adds and returns
count(); // 1
count(); // 2
function Count() {
this.x = 0;
this.count = function() {
return (this.x += 1);
};
}
counter = new Count();
counter.count(); //1
counter.count(); //2
Declare a variable globally:
var counter=0;
Create a function to return the value:
function count() {
return ++counter;
}
A constructor needs to return an object for the most part,
so returning a number in the constructor will just return the instance of that function,
not the number. You can explicitly return an object, however, so the closest you can get is:
;(function() {
var count = 0;
window.Count = function() {
return new Number(count += 1);
}
})()
var a = +new Count // 1
var b = +new Count // 2
Of course, you could just do:
window.count = (function(){
var i = 0;
return function() {
return i += 1;
}
})()
var a = count() // 1
var b = count() // 2
Which makes more sense in most cases.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Javascript closure inside loops - simple practical example
You have an array of arbitrary values. Write a transform function in the global scope that will transform the array to an array of functions that return the original values, so instead of calling a[3], we will call a3.
For example I want:
var a = ["a", 24, { foo: "bar" }];
var b = transform(a);
a[1]; // 24
b[1](); // 24
However I am getting:
b
[function () {
return this.temp;
}, function () {
return this.temp;
}, function () {
return this.temp;
}]
Here is my code:
var a = ["a", 24, { foo: "bar" }];
var b = transform(a);
document.writeln(a[1]); // 24
document.writeln(b[0]()); // 24
document.writeln(b[1]()); // 24
function transform(array) {
b = [];
var i;
for (i = 0; i < array.length; i += 1) {
b[i] = function () {
return temp;
};
}
return b;
}
function transform(array) {
b = [];
var i;
for (i = 0; i < array.length; i += 1) {
b[i] = (function (x) {
return function () { return x; };
})(array[i]);
}
return b;
}
demo http://jsbin.com/udasoj/1/edit
Your code is correct if you call b[0](), then you should get the value returned.
Note that none of the existing answers will quite work; they will all produce functions that return that last value in a. var is function-scoped and interacts poorly with closures.
See this other answer I just wrote, which explains a similar problem: https://stackoverflow.com/a/14330595/17875
What is temp? It looks like the way to accomplish this is to generate the function via another function:
function transform(array) {
b = [];
var i;
for (i = 0; i < array.length; i += 1) {
b[i] = createReturnFunction(a[i]);
};
}
return b;
}
function createReturnFunction(value){
return function(){ return value; };
}
Working Fiddle: http://jsfiddle.net/eFWyf/
Let's say I have a JavaScript object:
function a(){
var A = [];
this.length = function(){
return A.length;
};
this.add = function(x){
A.push(x);
};
this.remove = function(){
return A.pop();
};
};
I can use it like so:
var x = new a();
x.add(3);
x.add(4);
alert(x.length()); // 2
alert(x.remove()); // 4
alert(x.length()); // 1
I was trying to make .length not a function, so I could access it like this: x.length, but I've had no luck in getting this to work.
I tried this, but it outputs 0, because that's the length of A at the time:
function a(){
var A = [];
this.length = A.length;
//rest of the function...
};
I also tried this, and it also outputs 0:
function a(){
var A = [];
this.length = function(){
return A.length;
}();
//rest of the function...
};
How do I get x.length to output the correct length of the array inside in the object?
You could use the valueOf hack:
this.length = {
'valueOf': function (){
return A.length;
},
'toString': function (){
return A.length;
}
};
Now you can access the length as x.length. (Although, maybe it's just me, but to me, something about this method feels very roundabout, and it's easy enough to go with a sturdier solution and, for example, update the length property after every modification.)
If you want A to stay 'private', you need to update the public length property on every operation which modifies A's length so that you don't need a method which checks when asked. I would do so via 'private' method.
Code:
var a = function(){
var instance, A, updateLength;
instance = this;
A = [];
this.length = 0;
updateLength = function()
{
instance.length = A.length;
}
this.add = function(x){
A.push(x);
updateLength();
};
this.remove = function(){
var popped = A.pop();
updateLength();
return popped;
};
};
Demo:
http://jsfiddle.net/JAAulde/VT4bb/
Because when you call a.length, you're returning a function. In order to return the output you have to actually invoke the function, i.e.: a.length().
As an aside, if you don't want to have the length property be a function but the actual value, you will need to modify your object to return the property.
function a() {
var A = [];
this.length = 0;
this.add = function(x) {
A.push(x);
this.length = A.length;
};
this.remove = function() {
var removed = A.pop();
this.length = A.length;
return removed;
};
};
While what everyone has said is true about ES3, that length must be a function (otherwise it's value will remain static, unless you hack it to be otherwise), you can have what you want in ES5 (try this in chrome for example):
function a(){
var A = [],
newA = {
get length(){ return A.length;}
};
newA.add = function(x){
A.push(x);
};
newA.remove = function(){
return A.pop();
};
return newA;
}
var x = a();
x.add(3);
x.add(4);
alert(x.length); // 2
alert(x.remove()); // 4
alert(x.length); // 1
You should probably use Object.create instead of the function a, although I've left it as a function to look like your original.
I don't think you can access it as a variable as a variable to my knoledge cannot return the value of a method, unless you will hijack the array object and start hacking in an update of your variable when the push/pop methods are called (ugly!). In order to make your method version work I think you should do the following:
function a(){
this.A = [];
this.length = function(){
return this.A.length;
};
this.add = function(x){
this.A.push(x);
};
this.remove = function(){
return this.A.pop();
};
};
These days you can use defineProperty:
let x = {}
Object.defineProperty(x, 'length', {
get() {
return Object.keys(this).length
},
})
x.length // 0
x.foo = 'bar'
x.length // 1
Or in your specific case:
Object.defineProperty(x, 'length', {
get() {
return A.length
}
})
function a(){
this.A = [];
this.length = function(){
return this.A.length;
};
this.add = function(x){
this.A.push(x);
};
this.remove = function(){
return this.A.pop();
};
};