I have this closure :
function CFetchNextData(ofs, pag, fetchFunction) {
var offset = ofs;
var limit = pag;
return function(options, cb) {
//do stuff to create params
fetchFunction(params, cb);
offset += limit;
};
}
I then create a variable this way:
var fetchInfo = CFetchNextData(0, 10, specificFetchFunction);
fetchInfo(options, myCB);
So that everytime I call fetchInfo, pagination is automatically set to the next set of data. That works great, althought
I'd like to have multiple instance of : "fetchInfo", each one having its own scope.
var A = fetchInfo; // I'd like a clone with its own scope, not a copy
var B = fetchInfo; // I'd like a clone with its own scope, not a copy
I could do:
var A = new CFetchNextData(ofs, pag, fetchFunction);
var B = new CFetchNextData(ofs, pag, fetchFunction);
But obviously I would have to setup "ofs" and "pag" each time, whereas by cloning fetchInfo, I'd have a stable pagination, set only once and for good.
Do you know how to achieve that ?
Thanks in advance
There isn't a concept of cloning a function in JavaScript. You need to call CFetchNextData (or another function) multiple times if you want to create multiple closures.
You could have CFetchNextData return a factory function instead of returning the actual function. But I'm not sure that's really an improvement.
function CFetchNextDataFactory(ofs, pag, fetchFunction) {
return function() {
var offset = ofs;
var limit = pag;
return function(options, cb) {
//do stuff to create params
fetchFunction(params, cb);
offset += limit;
};
};
}
var fetchInfoFactory = CFetchNextData(0, 10, specificFetchFunction);
var A = fetchInfoFactory();
var B = fetchInfoFactory();
This may not answer all of your question but just to pitch in , you could try assigning your parameters to a default / fallback value which will allow you to avoid setting ofs and pag each declaration . Below is a prototype of what I came up with . Its using oop :
class CFetchNextData {
constructor(ofs, pag){
this.OFS = 1; //default value
this.PAG = 10; //default value
this.ofs = ofs;
this.pag = pag;
if(ofs == null || ofs == undefined){
this.ofs = this.OFS;
}
if(pag = null || pag == undefined){
this.pag = this.PAG;
}
}
fetchInfo(){
var data = this.ofs += this.pag;
return data;
}
}
var task1 = new CFetchNextData(); // Falls back to default values..
var task2 = new CFetchNextData(32,31); // Uses values from specified in args...
document.write(task1.fetchInfo() + "\n")
document.write(task2.fetchInfo())
Hope this helps...
Related
I'm building a small world builder in JavaScript (part of a larger simulation).
I'm trying to define an object's property in the constructor function by assigning a functions output to it.
In the code below, 'this.identifier' executes like a charm, but I want to assign more complex functions to for instance 'this.gender'.
In 'this.gender' I want to use math.random.math.floor to cycle through an array (that has two values, male and female).
When I write the actual function, 'this.gender' is dropped from the new Human object.
{
"identifier":42,
"lifestate":"Alive",
"health":"100",
"age":"10",
"metabolism":"12",
"econsumption":"11111",
"parent":"yes"
}
gender is dropped the moment I change it to a function.
I've tried using a return statement, but it makes no difference.
class Bluehuman {
constructor() {
this.identifier = Math.floor((Math.random() * 100));
this.lifestate = 'Alive';
this.health = '100';
this.age = '10';
this.metabolism = ['Low','Medium','High'];
this.econsumption = '11111';
this.parent = ['Yes','No'];
this.gender = ['Male','Female']; // Want to change this to a function without dropping from the new Bleuhuman object
}
}
var bluehuman = {};
var bluehumans = [];
for (var i = 0; i < 10; i++) {
bluehuman[i] = new Bluehuman();
bluehumans.push(bluehuman[i]);
}
var arrayPrint = JSON.stringify(bluehumans);
console.log(arrayPrint)
How can I assign the output of a function to 'this.gender' without having it dropped from the new bluehuman object?
You don't need a function, an expression is just fine to solve your problem
class Bluehuman {
constructor() {
this.identifier = Math.floor((Math.random() * 100));
this.lifestate = 'Alive';
this.health = '100';
this.age = '10';
this.metabolism = ['Low','Medium','High'];
this.econsumption = '11111';
this.parent = ['Yes','No'];
this.gender = ['Male','Female'][Math.round(Math.random())];
}
}
var bluehuman = {};
var bluehumans = [];
for (var i = 0; i < 10; i++) {
bluehuman[i] = new Bluehuman();
bluehumans.push(bluehuman[i]);
}
var arrayPrint = JSON.stringify(bluehumans);
console.log(arrayPrint)
You can just assign a function as any other value
this.test = function() { };
you will then be able to call it as:
new Bluehuman().test();
and if you log it to the console directly, you'll also see it:
console.log(new Bluehuman());
If you however call JSON.stringify on it, it will be turned into a string containing only data, functions (and a lot of other things) get removed.
I am struggling to understand how variables are referenced and stay alive in Javascript. In the following I have two types of object, a Note and an IntervalBuilder which takes a Note and creates
a second Note.
function Note() {
this.key = 1 + Math.floor( Math.random() * 13); // from 1 to 13 inclusive
this.setKey = function setKey(i) { key = i; };
this.getKey = function getKey() { return this.key; } ; // {return key} is a ReferenceError!!
}
function IntervalBuilder() {
this.setPerfectFifth = function setPerfectFifth(root) {
this.fifth = new Note();
console.log("this.fifth: " + this.fifth);
this.y = root.key;
console.log("root.key: " + root.key );
console.log("y: " + this.y );
this.fifth.setKey( this.y + 4 );
return this.fifth;
};
}
With the above I can now do this:
var x = new Note();
var ib = new IntervalBuilder();
ib.setPerfectFifth(x);
However, the instance ib now has a member named fifth! What I was hoping for was that I could assign the return value (a Note) from setPerfectFifth to a variable and let fifth vanish. How is that done?
Many thanks for any help, I find lots of this very confusing.
Gerard
Since you titled your quesion variable visibility in javascript what is basically going on is: In this.fifth = new Note(); the keyword this references the instance (the ib of var ib = new ...). So you attach your newly created Note to the instance. In JavaScript, as long as a variable can be reached starting with the global Object (window, when you think of a graph), it won't get garbage-collected away.
What you want is: var fith = new Note(), which will create a local variable which will get freed as soon as the function execution ends. Clearly, every usage of this.fifth then has to be replaced by just fith.
I do not know exactly what you want to achieve, but I think you want the following code structure:
// ==============================
// NOTE "CLASS"
// ==============================
var Note = (function () {
// Constructor
function Note() {
this._key = 1 + Math.floor( Math.random() * 13);
}
// Getter
Note.prototype.getKey = function () {
return this._key;
};
// Setter
Note.prototype.setKey = function (i) {
this._key = i;
};
return Note;
})();
// ==============================
// INTERVAL BUILDER "CLASS"
// ==============================
var IntervalBuilder = (function () {
// Constructor
function IntervalBuilder() {}
// Private members
var fifth = null,
y = 0;
// Setter
IntervalBuilder.prototype.setPerfectFifth = function (root) {
fifth = new Note();
y = root.getKey();
fifth.setKey(y + 4);
return fifth;
};
return IntervalBuilder;
})();
// ==============================
// CLIENT CODE
// ==============================
var x = new Note(),
ib = new IntervalBuilder();
ib.setPerfectFifth(x);
I thought there would already be an answer for this but I can't seem to find one..
How can I run a particular class method on all instances of this class in Javascript?
This has to be done in a situation where I do not know the names of the instances.
I think I could use some sort of static variable inside my class to store all instances, but this doesn't seem to exist in JS
So how to call my method on all existing instances of my class?
Note : just for clarification : I'm not speaking about CSS classes, I'm speaking about objects.
Edit : By Class in Javascript, I mean the creation of a new object on a function:
function something()
{
}
var instance = new something();
You can create a static array and store it on your constructor function:
MyClass.allInstances = [];
MyClass.allInstances.push(this);
However, you need some way to figure out when to remove instances from this array, or you'll leak memory.
In Chrome 62+ you can use queryObjects from the console API - which will not work in native JavaScript code but in the console so it's great for debugging.
class TestClass {};
const x = new TestClass();
const y = new TestClass();
const z = new TestClass();
queryObjects(TestClass)
You'll have to provide a custom implementation.
I would do something like this :
function Class() {
Class.instances.push(this);
};
Class.prototype.destroy = function () {
var i = 0;
while (Class.instances[i] !== this) { i++; }
Class.instances.splice(i, 1);
};
Class.instances = [];
var c = new Class();
Class.instances.length; // 1
c.destroy();
Class.instances.length; // 0
Or like this :
function Class() {};
Class.instances = [];
Class.create = function () {
var inst = new this();
this.instances.push(inst);
return inst;
};
Class.destroy = function (inst) {
var i = 0;
while (Class.instances[i] !== inst) { i++; }
Class.instances.splice(i, 1);
};
var c = Class.create();
Class.instances.length; // 1
Class.destroy(c);
Class.instances.length; // 0
Then you could loop through all instances like so :
Class.each = function (fn) {
var i = 0,
l = this.instances.length;
for (; i < l; i++) {
if (fn(this.instances[i], i) === false) { break; }
}
};
Class.each(function (instance, i) {
// do something with this instance
// return false to break the loop
});
Sorry for such a late reply, but I found myself trying to achieve this and I think this may be a simpler answer.
Say you want all instances of class MyClass, only get instances created at top window level (not including instances created inside a closure):
for (var member in window)
{
if (window[member] instanceof MyClass)
console.info(member + " is instance of MyClass");
}
Keyword 'static' could be used in classes now (but check support), ...
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/static
class Point{
constructor(x, y){
this.x = x;
this.y = y;
Point.all.push(this);
}
destroy(){
let i = Point.all.indexOf(this);
Point.all.splice(i, 1);
}
static all = [];
}
var p1 = new Point(1, 2);
var p2 = new Point(54, 33);
var p3 = new Point(297, 994);
console.log(JSON.stringify(Point.all)); //[{"x":1,"y":2},{"x":54,"y":33},{"x":297,"y":994}]
p2.destroy();
console.log(JSON.stringify(Point.all)); //[{"x":1,"y":2},{"x":297,"y":994}]
You'll need to store a list of instances yourself:
function someClass(param) {
// add to all
if (this.constructor.all === undefined) {
this.constructor.all = [this];
} else {
this.constructor.all.push(this);
}
// set param
this.logParam = function() { console.log(param); };
}
var instance1 = new someClass(1);
var instance2 = new someClass(2);
for (var i = 0; i < someClass.all.length; i++) {
someClass.all[i].logParam();
}
If memory leaks are a concern then you can create a method for deleting instances when you are done with them:
function someClass(param) {
...
this.destroy = function() {
var all = this.constructor.all;
if (all.indexOf(this) !== -1) {
all.splice(all.indexOf(this), 1);
}
delete this;
}
}
I'm trying to execute a rotating banner (Calling it through an array). I set an interval but the image only shows after 10 seconds (10000) and only then begins the rotation. I removed the cluttered HTML of the array, but here's the rest of it:
var current = 0;
var banners = new Array();
banners[0]=;
banners[1]=;
banners[2]=;
banners[3]=;
var myTimeout = setInterval("rotater()",10000);
function rotater() {
document.getElementById("placeholderlayer").innerHTML=banners[current];
if(current==banners.length-1){
current = 1;
}else{
current += 1;
}
}
window.onload = rotater();
window.onload = rotater;
is the correct syntax. You don't want to call the function. However, the bulletproof solution is rather this:
onload = function() {
rotater();
window.myTimeout = setInterval(rotater, 10000); // Never pass a string to `setInterval`.
};
ProTip™: Don't use new Array(), use an array literal. For example, this:
var arr = new Array();
arr[0] = 'Hello';
arr[1] = 'world!';
Should be written as:
var arr = ['Hello', 'world!'];
Just a comment:
Instead of:
if(current==banners.length-1) {
current = 1;
} else {
current += 1;
}
you can do:
current = ++current % banners.length;
is there a way to automatically create subobjects in an assignment after construction, i.e.
var obj = {};
obj.a.b.c=13;
the above gives me a "obj.a is undefined" error
i wrote a function to do this, but wondered if there was an easier way
_setObjectProperty(obj,13,['a','b','c']);
function _setObjectProperty(obj,value,loc)
{
if(loc.length>1) {
obj[loc[0]] = obj[loc[0]] || {};
_setObjectProperty(obj[loc[0]],value,loc.splice(1));
}
else if(loc.length===1) {
obj[loc[0]]=value;
}
}
No, there's no built in way to do this in JavaScript. The only way is to create your own function like you did. If you want the convenience of the dot operator/notation you can use the following function:
var set = function(path, value, root) {
var segments = path.split('.'),
cursor = root || window,
segment,
i;
for (i = 0; i < segments.length - 1; ++i) {
segment = segments[i];
cursor = cursor[segment] = cursor[segment] || {};
}
return cursor[segments[i]] = value;
};
set("a.b.c", 2);
console.log(a.b.c) // => 2