Should I create accessor methods in my JavaScript app - javascript

I used this form to structure my JS code
window.APP = window.APP || (function (global) {'use strict';
return {
operation: '',
operand: 0,
result: '',
init: function () {
}
};
}(window.document));
There is better way like this:
var APP = APP || (function (global) {
return {
init: function () {
}
};
}(window.document));
But this way JSLint complains that APP was not initialized in the second call of APP, specifically this part: "var APP = APP"
So window.APP works and JSLint finds APP object in the window namespace.
If you check the first code block I have three application wide properties, operation, operand and result. I need those three accessible trough all my other subfunctions and subobjects. So far I used this form to access them:
window.APP.operand = global.getElementById("operand").value;
This works but the problem is, the code overall looks very ugly and cluttered with extra unnecessary text. In my 250 lines of code I have this "window.APP" prefix everywhere.
My questions is, should I create special accessor methods to get/set each of those properties or is there a better way to avoid that window.APP prefix?
Let me know your thoughts.

You should be able to mix the two approaches and use
var APP = window.APP || (function(doc) { "use strict";
…
return {…};
}(document));

This seems promising:
var APP = APP || (function (global) {
var operand = 0,
operation = '',
result = '';
return {
init: function () {
}
};
}(window.document));
Have to try it though. I have some objects defined afterwards like
APP.namespace('Aritmetic', {
// properties/methods
});
namespace function creates subobjects of APP. In the example above Aritmetic will become subobject of APP and will contain all properties methods defined in the second parameter of namespace() function.
I changed the second parameter of namespace function to this:
APP.namespace('Aritmetic', (function () {
var parent = window.APP;
return {
test: function () {
parent.operand = "2"; // all properties/methods from window.APP are accessible trough parent.
}
};
}());
This might not be the most elegant solution to the problem but it works. If somebody knows better solution, let me know.

Related

Creating JS library with dynamic function calling

I'm creating a JS 'library' file, But I want to encapsulate it in it's entirety within an object, to avoid contaminating namespace of the pages that include the file
The twist to this is within a function inside the library I need to call others functions within library by name, eg using window[]
The code below is just a sample there would actually be several hundred functions that could be called by name. It's this that's caused by trouble as I can't get window[] to reference the function, what's the right way to go about this?
I have tried this, in host page:
<script src= "mylib.js"></script>
var oMyLib = new cMyLib(); //there will only ever be one 'instance' of this
In mylib.js everything is contained in one function:
function cMyLib() {
this.doStuff = function () {
someFunc(this); //call another function in the lib
}
// I tried it with prototypes also
// cMyLib.prototype.doStuff = function () {
// someFunc();
// }
function someFunc(that) {
var s='anotherFunc1'
var f = window[s]; //undefined!
f();
s='anotherFunc2'
f=window[s];
f();
}
function anotherFunc1() {}
function anotherFunc2() {}
}
The functions that you want to reference by name (or actually by number, according to your comments) should be part of that object, and not accessed via window, e.g.:
function cMyLib() {
// allow call without new
if (! (this instanceof cMyLib)) {
return new cMyLib();
}
// enforce singleton
if (this.constructor.singleton) {
return this.constructor.singleton;
} else {
Object.defineProperty(this.constructor, 'singleton', {
value: this
});
}
// instruction array (no need to expose via `this`)
var insn = [];
insn[0x4c] = function lda_immediate() { ... }
// instruction execution
this.step = function() {
var opcode = memory[pc++];
if (opcode in insn) {
// `.call` ensures `this` is set inside the instruction fn.
insn[opcode].call(this);
} else {
hcf();
}
}
}
Note the extra stuff at the top - convenience code to ensure that only one cMyLib can exist.
As long as a function is in parent scope you can just reference it directly, i.e.
function someFunc(that) {
anotherFunc1();
};
will simply work.
Another thing is that classical way to do this is to wrap everything in a self-calling anonymous function, i.e.
(function() {
function anotherFunc1() {};
function anotherFunc2() {};
this.cMyLib = function() { ... };
})();
But your approach is fine as well.
If you wish to call your functions by dynamic name, then you can store them in a top level object:
(function() {
var my_functions = {
anotherFunc1: function() {},
anotherFunc2: function() {}
};
this.cMyLib = function() {
var name = 'anotherFunc1';
my_functions[name]();
};
})();
It's like creating an isolated "global" scope.
Side note: Do not use eval. It is very unsafe and slow. It will backfire at you at some point.

Can I avoid using the word "this" inside Typescript when calling a function that came in through a constructor?

I have:
class AdminHomeController {
private config1; // I tried different variations here but none worked
public config2; //
constructor(
private $scope: IAdminHomeControllerScope
) {
this.config = $scope.config; // << this works
}
static $inject = [
'$scope'
];
configChanged = (clear) => {
this.config.clear();
};
}
This code works and this.config has all the methods I need. However is there a way
that I can remove the need for the this? What I would like to be able to do is to code the following:
configChanged = (clear) => {
config.clear();
};
I tried with many different variations but I cannot get it to work.
Here's an example of the same code before changing to Typescript:
angular.module('admin')
.controller('AdminHomeController', [
'$http',
'$q',
'$scope',
'utilityService',
adminHomeController]);
function adminHomeController(
$http,
$q,
$scope,
utilityService
) {
var app = $scope.app;
var config = app.config;
var home = this;
var util = utilityService;
home.autoSave = false;
home.data = {};
home.entityType = null;
home.forms = { grid: null, modal: null };
home.grid = { view: [], data: [] };
home.modal = { visible: false };
home.row = {};
home.rowSelected = null;
home.configChanged = function (clear) {
config.put();
if (clear) {
home.grid.backup = [];
home.grid.data = [];
}
};
As djechilin said:
If you omit "this," the interpreter will simply look for the variable name in local, closured and global scopes, not actually look up object properties
So you can potentially do that in TypeScript by moving the function definition into the body of the constructor (where you have access to the closured $scope variable). Here we also close over config and then use it in the function:
class AdminHomeController {
configChanged: ()=>void; // Need to declare the function
constructor(private $scope: any) {
var config = $scope.config;
this.configChanged = ()=> { // And then assign it
config.clear();
};
}
}
As you can see, it's not elegant. You have function definition + declaration split. Also, the constructor body is becoming needlessly heavy.
TypeScript is not to blame here. It's just JavaScript.
In Javascript definitely not, and in Typescript I'm pretty sure no. References in Javascript bind lexically, not whatever the other way is called. If you omit "this," the interpreter will simply look for the variable name in local, closured and global scopes, not actually look up object properties. You would need some sort of magical flag to say "this variable is an object property," and the way this is implemented is with "this."
This is very usual in Javascript. Compiled languages like Java don't suffer this problem, and I'm not sure about other dynamic languages. It's not necessarily hard to solve; it's just not how JS has done things (arguably wrongly).

Private variable is being shared across multiple instances of a class

I have a small problem using private variables in a JavaScript function. This software depends on draw2d, a rendering library for javascript. The library forces you to use John Resig's implementation of Class.js, which allows for simple Java like class inheritance, and what i believe is the root of the problem.
//= require block/XBlock.js
console.log("sblock loaded.");
xmicro.block.SimpleBlock = xmicro.block.XBlock.extend({
NAME: "xmicro.block.SimpleBlock",
init: function(path, width, height,input,output,contextMenua){
this._super(path,width,height,input,output,contextMenua);
image = path;
this.contextMenu = contextMenua;
xmicro.istn.BlockAttributeStore[this.id] = new xmicro.block.BlockAttributeStore();
},
getImage: function () {
return this.image;
},
onContextMenu: function (x, y) {
supaId = this.id;
that = this;
var buildFunc = function(){
var args = Array.prototype.slice.call(arguments);
args.push(supaId);
return that.contextMenu.build.apply(null, args);
};
if(this.contextMenu !== undefined){
$.contextMenu({
trigger: "right",
selector: this.contextMenu.selector,
build: buildFunc
});
}
},
getPersistentAttributes: function () {
var memento = this._super();
return memento;
}
});
The comment at the top does some auto concatenation, but the focus of the problem is at the onContextMenu function. I have a closure there that needs to be called in order to build a jQuery context menu from a properties object. One thing inside that properties object is a method called build, for which I use buildFunc to intercept the call and append the id of the figure it was called on.
The problem is that if I declare var supaId = this.id, as I make more figures of this type, they start sharing supaId, and start cross-contaminating variables. The other problem is that if I use just supaId = this.id like I below, then it works, but puts supaId on the global scope. Neither of these are good options for me, and I would like to understand how to fix it.
Any help is appreciated!

Function scope in JavaScript. Different objects same result

My question is based on the following scenario.
var test = (function(){
var SlideManager = !function(){
this.Sequencer = {
getSequence : function()...
}
return this;
}()
var LayerManager = !function(){
this.Sequencer = {
getSequence : function()...
}
}()
var module = {};
module.foo = function(){}
return module;
})()
As an explanation, the test object has two helper objects in its scope: SlideManager & LayerManager. These two handle different actions for the entities slide && layer. Each entity has its own fixed position in the DOM, position which should be retrieved through the Sequencer helper object.
Please note that every Manager should have its own Sequencer and I would expect that to be true in the provided example.
However it seems that there is a problem with my understanding of js scopes because both Managers have the same Sequencer (The one from Layer Manager).
Should I expect something like this or am I doing something wrong somewhere else in the code.
Thank you!
To expound upon what Scott Hunter said...
Just auto executing the functions (function() {})() Does not give them a new scope. For that you are wanting the "new" keyword.
So:
var SlideManager = function(){
this.Sequencer = {
getSequence : function()...
}
return this;
};
var LayerManager = function(){
this.Sequencer = {
getSequence : function()...
}
};
var slideManagerInstance = new SlideManage();
var layerManagerInstance = new LayerManager();
Might be more what you are looking for... also why are you "!" banging the auto executed functions return before assigning... that will give you a true/false boolean?
this in both Managers isn't local to that function, and thus is the SAME in both, which is why they have the same Sqeuencer.

What type of pattern does this JS adhere to?

I came across code similar to this recently,
// Simplified example..
var Application =
{
MemberVar1: null,
MemberVar2: null,
Initialize: function ()
{
Application.MemberVar1 = 'Foo';
Application.MemberVar2 = 'Bar';
console.log("Initializing..");
Application.GetMemberVars();
},
GetMemberVars: function ()
{
console.log(Application.MemberVar1 + ' ' + Application.MemberVar2);
}
};
$(Application.Initialize);
What is the name of this pattern/method/style? Utilizing OOP principles without using a style I've seen before, such as prototyping. What are the benefits of this style as opposed to other popular ones?
It's a simple one-off object literal that's being created... they can contain functions... perhaps that's what threw you.
The last line merely passes the Application.Initialize function to jQuery as a $(document).ready callback function
In light of the comments below, this is what the code actually does (and how you can write it a lot shorter/easier)
$(function()
{
console.log("Initializing..");
console.log("Foo Bar");//replace this with variables you declare #top of anon. function if you want
});
As a module (you can find out more about the module pattern here):
var Application = (function()
{
var memberVar1, memberVar2,
getMemberVars = function()
{
return memberVar1 + ' ' + memberVar2;
};
return {init: function()
{
memberVar1 = 'Foo';
memberVar2 = 'Bar';
console.log('initializing...');
console.log(getMemberVars());
}};
}());
$(Application.init);
Application is now an object literal, with only 1 property (init): a function that, because it was declared within the scope of that IIFE, has access to all variables local to that scope. That's the magic of closures for you. You can easily add getters and setters for the member vars, too:
var Application = (function()
{
var memberVars = {},//turned into object literal...
getMemberVars = function(all)
{
var i;
if(typeof all === 'string' || typeof all === 'number')
{
return memberVars[all];
}
all = [];
for (i in memberVars)
{
if (memberVars.hasOwnProperty(i))
{
all.push(memberVars[i]);
}
}
return all;//or all.join(' '), as you please
},
get = function(name)
{
return typeof name === 'undefined' ? name : memberVars[name];
},
set = function(name, val)
{
memberVars[name] = val;
};
return {init: function()
{
memberVars.one = 'Foo';
memberVars.two = 'Bar';
console.log('initializing...');
console.log(getMemberVars().join(' '));
},
get: get,
set: set};//just add getter and setter here
}());
This has the same behavior as your code:
var Application = (function() {
var app = {
MemberVar1: null,
MemberVar2: null,
GetMemberVars: function() { /* ... */},
Initialize: function() {
this.MemberVar1 = 'Foo';
this.MemberVar2 = 'Bar';
console.log('Initializing..');
this.getMemberVars();
}
};
$(function() {app.Initialize();});
return app;
}());
But there's a good chance that you don't really want that Initialize function hanging around. So this would simplify it:
var Application = (function() {
var app = {
MemberVar1: null,
MemberVar2: null,
GetMemberVars: function() { /* ... */}
};
$(function() {
app.MemberVar1 = 'Foo';
app.MemberVar2 = 'Bar';
console.log('Initializing..');
app.getMemberVars();
});
return app;
}());
And unless you're actually worried about code trying to access Application.MemberVar1, etc before jQuery's document.ready event, you can simplify it further to this:
var Application = (function() {
var app = {
GetMemberVars: function() { /* ... */}
};
$(function() {
app.MemberVar1 = 'Foo';
app.MemberVar2 = 'Bar';
console.log('Initializing..');
app.getMemberVars();
});
return app;
}());
I'm assuming that defining those MemberVars took some real work, and were not simple strings as in the example. If that's not the case, then I would switch this last to
var Application = (function() {
var app = {
MemberVar1: 'Foo';
MemberVar2: 'Bar';
GetMemberVars: function() { /* ... */}
};
$(function() {
console.log('Initializing..');
app.getMemberVars();
});
return app;
}());
You don't need to use prototype if you are going to use only one instance of some object.
In this case it's pretty clear the Application object is something unique and the author didn't intend there were going to be any additional copies of Application created.
Talking about style... that capital camel case looks ugly. The common agreement is to use CapitalCamelCase only for object constructors. I personally think it's ok to use for unique objects with logic too (Application). But using it for function names and variables should be avoided.
Talking about patterns... it's close to Singleton pattern. But don't think too much about it. All those OOP patterns from Java world lose part of their appeal in JS world. Some of them disintegrate completely. Concentrate on JS ways of solving problems.

Categories

Resources