JavaScript Globals - Method Handling - javascript

I have multiple global arrays that a single method performs operations on. The method will only need to operate on one array at a time. I would like to accomplish this by passing a parameter to the method and then let the method decide which array it needs to modify based on that parameter. For example,
var globalarray1;
var globalarray2;
Operate(globalarray1);
function Operate(globalarray){
globalarray.push("test");
}
Of course, the code above only changes the value of the array local to the scope of the method. I know I can do something like this:
var globalarray1;
var globalarray2;
Operate(1);
function Operate(flag){
if (flag == 1){
globalarray1.push("test1");
}
else if (flag == 2){
globalarray2.push("test2")
}
}
However, it just doesn't feel right. How can I change the value of the globals using parameters in a single method without using a bunch of conditional statements?

Your first approach is correct. This statement, however, is not:
Of course, the code above only changes the value of the array local to the scope of the method.
Array objects are passed by reference called by sharing (i.e. the reference is passed by value, not the value itself). When you pass the array to the method, it can (and in your case does) actually modified the global variable. This would not be the case if you passed in an immutable or primitive value such as a number or a string. In those cases, the value is in fact local to the scope of the method.
The fact that your variables are global have nothing to do with it. Take this code, for example:
function Hello(){
var localArray = [];
Operate(localArray);
// now, localArray has been modified by Operate
}
Hello();
Above, localArray is not a global variable, but it can still be affected by Operate() if you pass the array in directly.

.push is a mutator method, and would change the array passed by the method since objects are passed by reference and not value in ECMAScript. So the first way is correct.

Related

How does the length property work?

I'm writing code that needs to reference this inside a prototype, but it cannot be a function. Javascript won't let me do this, but it seems like the length property of arrays and strings does this. I know that length is built-in, and my code is not, but if I can, how do I implement this?
I tried:
String.prototype.prototypeName = (function(aThing){
//Do whatever I need to do here
})(this);
But that references to the global object, because this is called outside of the function.
String.prototype.prototypeName = function(aThing){
//Do whatever I need to do here referencing this
};
However, that is a function, and I can't have that.
I can't have a function because the user can call the function and use typeof on it, and the prototype is supposed to return a string.
For example:
String.prototype.reverse = "Put something that is the reversed string (or this)";
console.log("Stuff"); //"ffutS"
console.log("Anything"); //gnihtynA
You can use a Javascript getter to access a computed property without calling a prototype function. Note this is IE9+ only.

Can't use String.prototype.match as function for Array.some?

This doesn't work:
var s = '^foo';
console.log(['boot', 'foot'].some(s.match));
Uncaught TypeError: String.prototype.match called on null or undefined
But this does:
var s = '^foo';
console.log(['boot', 'foot'].some(function(i) { return i.match(s) }));
Why is this? I imagine somehow the String.prototype.match function is too "primitive" or something, but why exactly? Since I'm not using ES2015, the second version seems quite verbose. Is there an alternative?
EDIT
When I wrote the above, I actually got it backwards compared to my actual need, which was matching one string against a number of regexes. But thanks to the great answers and comments below, I get it: [/^foo/, /^boo/].some(''.match, 'boot').
Note: The value of this is determined by how the function is called! (exception: bound and arrow functions)
If you pass s.match to .some, then the function will be called with this set to the global object (e.g. window) not the string it "belongs" to.
I.e. it would be equivalent to this:
String.prototype.match.call(window, 'foo')
This cannot work because this has to refer to a string object.
You could solve this by binding the function to a specific this value:
['boot', 'foot'].some(s.match.bind(s));
Learn more about this:
MDN - this
You Don't Know JS: this or That?
How to access the correct `this` context inside a callback?
A function value in Javascript does not bring its object along with it. The value of s.match is a plain function value, with no knowledge that you happened to find it attached to s. In fact, no matter what String you access it through, it's always the same function value:
"foo".match === "bar".match
//= true
When you call a function through an object, Javascript sets this to that object for the duration of the function call. But as soon as anything comes between retrieving the function value and calling it, any object association is lost.
You can create a function that does remember a specific this value using bind, as in #Felix King's answer. someFunction.bind(someObject) has approximately the same meaning as function(arg1, arg2,...) { return someObject.someFunction(arg1, arg2,...); }, but it automatically handles the number of parameters properly.

Passing this.value to a function in JS and then changing that value

I'm writing a JS function that I would like to be used directly with an onfocus event, and also within another function. The problem is that if I pass the function this, then all of my function code needs to be field.value. That causes a problem when I use it inside a function, since the passed variable doesn't have a .value attribute.
My thought was then to just pass this.value to the function, so I could just work with the data passed, whether it was a field value or a function value. However, now it doesn't change the value of the original field.
Is there a good way around this, or do I just need to have two functions?
Here is my two different versions of the code:
// Can't be used with when using onfocus="makeNum(this.value)"
function makeNum(value){
value = value.match(/\d+(\.\d{1,2})?/g).join("");
}
OR
// Can't be used with a function, but works when using makeNum(this)
function makeNum(field){
field.value = field.value.match(/\d+(\.\d{1,2})?/g).join("");
}
Objects are passed by reference, but primitives are passed by value. Since this.value is a primitive (i.e. a string or number for example), it will be copied when you pass it to the function, and modifications to it only apply the the function.
Write the function so it returns a value, then assign it back to this.value like this:
this.value = makeNum(this.value);
function makeNum(value){
return value.match(/\d+(\.\d{1,2})?/g).join("");
}
If you showed the two flavors of desired code, we could probably help a lot more specifically. Objects are passed by reference, but individual variables are not so you can't have the same behavior for both.
Your options I can think of are this:
Pass an object into the function as an argument then refer to obj.value in order to change the actual value on the original object.
Pass a callback function to your main function that operates on the object and you can then have several different ways of setting the value from the same core code.
Break your core function up into smaller functions that can be called from different places and used in different ways when operating on different types of source data.
Write a single function that can tell from its arguments which type of data you are passing to it and operate accordingly.
In the case of your code examples, here's the core function that you can use in a couple different ways:
function makeNum(value){
return(value.match(/\d+(\.\d{1,2})?/g).join(""));
}
x.onfocus = function() {
this.value = makeNum(this.value);
}

Memory Usage/Garbage Collection of Objects Passed Into Functions

When an object is passed into a function, the object is passed by value (although the value for an object is a reference). I am passing very large objects into my functions, but only accessing a handful of properties (6-12) from within the function. Memorywise, would it be better to only pass the properties instead of the whole object? Or would this actually create more of a memory issue if my properties are strings?
Given the two functions below, what happens memorywise? In f1, does javascript/v8 create a new object foo in memory or is it really just a pointer? Does it remain just a pointer if I access a string property or does V8 then make a copy of that string for use within the function. In f2, I assume that a completely new copy of the string foo is made for the function. Is this a correct assumption?
function f1(x) {
var y = x.foo;
}
function f2(foo) {
var y = foo;
}
var obj = {foo: "test"};
f1(obj);
f2(obj.foo);
"Memorywise, would it be better to only pass the properties instead of the whole object? Or would this actually create more of a memory issue if my properties are strings? "
That would require more memory. Doesn't really matter if they're strings, since strings are generally implemented as Reference Types as well, but for each argument, there will be a copy of the value instead of just a single copy of the Object reference.
The object reference is very light weight, so you just as just copy that instead of all individual members of the object.
Also, this will be required if you rely on mutations of the object within the function.
In your examples, there's only one property being passed (a string). If your code doesn't rely on mutations of the object itself, then there'll be no significant difference between the two.
In the example that passes the object, the only copy is the object reference. It isn't a pointer, but it is very light weight, and nothing to be concerned about.
In the example that passes the string, it would seem as though it makes a copy of the entire string, but since stings are immutable in JavaScript, implementations generally implement them as reference types as well.
Therefore it's as efficient to pass a single character string as it is to pass a 10,000 character string.

JavaScript function arguments for filter function

numbers = [1,2,3,4,5,4,3,2,1];
var filterResult = numbers.filter(function(i){
return (i > 2);
});
I don't understand how this works. if I omit the i as a function argument it breaks the function but the i isn't tied to anything so why does it need to be there?
.filter (Array.prototype.filter) calls the supplied function with 3 arguments:
function(element, index, array) {
...
element is the particular array element for the call.
index is the current index of the element
array is the array being filtered.
You can use any or all of the arguments.
In your case, i refers to the element and is used in the body of your function:
function(i){
return (i > 2);
}
In other words, "filter elements where element is greater than 2".
i is a reference to the current object in the set when inside that closure. It could be named anything as it is just a variable, but then would have to have the same name inside the closure. Instead of using function(){} you could use a callback which is how filter was designed.
The reference is done implicitly by the definition of .filter, you can read more here: http://msdn.microsoft.com/en-us/library/ff679973(v=vs.94).aspx
The i is actually very important. It tells gives the filter function information about the elements it's acting on. In fact it's used right here (i > 2).
This keeps elements whose value is greater than 2.
That i is the formal parameter for the function you are supplying to .filter(). If you do not insert it, the function will not have any way¹ to refer to the argument it's being passed (the i inside the function body will then refer to some other entity that might not even be defined -- window.i would be typical).
¹ that is technically a lie, but consider it true for the purposes of this discussion
An old thread indeed, but just filling in what remains unsaid.
The parentheses are there for you the programmer to insert whatever variable name makes sense for your specific program.
If you choose 'i', most other (beginner) programmers might think 'Oh, i means index'. Which would be wrong.
If you use one argument instead of three, I'd choose 'el' to represent the element, or if your array contains flavors of soda, I'd choose 'flavor'.
That's ES5 notation and maybe if you see it in ES6 notation you would understand why the "i" is a must:
numbers.filter(i => i > 2);
A variable must always be used to refer to the item of the array that you process in each iteration (in this case "i"). It has to be passed as argument to the entry point of the function (in ES6 that goes before the arrow).

Categories

Resources