Javascript: Where do I put an array with standard data? - javascript

I'm a bit new to posting here, I've always found my answers by searching and never needed to create my own post, so if I'm doing something wrong please do tell me.
I also don't really know how to formulate the question, so I'm sorry if it's weird.
I'm writing an extension for chrome and I'm unsure about where I leave my array with country codes and names.
Right now it's just at the start of my javascript file (with all the other code under it). It's not really a problem but I feel like I can put it somewhere else. Should I make a seperate file for it or should I leave it the way it is?
It's just this:
var countryList = [
["AF", "Afghanistan"],
["AX", "Aland Islands"],
["AL", "Albania"],
["DZ", "Algeria"],
["AS", "American Samoa"],
["AD", "Andorra"],
["AO", "Angola"],
["AI", "Anguilla"],
["AQ", "Antarctica"],
["AG", "Antigua And Barbuda"],
["AR", "Argentina"],
["AM", "Armenia"],
// And then a whole bunch more...
];
I'm sure I can find the answer somewhere, but since I'm having trouble formulating it I can't seem to find any related issues.

It's best practice to put it either in a namespace or scoped within another function to keep it out of the Global namespace of the 'Window' object and not have any potential conflicts with other variables/libraries.
Here's an example of a namespace:
var App = {
countryList: []
};
var arr = App.countryList[0];
Here's an example of scoping:
(function() {
var countryList = [];
// do something here
})();
When scoping within a Function like the last example, the 'countryList' variable will only be available to other functions/code contained within the surrounding function. By the way, this is scoped/contained it within an "anonymous method" that is automatically executed after declaration, via currying.
More information about Currying: http://www.dustindiaz.com/javascript-curry/

Related

Vanilla JS - hoisting a querySelected variable to Window

I've been researching and trying different solutions to this literally all day.
** EDIT: regarding duplicate post: As I wrote below, a set timeout function has been attempted and successful around the function call. Please, before you close my question, atleast ask that what you’re describing as a duplicate hasn’t already been attempted… or in this case. INCLUDED in my original post. I’m not looking for cred, I’m looking for help. **
I have a reusable function takes in 3 params:
What to wrap,
wrap in what type of element
and the id of the new wrapping element (so I can control access it later.)
Here's a codeSandbox version to help you help me! https://codesandbox.io/s/queryselector-to-globe-jbffk0?file=/index.html
Goal: I'd like to include a querySelector within the function that takes in the id to eliminate the extra step, to ensure the selector is defined after the item is created, and to keep a cleaner code-base. The problem is I keep fighting between a function that's surrounded by parens...
Var wrap = (function(params){...})(window); to potentially give global scope to the queryselector(object ref) I'm trying to create, and a standard es6 function I'm more familiar with... Var wrap = (params) => {...};
import "./styles.css";
const item = document.querySelector(".item");
var wrap = (function (toWrap, wrapper, id) {
wrapper = wrapper || document.createElement("div");
wrapper.setAttribute("id", `${id}`);
toWrap.parentNode.appendChild(wrapper);
// Non-working auto id something to
// window.id = document.querySelector(`${id}`);
return wrapper.appendChild(toWrap);
})(window);
// How can I "store the window.id" just as if it were manually written right here in global scope?
wrap(item, "div", "itemadded");
Note: the window thing I read at: http://markdalgleish.com/2011/03/self-executing-anonymous-functions/
Like I said, I can provide more working code/attempts to show I've made a ton of effort if anyone is wondering.
PS, I'll definitely mark the answer and give upvotes for help.
Thanks in advance!
If your still reading, I've tried simplifying even further, adding a timeout function to ensure that the function takes in toWrap correctly... idk what else to try... :(

Use one javascript script to dynamically modify another script

Yo!
I have an arbitrary javascript file, let's call it localScript, and just say it looks something like this:
<script id="myScript" type="text/javascript">
function () {
var blue = 'blue';
var person = {
firstName:"John",
lastName:"Doe",
age:50,
eyeColor:"brown"
};
var bluePerson = function () {
person[color] = blue;
};
}
</script>
I want to be able to use another externalScript to dynamically change the contents of this localScript. For this simple example, let's just say I want to update some of the values in localScript, like—maybe change age of the person object to 75. (Obviously, there's very simple ways to do this, but for my use case it's imperative that I use another externalScript to generate the contents of this localScript).
It would be easy if there was something like .innerHtml which I could use in the externalScript which would allow me to select an element and then replace the 'innerHtml' contents. The localScript, though, obviously isn't composed of elements.
As far as I know, when using a script to modify another script, there aren't any 'easy' ways to reference variables/objects/items in the script.
Things I've considered are indexOf(), search(), and match(), which I could use in externalScript to find strings inside localScript and then replace the values. I feel though as these could be performance no-no's, especially if the script grows.
Are there any easy ways to do this—with an emphasis on performance? I feel like there must be some easy way to reference one of the items in the script, though, I suppose a script is all one large string.. and maybe there is no simple way.
BTW—I'm using AngularJS, if there are any built in methods—though I think this is mostly just a javascript thing.
Thanks a bunch!
It looks like a bad idea, but... well, if it is imperative...
It makes no sense to change a script in a <script> tag - if it is in DOM, it has already executed (and no longer matters). Thus, to change the script before it has a chance to execute, you need to load it using AJAX, change the text, then eval it.
You can easily change the variables. Refer following steps
Include external script just below the script you have written.
Access the variables in the external script as if they are locally declared.
The variables you have created in above script are available in global scope and hence should be accessible from everywhere.
Note: This answer was added before the function clause was added.

Strange javascript behaviour - error unless 'classes' are defined in correct order

I have a very strange problem with javascript and easel js.
I am using the easel.js library and am already fairly far into the construction of a project using it.
I am attempting to have a 'class' (I know they aren't technically classes in javascript but I will use this terminology for lack of a better word) inherit the Shape class from easel js, and then have another class inherit that. So it would be something like this:
easeljs.Shape --> MenuButton --> BuildingButton
The code I am using looks like this:
BuildingButton.prototype = Object.create(MenuButton.prototype);
BuildingButton.prototype.constructor = BuildingButton;
function BuildingButton(){
MenuButton.call(this);
}
MenuButton.prototype = Object.create(createjs.Shape.prototype);
MenuButton.prototype.constructor = MenuButton;
function MenuButton(){
createjs.Shape.call(this);
}
The problem is that I get the following error with this code:
Uncaught TypeError: undefined is not a function
easeljs-0.7.1.combined.js:8439
(line 8439 is pointing to the initialize() function in the Shape() constructor).
now here's the strange thing. If I change the order of the definitions so that the sub class is defined second and not first, it works fine!
MenuButton.prototype = Object.create(createjs.Shape.prototype);
MenuButton.prototype.constructor = MenuButton;
function MenuButton(){
createjs.Shape.call(this);
}
BuildingButton.prototype = Object.create(MenuButton.prototype);
BuildingButton.prototype.constructor = BuildingButton;
function BuildingButton(){
MenuButton.call(this);
}
This is very confusing as I can't seem to figure out why on earth this is happening. I could just make sure I define them in the correct order and leave it be, but I have all my 'classes' in different source files which are then strung together by grunt, which does so alphabetically.
Also, I feel like I may have a big gap in my knowledge of javascript (or maybe easel.js I'm not sure what exactly is causing this behaviour).
Thanks in advance for your help and I hope the question makes sense!
MenuButton.prototype = Object.create(createjs.Shape.prototype);
…
BuildingButton.prototype = Object.create(MenuButton.prototype);
These two statements have a clear dependency and need to be executed in the correct order (for the function declarations the order is irrelevant if placed in the same scope/file, but if in different files they need to be loaded in the correct order obviously).
I have all my 'classes' in different source files which are then strung together by grunt, which does so alphabetically
That's not a good idea. You should use some build tool/script that allows the declaration of dependencies.
Read this to clear things out: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Inheritance_and_the_prototype_chain
In first example you try to inherit from nothing, since MenuButton.prototype is not yet defined. To make it work just add MenuButton.prototype = new createjs.Shape.prototype(instead of Object.create() wich shouldn't be used anymore) to instantiate it first before you can you use it. Your first code is like you are willing to eat a banana before having one.

JavaScript Strange Array Scope Issue

All source code is available here: Simply view the page source. Half the code is on that page, the other half is in the 'deputyDepot.js' file which is linked in the source and should also be viewable.
Just a few things: this is obviously still a work in progress. I'm pretty disorganized when coding, and I tend to jump around and do a little of this and a little of that. So it's a bit messy. Also the background. We'll just pretend that doesn't exist, okay?
So now, on to the problem! It seems that I'm unable to access arrays in any functions.
Currently, the way I've been testing is by modifying my main function (called weTalkNow(input)). This is located in deputyDepot.js. I set it to return whatever values I'm testing to see what they're set to. These values get printed in my chat box thingy. So I use it like console.log(). Currently it's set to return the length of the user input, but that's completely irrelevant.
_inputArray is populated by taking the user input (a string) and splitting it on spaces. It is declared at the top of the page. This is all fine and dandy.
Where the problem arises is if an array is populated manually.
var x = [ [1,2], [3,4] ];
/* Main Function */
function weTalkNow(){
return x[0][0];
}
That code, as far as I can tell, SHOULD output 1. But it does not. When the code is modified to this, it works fine:
/* Main Function */
function weTalkNow(){
var x = [ [1,2], [3,4] ];
return x[0][0];
}
This isn't very helpful, however. I need a global array, not a local one.
What makes things really weird is that if I decide to declare
var x = [ [1,2], [3,4] ];
on my main page (the one with HTML and stuffs), and then do this
/* Main Function */
function weTalkNow(){
return x[0][0];
}
in the deputyDepot.js file, it works fine. So suddenly if I declare a global array on a different page it works okay.
Please let me know if I can clarify any points in any way. I tried to give all the info I could. Random side tips are welcome too, but I'm mostly just focusing on this.
Again, just so I'm clear: for whatever reason, I CANNOT USE ARRAYS if I populate them manually (I assume this is somehow related to the problem). _inputArray is doing it's job fine, so that array works okay. It's the only global array that does so. But it isn't populated manually, but by the split function. I can't seem to be able to make a global array that is accessible by functions.
EDIT:
Okay, I found the problem! All the code I was writing works fine, like it's supposed to. The problem is that at the very top of my .js file was a broken function. This very first line prevented all the code below it from running, and so my arrays were never being initialized in the first place. For this reason I was unable to access them.
Once I checked the web console I was able to fix everything. I didn't know there was a web console before posting this question.
If your function refers to an array that is declared below the line where the function is called, the array will not be in scope.
myFunc();
function myFunc () {
console.log(ra[0]); // won't work
};
var ra = ["a"];
This will work:
var ra = ["a"];
myFunc();
function myFunc () {
console.log(ra[0]); // will work
};
The other thing to keep in mind is that javascript includes are processed in order also. One more thing: while generally javascript is processed from top to bottom, in other words; a function cannot call or reference variables that are defined on a lower line in your file, there is an exception. The exception is named functions, which you are using.
This won't work.
var funcA = function () {
funcB(); // wont work
};
funcA();
var funcB = function () {
console.log("from funcB");
};
This will work:
funcC(); // works fine
function funcC () {
funcD(); // works fine
}
function funcD () {
console.log("from funcD");
};
These subtle differences may be perceived to represent less than perfect design, but they can work very well.

Having trouble understanding a reflection test in Javascript Koans

There is already an answer posted to the test itself, which can be found here, but I can't seem to figure out why that answer is correct.
The part of the test that is giving me trouble is:
var keys = [];
var fruits = ['apple', 'orange'];
for(propertyName in fruits) {
keys.push(propertyName);
}
ok(keys.equalTo(['__', '__', '__']), 'what are the properties of the array?');
The (apparently) correct answer, as noted in the above linked question is
ok(keys.equalTo(['0', '1', 'fruits.prototype'), 'what are the properties of the array?');
I tried inserting the answer - fixed the syntax error - and my test still fails.
In the same test file, another test is nearly identical and the answer is what I would expect it to be:
test("property enumeration", function() {
var keys = [];
var values = [];
var person = {name: 'Amory Blaine', age: 102, unemployed: true};
for(propertyName in person) {
keys.push(propertyName);
values.push(person[propertyName]);
}
ok(keys.equalTo(['name','age','unemployed']), 'what are the property names of the object?');
ok(values.equalTo(['Amory Blaine',102,true]), 'what are the property values of the object?');
});
The only difference I can see between these two tests is that the second is using an object rather than an array.
I ran the code from the first test by itself (outside of the unit testing framework) and output the value of keys, which it showed as ["0","1"] - what I would expect. Where is this hidden third value, and how can I access it?
So, I guess I ultimately have two questions:
Why is the answer from the other question not working for me?
What is different about the first test and the second test?
Disclaimer: I'm pretty sure this is right, but haven't bothered testing it. Could you try my answer out, since you've got the tests running?
Looking at the files on GitHub, there is a helper script called koan.js. I'm assuming it gets loaded before the tests because I am too lazy to run them myself :P. (It's in the support directory.)
In this file, there is a method called equalTo defined on all arrays:
Array.prototype.equalTo = function(compareTo) { ... }
So the answers to your questions:
Because the answer to the other question was wrong. Completely misguided. Etc.
Because the method is defined on Array rather than Object.
Seems a little bit underwhelming.
If you define a function like this on the prototype, it will be inherited by all arrays. Try defining something like that in the console and then evaluate [].equalTo. And then, for more fun, try something like:
for (x in []) console.log(x)
Since this method is defined on the prototype, the loop iterates over it as well. So the answer is to the test is probably 0, 1, 'equalTo'. However, if you use the for loop with the hasOwnProperty check, it will naturally not iterate over the method.
This is really an object lesson about no using for in to iterate over arrays :). You never know what's going to sneak in... Coincidentally, this is why prototype.js fell out of favor despite actually being a nice framework.

Categories

Resources