How to make concatenation within javascript function - javascript

I want to call the javascript functions like bbb(a1), bbb(a2), bbb(a3)......
through the function
function sss()
{
for (i=1;i<=3;i++){
bbb(a.i)
}
}
sss();
There must be many errors in the above code. What should be the correct syntax? Specially in bbb(a.i) i.e., to concatenate 'a' with variable 'i'.

I'm not 100% sure of your intentions, but re-reading your question a couple of times, I think you're looking to build a string out of the iterator variable i to pass to bbb(). If so, you'd want this:
function sss() {
for (var i = 1; i <= 3; i++) {
bbb("a" + i);
}
}
This will effectively do:
bbb("a1");
bbb("a2");
bbb("a3");
Also note the introduction of var before i = 1 -- you definitely don't want to accidentally create global iterator variables.

If I'm understanding you right, there aren't any syntax errors, but there are a couple of others:
function sss()
{
var i; // <=== Declare `i`
for (i=1;i<=3;i++){
bbb(a[i]); // <=== Use [i] to access `a[1]`, `a[2]`, etc.
}
}
sss();
Note that if a is a normal, non-sparse array, you probably want:
for (i=0;i<=a.length;i++){
In JavaScript, you can access properties using dot syntax with a literal (obj.foo), or bracketed syntax with what is technically coerced to a string (obj["foo"]). The second syntax is what we typically use for arrays, using a[0], a[1], etc. (which are technically, theoretically coerced to a["0"], a["1"], etc., because regular JavaScript arrays aren't really arrays at all.)

Related

JavaScript Function Parameters vs Object Methods

Can someone explain to me the difference of when to use a function by feeding your variables into the parenthesis, and when to tack the function on after the variable with a period, like using the toString() function?
example code
function addMe(a){
a = a+1;
return a;
}
var num = 1;
addMe(num);
num.toString();
I'm not actually sure if my syntax is correct, but I want to know when to feed a variable as a parameter, like how I feed the variable num, to the addMe function. And when to use the function .toString() by putting a period after the variable and typing out the function.
could I have done something like this- provided I built my function correctly?
var num = 1;
num.addMe();
Thanks for the help!
The first is used for simple 'stand alone' functions, while the latter is used for object methods. E.g a number object by default has a toString() method. Some object methods may also require parameters to be passed between the parentheses.
Variables (a function declaration is just a function stored in a variable) are looked up in the scope chain (going up to the next outer scope until a variable with the name is found):
let a = 1; // outer scope
{ // inner scope
console.log(a); // looked up in "inner scope", than "outer scope"
}
Properties of an object are looked up in the objects prototype chain, so if you do
a.b
then a gets looked up in the scopes as explained above, then b is accessed on the resulting object (everything is an object in JavaScript, except for "nothing" (undefined, null)) by looking up the prototype chain. For a simple object, the chain is quite short:
const a = { b: 1 }; // object -> Object.prototype
Here b will be found in the object itself. However all objects inherit from the Object.prototype object, so if you add a property to that (please don't):
Object.prototype.test = 1;
you can then look it up on every object, as the lookup traverses up the prototype chain, and reaches Object.prototype:
console.log({}.test); // 1
Now for numbers (like in your case), they inherit the Number.prototype so you could do:
Number.prototype.addMe = function() {
console.log(this);
};
// two dots are needed to distinguish it from numbers with a fraction (e.g. 1.2)
1..addMe();
That said, now addMe can be called on every number, everywhere in your code. While that might seems useful, it is actually a pain as you don't know where a certain method was added
1..whereDoIComeFrom()
that makes code unreadable and unstructured. Instead if you need a certain functionality multiple times, abstract it into a function, don't touch the native prototypes.
I assume that addMe is just a simplified example, if it isn't, read on:
If you pass an argument to a function in JavaScript, the value will be copied (it is a bit more complicated with non primitives (everything except numbers, booleans etc.)) into the parameter variable of the function called so here:
function addMe(a){
a = a+1;
console.log(a); // 2
return a;
}
var num = 1;
addMe(num);
console.log(num); // 1 ... ?
you actually got two variables (a and num), changing a does not change num. But as you return a you can do:
num = addMe(num);
which copies the value of num into a, then increases a by one and then copues the value of a back to num.
When you did var num = 1 you created a JavaScript object. It looks just like a number but you can think of everything in JavaScript as an object (simplification) and all these objects have different features. So a number has some features, a string has some other features, etc.
You mentioned one feature: toString. Another feature would be toLowerCase.
toString and toLowerCase are functions that come with JavaScript. These functions are then "put on" all of these objects for us to use.
I can have a string variable like
var text = 'MY TEXT'
var lowercaseText = text.toLowerCase()
console.log(lowercaseText) // my text
This code will work because it was decided that the toLowerCase function should work on strings
I can also have an array (list of items)
const list = ['A', 'B', 'C']
const answer = list.toLowerCase()
console.log(answer)
But this code won't work because toLowerCase doesn't work on arrays. So you get the following error message: list.toLowerCase is not a function.
Basically its saying: I don't know what toLowerCase means when used on this list variable (array).
In JavaScript this is called prototypes. Prototype is a way for JavaScript to get some feature from another. Basically: I have all kinds of functions, what object can use what functions. This is called the prototype chain.
In both cases you are using a function. addMe is a function you created and toString is a function in JavaScript that has been placed on objects through this prototype-chain.
Im not actually sure if my syntax is correct
Yes your syntax is correct. Your addMe function is the standard way to create a function in JavaScript.
But i want to know when to feed a variable as a parameter, like how i
feed the variable num, to the addMe function.
Just like you did, you define a function and parameters like you did.
..and when to use the function .toString() by putting a period after
the variable and typing out the function.
When you want to place your function on a object so that all instances of that object can you that object.
In most cases, espcially when you are starting out. You don't have to worry about these prototypes. The way you did.
function addMe(number) {
return number+1
}
const answer = addMe(1) //2
Is a standard way of defining a function and calling it.

Looking for a good clear explanation for why this doesn't work

So I am learning Javascript and testing this in the console.
Can anybody come up with a good explanation why something like this does not work?
var students = ['foo', 'bar', 'baz'];
function forEach2(arr1) {
for (i = 0; i < arr1.length; i++) {
console.log(arr1[i]);
}
}
students.forEach2(students)
I get : Uncaught TypeError: students.forEach2 is not a function
For me it would seem logical to work but it doesn't
why?
forEach2 is not a function of students. students is an array containing 3 string values. just use forEach2 without students. before it.
var students = ['foo', 'bar', 'baz'];
function forEach2(arr1) {
for (i = 0; i < arr1.length; i++) {
console.log(`arr1[${i}]:`, arr1[i]);
}
}
console.log("students:", students);
console.log("students has .forEach2 function ?", typeof students.forEach2 == "function");
console.log("forEach2 is a function?", typeof forEach2 == "function");
console.log("forEach2(arr1)...");
forEach2(students);
console.log("students.forEach(student)...");
//forEach already has a native implementation
students.forEach((student)=> {
return console.log("student:", student);
});
JavaScript is an object-oriented language with prototypal inheritance.
Object-oriented means you have objects with members (called properties in JavaScript) which hold values. In JavaScript, functions are “first-class citizens”, meaning you can assign them to variables just like you would other values.
When you write write a function such as ‘function x(y) { return y +1; }’, what’s really happening is 1) you are declaring a variable named “x”, and 2) you are creating a function “value” which is then assigned to that variable. If you have access to that variable (it’s within scope), you can invoke the function like ‘x(5)’. This evaluates to a new value which you could assign to another variable, and so on.
Ok, so now we have a problem. If functions are values, and values take up space (memory), then what happens when you need a bunch of objects with the same function? That’s where prototypal inheritance comes in. When we try to access a value on an object, via either the member access operator ‘.’, like ‘myObj.someValue’, or via an indexing operator ‘[]’ like ‘myObj[“someValue”] (both of which are equivalent in JavaScript, for the most part), the following occurs:
The runtime checks to see if a ‘myObj’ variable exists in the current scope. If it doesn’t? Exception!
The runtime looks at the object referenced by the variable and checks to see if it has a property with the key “someValue”.
If the object has that property, the member access expression (‘myObj.someValue’) evaluates to that property’s value, and we’re done.
If the object does not have that property, we start doing prototypal inheritance stuff. In JavaScript, all this means is that when we try to access a property that doesn’t exist, the runtime says “hey, what if this objects *prototype has a property with that key?” If it does, we use the prototype’s property’s value. If it doesn’t, we return ‘undefined’.
Notice that because prototypes are just objects, and therefore can themselves have a prototype, step 4 is recursive until we run out of prototypes on which to attempt member access.
Ok, so at this point you may be thinking “what’s a prototype and what does it have to do with my question?” It’s just an object. If any object has a property with the key “prototype”, then that property’s value IS a prototype. Specifically, it’s that object’s prototype. And so this is where your problem arises.
There is no property on your object with the key “forEach2”. Why? Because you didn’t put it there, and you didn’t put it on the object’s prototype (or any of the prototypes “up stream”.
The ‘forEach’ function of an Array exists as a property on the Array’s prototype: ‘Array.prototype.forEach = function (...) {...}’. Your function does not, and therefore you cannot use member access on an array to get that value (the function), and that’s why your code is borked.
Fortunately for you, a variable ‘forEach2’ exists in your current scope, and you can just use it without needing to do any member access! You just write ‘forEach2(students);’ and that’s all.
But what if you want to access that function anywhere you have an array? You have two options: put it on every instance of your arrays, or put it on Array’s prototype. ‘Array.prototype.forEach2 = forEach2;’ however, if you do this you will need to change your function a bit. Right now it expects the array as its first argument (‘arr1’), but its redundant to write ‘students.forEach2(students)’ because when a function is invoked immediately following member access, the function will be provided with a special variable ‘this’ which will have the value of the object for which you are accessing its member. So, in this case, you would omit the ‘arr1’ argument and instead just use the the special ‘this’ variable which is magically in scope within your function.
Array.prototype.forEach2 = function ()
{
for (var i = 0; i < this.length; i++)
{
console.log(this[i]);
}
}
I hope this clarifies some things for you, and I hope it raises a bunch more questions.
P.S: Adding things to prototypes is both powerful and considered harmful unless you know what you’re doing and have a good reason to do it (like writing polyfills)... so do it at your own peril and use responsibly.
For your example to work, simply add the following statement after definition of forEach2:
// Here you're redefining the built-in forEach function with your
// custom function
students.forEach = forEach2;
// Now this must work
students.forEach(students);
This is an explanation why is that:
An array is a particular implementation of the Object. Object is an aggregate of the property:value pairs, such as
{'some_property': '1',
'some_function': function(),
'forEach': function() {<function logic>},
...
}
Your error 'Uncaught TypeError: students.forEach2 is not a function' tells, that there is no property forEach2 (which supposed to be a function) in between the Object's properties. So, there are two methods to correct this situation: - add a property (method function) to the object, or alter the existing property with similar functionality (not necessarily though).
[1] The first method assumes you add a new property function using Array.prototype.forEach2 = function() {...}.
[2] The second - you may redefine or alter any property in the Object by just assigning a new value to that property: Object.forEach = forEach2
Because the function forEach2 is not available either within the Array.prototype or is not a direct property of that array, so, you have two alternatives to use that custom forEach:
Use a decorator to add that function to a specific array
var students = ['foo', 'bar', 'baz'];
function forEach2() {
for (i = 0; i < this.length; i++) {
console.log(this[i]);
}
}
function decorate(arr) {
arr['forEach2'] = forEach2;
return arr;
}
decorate(students).forEach2()
Add that function to the Array.prototype
var students = ['foo', 'bar', 'baz'];
Array.prototype.forEach2 = function() {
for (i = 0; i < this.length; i++) {
console.log(this[i]);
}
}
students.forEach2();
Both alternatives use the context this to get the current array.

JavaScript chained concatenation function?

No jQuery please!
The Web says that the native String.concat() and join() functions of JS are to be avoided because of their poor performance, and a simple for() loop of += assignments should work a lot faster.
So I'm trying to create a function in pure JavaScript that will concatenate strings. This is somewhat how I envision it:
I want a main function concatenate() that will concatenate all passed arguments and additionally insert a variable string after each concatenated argument, except for the last one.
If the main function is called by itself and without the chained .using() function, then that variable string should be an empty one, which means no separators in the result.
I want a chained sub-function .using() that will tell the main concatenate() function what certain string other than the default '' empty string to add after each concatenated segment.
In theory, it should work like this:
concatenate('a','b','c'); /* result: 'abc' */
concatenate('a','b','c').using('-'); /* result: 'a-b-c' */
I want to avoid having two separate functions, like concatenate() and concatenateUsing(), because the concatenateUsing() variant would then have to utilize a special constant argument (like arguments[0] or arguments[arguments.length-1]) as the injected separator and that would be terribly untidy. Plus, I would always forget which one it was.
I also want to avoid having a superceding Concatenate object with two separate sub-methods, like Concatenate.strings() and Concatenate.using() or similar.
Here are some of my failed attempts so far...
Attempt #1:
function concatenate()
{
var result="";
if(this.separator===undefined){var separator=false;}
for(var i=0; i<arguments.length; i++)
{result += arguments[i] + ((separator && (i<arguments.length-1))?separator:'');}
this.using=function(x)
{
this.separator=x;
return this;
}
return result;
}
So what I'm trying to do is:
check if the separator variable is undefined, this means it wasn't set from a sub-method yet.
If it's undefined, declare it with the value false for later evaluation.
Run the concatenation, and if separator has another value than false then use it in each concatenation step - as long as it's not the last iteration.
Then return the result.
The sub-method .using(x) should somewhere along the way set the
value of the separator variable.
Naturally, this doesn't work.
Attempt #2:
var concatenate = function()
{
var result="";
var separator="";
for(var i=0; i<arguments.length; i++)
{result += arguments[i] + ((separator && (i<arguments.length-1))?separator:'');}
return result;
}
concatenate.prototype.using=function(x)
{
this.separator=x;
return this;
}
It also doesn't work, I assume that when this is returned from the using() sub-method, the var separator="" of the main concatenate() function just overwrites the value with "" again.
I tried doing this 4 or 5 different ways now, but I don't want to bore you with all the others as well.
Does anyone know a solution for this puzzle?
Thanks a lot in advance!
What you are trying to do is impossible.
You cannot chain something to a method call that returns a primitive, because primitives do not have (custom) methods1.
And you cannot make the first function return different things depending on whether something is chained or not, because it doesn't know about its call context and has to return the result before the method call is evaluated.
Your best bet is to return an object that can be stringified using a custom toString method, and also offers that using thing. It would be something along the lines of
function concatenate() {
return {
args: Array.from(arguments), // ES6 for simplicity
using: function(separator) {
return this.args.join(separator);
},
toString: function() {
return this.args.join("");
}
};
}
console.log(String(concatenate('a','b','c')); // result: 'abc'
// alternatively, use ""+… or explicitly call the ….toString() method
console.log(concatenate('a','b','c').using('-')); // result: 'a-b-c'
1: No, you don't want to know workarounds.

Why is this checking for variable existence using array notation instead of dot notation?

I'm looking at https://www.youtube.com/iframe_api and it starts with:
if (!window['YT']) {
var YT = {
loading: 0,
loaded: 0
};
}
if (!window['YTConfig']) {
var YTConfig = {
'host': 'http://www.youtube.com'
};
}
I don't understand why checks for variables are not using dot notation such as:
if (!window.YT) {
var YT = {
loading: 0,
loaded: 0
};
}
if (!window.YTConfig) {
var YTConfig = {
'host': 'http://www.youtube.com'
};
}
Is this just personal preference? Or are there implications?
There are no implications in this specific example
Common reasons to use array notation would be if the string contains special characters
// something like
obj["hello world"]
// or like
obj["hello-world"]
Another reason would be if the key you want to access is a variable
var foo = "hello";
obj[foo] === obj.hello;
Otherwise
// these are the same
obj.foo === obj["foo"]
When the string doesn't contain any characters that can't be used in an identifier, there is no difference between accessing the property by name or using a string.
Note that the code is written as if the variables are created inside the if statements if they don't exist. The variables does actually always exist, as the declaration is hoisted to the beginning of the scope, so the if statements only checks if the variables contain a falsy value.
The author of the code perhaps thought that it would be safer to check for the existance of the variables by accessing them using a string, but there is no such difference. In this case there is no need for any such caution anyway, as the variables definitely always exist.
The code is the equivalent of:
var YT, YTConfig;
if (!YT) {
YT = {
loading: 0,
loaded: 0
};
}
if (!YTConfig) {
YTConfig = {
'host': 'http://www.youtube.com'
};
}
If any of the variables did exist prior to this code, the declaration for that variable here would just be ignored, i.e. the variable won't be redeclared by a duplicate declaration.
In your specific example, there is absolutely no difference. They both access the same variables.
However, there are advantages and disadvantages to each.
Dot notation
Personally, I use the dot notation in every single time that I don't need to use the array notation. It is much more readable with the . separating each object level.
office.employees[0].empNumber is much more readable than office['employees'][0]['empNumber']. (They both access the same variable)
Array notation
There are 3 main reasons for you to use the array notation :
When you're accessing number-indexed arrays (employee[0], employee[1], ...)
When you need to use variables as keys (phonelist[customerServiceID], where customerServiceID is a variable, which may be a number or a string)
As #naomik indicated in his answer, special characters as keys would also make you need to use the array notation instead.

Odd Javascript alert output

I have an odd problem. I'm trying to use Javascript to fetch me some values from a multidimensional array, and it's giving me some weird output.
Here is my code:
foo = [['3','4'],['5','6']];
for (bar in foo) {
baz = bar[0];
alert(baz);
qux = bar[1];
alert(qux);
}
Here is the output of the above:
// These are all alerts, by the way
0,undefined,1,undefined,$,f,$,c,e,a,c,l,c,l,i,i,n,a,s,l,i,c,o,a,p,g,e,g,e,i,n,c,o,e,r,e,m,f,l,p,i,h,e,r,g
Can somebody tell me what is happening?
Here is a jsFiddle of the problem: http://jsfiddle.net/Jey6w/
Edit:
Here is another jsFiddle, with another layer of "Inception": http://jsfiddle.net/8vyGq/
The output:
// Again, these are all alerts, and * signifies undefined
0**1**$ff$ceaacllcllinnassliicooappgeegeeinncooerremmfllpiiheergg
The JavaScript for ... in loop gives you the names of the object properties, not the values.
Don't use for ... in for real arrays. Use a numeric index or .forEach().
The reason you're getting your output is complicated and uninteresting, since you just shouldn't do that, but here's a start. The property names will be coerced to strings by the for ... in. Thus, on the first iteration, "bar" is the string "0", so ("0")[0] is just "0", and ("0")[1] is undefined because "bar" is a single-character string.
After that, your for ... in loop staggers into some other properties inherited from somewhere; perhaps you're using Prototype or something. The loop then alerts the first two characters of the names of all those other properties.
I could be wrong, but I think it's due to the fact that bar is returning a reference to a property within an object. Changing your selectors to foo[bar][0] works a treat.
foo = [['3','4'],['5','6']];
for (bar in foo) {
alert(foo[bar][0]);
alert(foo[bar][1]);
}​
In cases where your object is simply a multi-dimensional array, I would sway array from using the for in statement, as it can select unwanted properties. I would stick to the good old fashioned for(start, stop, increment)
foo = [['3','4'],['5','6']];
for (i = 0; i < foo.length; i++) {
alert(foo[i][0]);
alert(foo[i][1]);
}​
Update - jQuery
As there has been mention of jQuery's .each method I thought I'd also post an example of how it could be utilised. The jQuery's each method passes 2 optional parameters, indexInArray, and valueOfElement. Additionally, the jQuery documentation also states that
The value can also be accessed through the this keyword, but
Javascript will always wrap the this value as an Object even if it is
a simple string or number value
With this in mind, we could achieve the same results as previous example, using the following jQuery (jsFiddle):
var foo = [['3','4'],['5','6']];
$.each(foo, function() {
// 'this' is the context of the current item within the array
alert(this[0]);
alert(this[1]);
}​)​

Categories

Resources