Is there anything wrong with this pattern for a JS library? - coding-style

I admittedly know little about the inner workings of javascript, but need to make a library and would like to learn (hence asking here). I understand using the closure and exporting to window to not pollute the global namespace, but beyond that it confuses me a bit.
(function() {
var Drop = window.Drop = function() {
var files = [];
var add = function(word) {
files.push(word);
return files;
}
return {
files: files,
add: add
}
}
})()
// All of these seem to be the same?
var a = Drop();
var b = new Drop();
var c = new Drop;
// Each has their own state which is what I want.
a.add("file1");
b.add("file2");
c.add("file3");
Why are all three ways of "initializing" Drop the same?
What exactly gives them the ability to have their own state?
Is there an alternative to the return syntax to export those functions on Drop?
Is there just a flat out better best practice way of creating a self contained library like this?
I have searched around the net, but have found very little consistency on this subject.

The first way (Drop()) just calls the function as normal, so this is the global object (window in browser environments). It does its stuff and then returns an object, as you'd expect.
The second way (new Drop()) creates a new Drop object and executes the constructor with this set to that object. You do not, however, use this anywhere and return an object created from an object literal, so the Drop object is discarded and the object literal returned instead.
The third way (new Drop) is semantically the same as the second; it is only a syntactic difference.
They all have their own state because each time you call Drop, it has its own set of local variables distinct from the local variables of any other call to Drop.
You could transform your code to use the normal new syntax and prototypes. This has a few advantages: namely, you only create the add function once rather than one for each Drop call. Your modified code might look like this:
function Drop() {
this.files = [];
}
Drop.prototype.add = function(word) {
this.files.push(word);
return this.files;
};
By doing this, though, you lose being able to call it without new. There is, however, a workaround: You can add this as the first line inside function Drop:
if(!(this instanceof Drop)) {
return new Drop();
}
Since when you call it with new, this will be a Drop, and when you call it without new, this will be something other than a Drop, you can see if this is a Drop, and if it is, continue initializing; otherwise, reinvoke it with new.
There is also another semantic difference. Consider the following code:
var drop = new Drop();
var adder = drop.add;
adder(someFile);
Your code will work here. The prototype-based code will not, since this will be the global object, not drop. This, too, has a workaround: somewhere in your constructor, you can do this:
this.add = this.add.bind(this);
Of course, if your library's consumers are not going to pull the function out of the object, you won't need to do this. Furthermore, you might need to shim Function.prototype.bind for browsers that don't have it.
No. It's all a matter of taste.

Why are all three ways of "initializing" Drop the same?
// All of these seem to be the same?
var a = Drop();
var b = new Drop();
var c = new Drop;
When you use new in JavaScript to invoke a function, the value of this inside the function becomes the new object.
But the reason they're the same in your case is that you're not using this at all. You're making a separate object using object literal syntax, and returning it instead, so the new has no impact.
What exactly gives them the ability to have their own state?
Because each function invocation makes a new object, each object is entirely different for each invocation.
The functions assigned to the object are recreated in each Drop invocation, and therefore create a closure over the enclosing variable scope. As such, the files array of each invocation is continuously accessible to the functions made in each respective invocation.
Is there an alternative to the return syntax to export those functions on Drop?
Yes. Assign the functions and array to this, and remove the return statement. But that will require the use of new. Alternatively, put the functions on the .prototype object of Drop, and they'll be shared among all instances made using new, but keep the array assigned to this in the constructor so that it's not shared.
For the prototyped functions to reference the array, they would use this.files.
Is there just a flat out better best practice way of creating a self contained library like this?
JavaScript is very flexible. There are many ways to approach a single problem, each with its own advantages/disadvantages. Generally it'll boil down to taking advantage of closures, of prototypal inheritance, or some combination of both.
Here's a full prototypal inheritance version. Also, the outer (function() {})() isn't being used, so I'm going to add a variable to take advantage of it.
(function() {
var totalObjects = 0; // visible only to functions created in this scope
var Drop = window.Drop = function() {
this.files = [];
this.serialNumber = totalObjects++;
}
Drop.prototype.add = function(word) {
this.files.push(word);
return this.files;
};
})();

Related

AJAX and Leaflet: Inspect feature properties before styling/adding to map

I'm using leaflet-ajax to load geoJSON on demand. I want to find the maximum theProperty value so I can use that to scale the feature's fill colors before I add them to the map.
Here's my general approach:
function maxBinPropertyValue(theProperty) {
var theGeoJson = null;
var maxPropertyValue = 0;
var propertyValue = null;
var theGeoJson = new L.GeoJSON.AJAX(binsFileName());
theGeoJson.on('data:loaded', function() {
console.log('The data is loaded');
theGeoJson.eachLayer(function(layer) {
console.log('Looping through the layers');
propertyValue = feature.properties[theProperty];
if (propertyValue > maxPropertyValue) {
maxPropertyValue = propertyValue;
console.log('Max so far: ' + maxPropertyValue);
};
});
});
theGeoJson = null;
console.log('The final maximum value: ' + maxPropertyValue);
return maxPropertyValue;
};
I'm trying to wait for the data:loaded event, then loop through all the features to find the maximum value of theProperty, which is returned to the calling routine.
Except it doesn't work. The first console.log says 'The data is loaded'. The second and third console.logs are never reached, and the fourth and final one reports a value of 0 for maxPropertyValue.
How can I examine all the features in a featureset before styling them, in a way guaranteed to not have asynchronous problems?
PS: I'm pretty sure I can't use onEachFeature: instead of the above approach, because I need to examine every feature's property to determine the maximum value in the set before I can style any of the features.
As for your issue about inspecting your data and retrieving the maximum value, you are indeed facing the classic asynchronous concept of JavaScript.
See How do I return the response from an asynchronous call?
Asynchronism is a problem if not dealt with properly, but an advantage if correctly handled.
To put the concept shortly, you do not manage asynchronism in a "standard" sequential way, but you should rather consider parts of code (callbacks) that are executed at a later time based on events.
Whenever you provide a function as an argument, it is certainly a callback that will be executed at a later time, but very probably much later than the next instructions.
So in your case, your 2nd and 3rd console.log are within a callback, and will be executed once your data is loaded, which will happen much later than your 4th console.log.
As for your next step (styling and adding to map), you actually do not need to perform an extra AJAX call, since you already have all data available in theGeoJson variable. You simply need to refactor / restyle it properly.
It is a good approach to break your problem in small steps indeed.
Good luck!
PS: that being said, ES7 provides async and await functionalities that will emulate a sequential execution for asynchronous functions. But to be able to use those, you need latest browser versions or transpilation, which is probably more work to learn and configure as of today for a beginner than understanding how to work with async JS.
I also had this problem and had to wrap my head around this, so giving an explicit example for solution here;
// make a request with your "url"
var geojsonLayer = new L.GeoJSON.AJAX("url");
// define your functions to interact with data
function thingToDoBeforeLoadingStarts () {
// do stuff
}
function thingToDoForEachFileDownloaded () {
// do stuff
}
function thingToDoAfterAllDownloadEnds () {
// do stuff
}
// attach listeners
geojsonlayer.on("data:loading",thingToDoBeforeLoadingStarts);
geojsonLayer.on("data:progress",thingToDoForEachFileDownloaded)
geojsonLayer.on("data:loaded",thingToDoAfterAllDownloadEnds);

AS2, Referencing a Changing Object Name

so I was wondering if there was a way to reference different objects on stage with he same method to save repeating lots of lines of code. This is what I have right now
function bossKilled(i:Number):Void {
trace("Boss Killed!");
kills ++;
_root.bossDeath.gotoAndPlay(2);
_root["pirate"+i+"Active"] = false; //name of variable would be pirate1Active
_root["pirate"+(i+1)+"Active"] = true; //name of variable would be pirate2Active
bossDeath._x = _root["pirate"+i+"Active"]._x;
bossDeath._y = _root["pirate"+i+"Active"]._y; }
However, this reference does not actually affect the variables. I was wondering if this was possible, and if so, what am I doing wrong?
Thanks.
Not sure what you try to achieve ... pirate1Active is a BOOL. A BOOL has no _x or _y property (nor any other).
If you are not sure where to find your objects in the object tree, you can use the debugger or add some traces on the MCs timeline, like trace (_parent);
Consider switching to AS3, it is much more object oriented and has better tools support.

trigger.io file.saveURL and looping

I am using the file.saveURL in a loop and its working good but I am seeing some strage things. Basically I loop over about 70 images and then grab the uri to them after they are saved and store that locally so I can then use it to display in the app
What happens is that once the loop is done I display the images out but randomly some of the images are the same. I have validated the correct URL is being passed but its as if and I don't know for sure but maybe the function is not done with the previous and is somehow overwriting it?
This makes the most sence because the issue usually happens with images right next to each other.
So I guess my question is, does the file.saveURL only work on a one to one aspect, like it has to by synchronous?
If that is the case what would be the recommended approach for looping over and saving these images.
Thanks!
EDIT
This is a basic sample (I have some conditional stuff in there but this is the main part)
I have the JSON object stored and I loop over it
$(data).each(function(i){
var slcval = 'speaker' + this.SID;
var imageID = 'simageid' + this.IMAGE;
var speakerImage = "http://mydomain.com/users/images/speakers/" + this.IMAGE;
//then I call the save url function
saveURLImage(speakerImage,slcval,'speaker',this.SID,imageID);
}
this loops over my images and calls the save image function that then does the save URL function
function saveURLImage(url,ID,type,extraVal,imageID){
forge.file.saveURL(url, function (file) {
forge.file.URL(file, function (url) {
var fileObject = JSON.stringify(url);
localStorage.setItem(ID, fileObject);
})
});
}
This is a simple version of it, I have some other parts that set some localstorage vars but this is the main call.
So my problem was a scoping issue
so if anyone else comes arrocss this I found this thred that helped out
Javascript: function in setTimeout and references
Basically what I did was creat a function that has an announmous function in it so the scope would be correct
function saveURLImage(url,ID,type,extraVal,imageID) {
(function() {
saveURLImageScoped(url,ID,type,extraVal,imageID)
})();
}
so the function name is still the same as before but I renamed the main function saveURLImageScoped and now it has its own variable scope

Can you safely extend the Ti or Ti.UI object with your own functions?

I'm working on a mid-size Appcelerator Titanium app. I want to extend the Ti.UI object, and I am wondering if this is safe.
What I want to do
Store a number of UI-related helper functions and objects as part of the Ti.UI tree.
A trivial example would be:
Ti.UI.COLORS = {
RED: '#213234',
BLUE: '#ABDCEF'
}
My big concern is that this may be unsafe or just not future-proof.
Why I want to do it
I've had bad experiences with Titanium's JSS and I am currently storing and retrieving my files in a CSS.js file. This file bundles a few functions and objects that make styling easier (like the colors example above), and combines them with a big long list of style classes, stored as objects. The classes make use of the helper functions.
Like so:
//Provide helper functions
COLORS = { RED: 'etc' };
IOS_ANDROID = function(iosValue,androidValue){
if (Device.isIOS) {
return iosValue
} else {
return androidValue
};
//Provide the styles as exports object (using commonJS)
exports.styles = {
winHome: {
backgroundColor: COLORS.RED
},
winProducts: {
navBarHidden: IOS_ANDROID(true,false),
}
}
Now that my app has grown, the size of this styles object is getting annoying. I am trying to split the styles into several .js files and combine them (and the necessary functions) using includes and requires. So I now have a 'css-Home.js', 'css-Products.js', etc.
This works, sort of, but I currently need to re-include/require the helper functions in every css-.js file. This feels awkward. I am trying to be strict in the CommonJS practice of only using require() and not doing include(). However, if I use require() to add the helper functions, like so...
var cssHelpers = require('css-helpers.js')
...then I would need to prefix all the helpers with that variable, like so...
exports.styles = {
winHome: {
backgroundColor: cssHelpers.COLORS.RED,
},
}
That's why I would like to put these basic things into Ti.UI during the app's initialization. Then I'll have the style helper functions available wherever.
Try using the applyproperties method which would be the recommended approach if you must extend the default objects
I found a decent solution that doesn't involve altering Ti.UI. The cue came from trying to run the app on Android and finding that it passes even fewer variables between different parts. So I needed to dig deeper into the CommonJS principles and the meaning of require() and Ti.include().
The trick to not having to prefix my CSS helpers with their parent's name is as follows:
Require a CSS-helpers.js file in the file where you need the helper functions.
Have CSS-helper.js's exports object return just one function.
Execute the function immediately after requiring. Like so:
//Include CSS helper functions as local variables
require('shared/css-helpers')();
In the one exports function of CCS-helpers, use the 'this' variable to apply functions directly to the js context where globals is included:
exports = function(){
this['IOS_ANDROID'] = function(ios,android){ etc };
this['otherHelperFunction'] = function(){};
}
Now, in the file where CSS-helpers was included, you can use the helper functions like IOS_ANDROID() without any prefix. That's because the 'this' variable in CSS-helpers points to the context that called the function.

Scope for Actionscript 2.0 Event

I'm using Actionscript 2.0 for a mobile phone and can't get my head around Events.
I'm creating a class object with all my code and using a group of functions (all as direct 1st level children of the class). There's one function that creates a Movieclip with a square on it and sets the onPress event to another function called hit:
public function draw1Sqr(sName:String,pTL:Object,sSide:Number,rgb:Number){
// create a movie clip for the Sqr
var Sqr:MovieClip=this.canvas_mc.createEmptyMovieClip(sName,this.canvas_mc.getNextHighestDepth());
// draw square
Sqr.beginFill(rgb);
//etc ...more lines
//setup properties (these are accessible in the event)
Sqr.sSide=sSide;
Sqr.sName=sName;
//setup event
Sqr.onPress = hit; // this syntax seems to lead to 'this' within
// the handler function to be Sqr (movieclip)
//Sqr.onPress = Delegate.create(this, hit);
//I've read a lot about Delegate but it seems to make things harder for me.
}
Then in my event handler, I just cannot get the scope right...
public function hit(){
for (var x in this){
trace(x + " == " + this[x]);
}
//output results
//onPress == [type Function]
//sName == bSqr_7_4
//sSide == 20
trace(eval(this["._parent"])); //undefined
trace(eval(this["._x"])); //undefined
}
For some reason, although the scope is set to the calling object (Sqr, a Movieclip) and I can access properties I defined, I can't use the 'native' properties of a Movieclip object.
Any suggestions on how I can access the _x, _y and other properties of the Movieclip object that is pressed.
Use the array accessor or the dot accessor, but not both. For example:
trace(this._parent); // OR
trace(this["_parent"]);
As for the results of your iteration, I recall AS2 being screwy on this front. IIRC only dynamic properties are returned when looping with for ... in. This prevents Objects (which often serve as hash maps) from including their native properties when all you want are the key/value pairs you set yourself.
Also - the eval() function can be easily overused. Unless you absolutely must execute a String of AS2 that you don't have at compile-time I would recommend avoiding it. Happy coding!

Resources