In class, teacher couldn't explain why tweets(i) failed and tweets[i] works:
var tweets=["hi","who","when","where","bye"];
alert("start");
for (var i=0; i < tweets.length; i++) {
alert(tweets[i]);
}
alert("finish");
Brackets are used for functions, so array() would be a function called array. Square brackets are used for arrays, so array[] would be an array. array[0] is the first entry in an array, array(1) would send 1 as an argument to a function called array.
And stop going to classes where the teacher can't explain something this simple. They clearly aren't a programmer.
The reason tweets(i) fails in this code snippet is because, when you say tweets(i), javascript looks at it and says "oh, the code wants me to go find a function named tweets and execute it with a parameter named i."
When javascript sees tweets[i], it says "oh, this isn't a function. The code wants me to find the number-i place in an array and give it back the value stored there.
In short, The reason tweets(i) doesn't work is because you're telling it to alert a function that you haven't defined.
The () is a method invocation operator and the [x] is an member access operator. As array is not a function (e.g. typeof array !== 'function'), so you can only use member access operator on the array.
Note:
I don't know the specification name of the above operators, will need expert explanation on them.
A function is an object so you can use both operators on it
e.g.
var func = function() { return 'hello'; };
func.world = 'earth'
console.log(func());
console.log(func['world'])
console.log(func.world)
Related
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.
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.
I have come across an interesting piece of code:
function repeat(str,x) {
return Array(x+1).join(str);
}
repeat("wow", 2);
The outcome of this is a string "wowwow". However, I have no idea what this Array(x+1) is actually doing. And very interesting thing is that if I just use Array(x) it prints the str only once and not twice as expected.
When I console.log Array(x+1) it gives this strange output:
Array(x+1) (3) [empty × 3]
I am aware that there exists a repeat() method on strings which can be used happily to achieve the same result as the presented function. But as I've come across it, I would like to know the mechanism behind Array(x+1). I also know what an array or new Array() is. But this I see for the first time.
Array is specified such that new is optional. From the spec:
When called as a constructor it creates and initializes a new Array exotic object. When Array is called as a function rather than as a constructor, it also creates and initializes a new Array object. Thus the function call Array(…) is equivalent to the object creation expression new Array(…) with the same arguments.
(my emphasis)
To my surprise, the MDN page is not at all clear about this. If I get time, I may have to fix that...
As you can see in console Array(x+1) creates array with 3 empty elements (as far as x = 2). Then you join these elements with string wow so you have:
empty element + "wow" + empty element + "wow" + empty element = "wowwow"
Array(x+1) creates an array of 3 elements all containing empty elements.
Later you are joining these empty elements with the string wow, thus returning:
empty + "wow" + empty + "wow" + empty => wowwow
It is a function that creates an array.
Things like this you should really just try in you console before asking.
These things can be done in Javascript even though they are somewhat contra intuitive:
function A() {
return new Array();
}
let myA1 = A(); // returns an array
let myA2 = new A(); // also returns an array.
EDIT:
The reason is that Javascript is a prototypal language and a "Class" is just a function that we new. If that function is not returning anything we get a new instance of in our case A and if the function returns some other object, that object gets returned.
What is does is to create an array with size x+1(3, in this example). And filling it each cell with the str variable value.
In this code I create an array of size 3 cells and fill them with the string "yolo".
$(document).ready(function(){
var str = "yolo";
console.log(Array(4).join(str));
})
Example fiddle: https://jsfiddle.net/6o90fv9c/
I am a novice in nodejs and javascript .I am learning nodejs. I have a doubt here . I came across a node js code , which I was unable to understand :
jumble = {} ;
jumble.debug = false;
jumble.start = function (guid, callback) {
}
I am still wondering , what does jumble.start do when its just an empty array, any help /links would be appreciated Please
There are no arrays here.
jumble = {} ; creates a object and assigns it to jumble
jumble.debug = false creates a property called debug on the object and assigns the value false to it.
jumble.start = function (guid, callback) {} creates a property called start on the object and assigns a function to it.
You could call that function with jumble.start(1,2), but it wouldn't do anything since the function doesn't have anything between { and }.
I don't know node.js but, I know it is similar to javascript.
So, first of all, jumble is an object and not an array, as you think it is.
debug is a property of jumble object which has been assigned the value of false.
start is a function of jumble object which is obviously empty as it does nothing when called by doing jumble.start(3,4).
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]);
})