Javascript prototype reflection function - javascript

I'm not exactly sure of the name of what I'd like to do but it goes like this:
Currently, I have a bunch of variables in my javascript context that look like $A126 or $B15.
Before running, I have to load in all 9000 of these variables and their current values so later parts of the code can just reference $xxx for the value.
The preloading is not efficient at all and is causing a bottleneck.
As there is a substantial amount of code that uses this $xxx notation I was wondering if it would be possible to make a universal change to $.xxx where $ is a function that performed a lookup of the value passed to it via what was after the period.
So $.xxx would be analogous to GetItem(xxx)
This is for a javascript environment in C# using clearscript, though I don't think that would impact the answer.
It looks like
function Field(val){
var value = val;
this.__defineGetter__("xxx", function(){
return value;
});
this.__defineSetter__("value2", function(val){
value = val;
});
}
var field = new Field("test");
console.log(field.xxx)
---> 'test'
That is almost an example of what I'm looking for. The problem is that I would like to have a general defineGetter that doesn't look for a particular getter by name.

Related

What is the role of variables (var) in Javascript

I am currently learning JavaScript and I am wondering what is the role of the variables (var).
In the example bellow, on the last two lines we first define a variable "monCompte" in which we call "john.demandeCaissier(1234)". Then we use console.log(monCompte) to print the result on the screen. What I don't understand is why do we first need to define the variable "monCompte" to call "john.demandeCaissier(1234)". Why can't we just do something such as:
console.log(john.demandeCaissier(1234));
Example
function Personne(prenom,nom,age) {
this.prenom = prenom;
this.nom = nom;
this.age = age;
var compteEnBanque = 7500;
this.demandeCaissier = function(mdp) {
if (mdp == 1234) {
return compteEnBanque;
}
else {
return "Mot de passe faux.";
}
};
}
var john = new Personne('John','Smith',30);
var monCompte = john.demandeCaissier(1234);
console.log(monCompte);
Thank you for you answers.
Yes, you can inline your function call and avoid the need for a variable. However, if an error occurs on that line, it becomes harder to debug:
var monCompte = john.demandeCaissier(1234);
console.log(monCompte);
vs
console.log(john.demandeCaissier(1234));
in the second example, there are several different modes of failure that would not be apparent in a debugging session. When split over two lines, some of those failures become easier to track down.
Second, if you wanted to reuse the value returned by john.demandeCaissier(1234) (the author might have shown this), then a variable becomes very useful indeed.
In my opinion, it's a worthy pursuit to perform only a single operation per line. Fluent-style advocates might disagree here, but it really does make debugging considerably easier.
You could definitely do that, but in more complex programs you will need to store variables for several reasons:
Shortening Long Expressions
Imagine if you saw this code somewhere:
console.log((parseInt(parseFloat(lev_c + end_lev_c)) - parseInt(parseFloat(lev_c + start_lev_c)) + 1));
BTW I got that from here
Wouldn't it be so much simpler just to split that expression up into different variables?
Storing Data
Let's say that you take some input from the user. How would you refer to it later? You cannot use a literal value because you don't know what the user entered, so do you just call the input function again? No, because then it would take the input a second time. What you do is you store the input from the user in a variable and refer to it later on in the code. That way, you can retrieve the value at any time in the program.
If you are a beginner, you might not see any use for variables, but when you start writing larger programs you will start to use variables literally in almost every line of code.
Variables exist to store data. They're useful because instead of invoking an operation over and over again, which is criminally inefficient, they allow you to invoke an operation once, and then use that result where necessary.
And that's for all languages, not just JavaScript.
Variables are structures that store some value (or values). They're only that and you could probably do all your code (or the majority of it) without them.
They help you organize and add some readability to your code. Example:
alert(sumNumbers(askNumber()+askNumber()));
takes a lot more effort to read/understand then this:
var firstNumber = askNumber();
var secondNumber = askNumber();
var total = sumNumbers(firstNumber + secondNumber);
alert(total);
Sure it's longer but it's more readable. Of course you don't have to use var for everything, in this case I could just hide the total.
Another common use for variables is "caching" a value.
If you had a function that sums like 1 million values, if you keep calling it for everything, your code would always have to do all that hard work.
On the other hand, if you store it on a variable the first time you call it, every other time you need that value again, you could just use the variable, since its a "copy" of that calculation and the result is already there.

Dependency injection in JavaScript doesn't work

I want to write a function createCoffee that accepts a function argument called knowHow
function createCoffee(knowHow){
var x=new knowHow(coffee,beans,milk,sugar);
knowHow.create();
}
This is so that I can have different knowHow for how to create the coffee.
Then I write a sample knowHow function
var x=function oneWay(a,b,c,d){
console.log(a+b+c+d)
};
I pass x to createCoffee
Then
a=5;b=1;c=2;d=2;
createCoffee(x);
This should createCoffee according to the specified knowHow.
I expected that the result would be logging in the sum of the variables. Does it have something to do with variable scope.
Is the example logically sound. How can I specify the variables in the oneWay(...) function
Instead of initializing a,b,c,d, do this:
var coffee=5, beans=1, milk=2, sugar=2;
Thanks everyone. I solved my objective in the following way ....
function coffeeMaker(knowHow,coffee,milk,sugar){
knowHow.create(coffee,milk,sugar);
}
var x={create: function oneWay(a,b,c){
console.log(a+b+c);
}};
coffeeMaker(x,2,3,4);
I wanted to make it so that I could do the program according to interface thing as is done in Java.
In Java you can pass reference to an interface and you can have different implementations.
I wanted to achieve the same thing.
In this I can change the knowHow and plug it into the coffeeMaker.
It looks redundant in the present case but when there are like 10 behaviors associated with an object then it becomes useful. I am drawing on the Strategy design pattern for this.

Change meaning of ["foo"] in Javascript?

I'd like to make foo["bar"] return the bar field value normally, but if it doesn't exist, look it up in another object to find it there. Is it possible to replace how [] works?
Why? I am porting a 6 year old Javascript application to AngularJS. In the existing app, there's (of course) one global variable (let's call it i2) that's used as a namespace that has everything in the app attached to it.
i2.models.fooModel.bar += 1; //and the rest of the app is similar
If that's not enough responsibility, i2 is also used as a registry of application "cells" like so:
var myCell = i2["MyCell"];
I'm breaking the global's fields into AngularJS services. The cell lookup feature is also broken out into another servicer "cell registry" service. Since this application has existing plugins that we'd like to be backwards compatible with, I'd like the code in the existing plugins like:
var myCell = i2["MyCell"];
... to still work (though deprecated). Is there a way I can replace the [] function in i2 to look up the field in i2, and if it doesn't exist, look it up in another object (the cell registry)?
No, you cannot directly and literally change the meaning of
i2["MyCell"]
because this is the design of the language and that typically can't be changed (and it would be terrible if you could). However, you can do something like this:
function lookupVar(key) {
var value = i2[key];
if(typeof value !== "undefined") {
return value;
}
// do whatever you want to do now that it couldn't be found
}
var myCell = lookupVar("MyCell");
Of course this can be extended to handle other things than just a single variable i2. It might also not be needed at all and a simple
var myCell = typeof i2["MyCell"] !== "undefined" ? i2["MyCell"] : somethingElse["MyCell"];
might be enough (though it contains annoying duplication). If you know that if they key exists in i2["MyCell"], it won't be a falsy value (0, "", false, …), then this will suffice
var myCell = i2["MyCell"] || somethingElse["myCell"];
Though it's not very future-proof.
Yes, you can use getters (don't work in IE8) or Proxy (not recommended for production code)...
Is there a way I can replace the [] function in i2 to look up the field in i2, and if it doesn't exist, look it up in another object (the cell registry)?
Or just think about prototypes.

Is it possible to concatenate a function input to text of another function call?

Firstly appologies for the poor title, not sure how to explain this in one line.
I have this Javascript function (stripped down for the purpose of the question)...
function change_col(zone){
var objects= zone1227.getObjects();
}
I am passing in an integer into the function. Where I have "zone1227", I want that 1227 to be the integer I pass in.
I've tried this;
var zonename = "zone" + zone;
var objects= zonename.getObjects();
but that doesn't work.
Is this possible? The functions do exist for every possible integer passed in, but I was hoping to keep the code compact rather than a long list of if statements with hardcoded function names.
Since zone1227 is apparently a global variable, it can also be written as window.zone1227 or as window['zone1227']. This means that you can achieve what you describe, by writing this:
function change_col(zone){
var objects= window['zone' + zone].getObjects();
}
Nonetheless, I agree with Interrobang's comment above. This is not a good way to accomplish whatever it is that you really want to accomplish. You should not be referring to global variables via strings containing their names.
No, you cannot refer to a variable with the value of a string, nor can you concatenate anything onto a variable name. EDIT: turns out you can. You still shouldn't.
Yes, you can avoid using a long hard-coded if/elseif sequence: use an array.
Then you can say this:
function change_col(arr, i)
{
var objects= arr[i].getObjects();
}
And the call would be something like:
change_col(zone, 1227);

pulling an array of objects

I currently have a validation script that has a selection of <input> elements stored in objects with properties such as "id", "type" "isRequired" and"isValid". I currently have this setup() function that does the following:
function setup(obj) {
obj.getElement().onkeyup = function() {validate(obj)}
}
In order to run this setup() function on all of my input objects I need to execute the following addEvents() function
function setEvents() {
setup(firstName)
setup(lastName)
setup(email)
setup(dateOfBirth)
}
I'm helping create a system that has multiple pages of nothing but forms so I'd prefer if I didn't have to type this for each object. Is there a way I can collect an array of all the objects that are based on a specific object template? This way I could loop through the array and apply a setup to each object in a single function. If not, are there alternatives?
(p.s. I've been asking so many object-oriented(oh, I crack myself up sometimes) questions lately because this is my first time messing with objects)
---Edit---
the object template I'm referring to looks something like this:
function input(id,isRequired,type) {
this.id = id
this.isRequired = isRequired
this.type = type
}
this is then followed by a
firstName = new input('firstName',true,'alpha')
As I said in my comment, you could add the element to an array when you create it:
var inputs = [];
var firstName = new input('firstName',true,'alpha');
inputs.push(firstName);
This is not ver convenient yet. But you could create another object which manages all this:
var InputManager = {
elements: [],
create: function(/* arguments here */) {
var n = new input(/* arguments here */);
this.elements.push(n);
return n;
},
setup: function() {
for(var i = this.elements.length; i--;) {
(function(obj) {
obj.getElement().onkeyup = function() {validate(obj)};
}(this.elements[i]));
}
}
};
with which you can do:
var firstName = InputManager.create('firstName',true,'alpha');
// etc.
InputManager.setup();
Something along these lines. I think this would be a quite object oriented way. If you have a collection of objects, you often have another object which handles the functions that should be performed on all those objects.
As with most javascript questions, the easiest way to do this is with a library such as jQuery. If you have a unique way to differentiate these objects with a css selector (e.g., they all have the class "validate" or they're the only input[type="text"] fields on the page or something), then you can do a simple selection like $('.validate') to get an array of all these objects. You can get this array using javascript of course but it's a tad more complicated. Once you have the array you can loop over the elements or you can do a simple bind like $('.validate').change(validate); which will call the validate() method whenever a dom element with the class 'validate' changes.
Edit: So obviously I don't know the entirety of what you're trying to accomplish, but if you're new to web programming, just note also that no matter what you're doing on the client side (ie in the browser), all validation should also be done on the server side. Javascript validation is generally used to just be user-friendly and not to actually validate your inputs, since I could easily just turn javascript off or redefine validate as function validate() {} and bypass javascript validation for whatever reason.
2nd Edit: So I'm not sure if this answer was 100% what you're looking for but it's good to know regardless.
Judging by your examples you are not using jQuery. And for that reason alone, I'm going to up vote you. On the same note, after you get really comfortable with JS and how you can do things, really consider using a framework or saving your scripts so you don't have to reinvent the wheel for each project.
You can actually use the DOM to your advantage!
All the forms in your page can be referenced with document.forms[index]. Alternatively you can also reference a named form with document.formName.
Look at this jsfiddle for an example using the latter.
UPDATE
Reading your update and the fact that you needed a way of creating the input objects and setup the validation. I updated my fiddle with a different approach.
Used the id to hold the validation info regarding the element then the addValidation function reverts the id to it's basic form so you can still use it normally throughout your application.
The only requirement is that you addValidation the first thing after page load. So the ID get revamped first.
The solution is also JS safe, meaning if the user doesn't have JS, apart from no validation, no other things will happen.
I think your problem is that the obj in the onkeyup scope is undefined.
function setup(obj) {
//obj is desired
obj.getElement().onkeyup = function() {validate(obj) //obj is undefined because onkeyup is the new scope of this function
}
instead you could do this:
function setup(obj) {
obj.getElement().onkeyup = function() {validate(this)
}

Categories

Resources