Modern JavaScript From The Beginning: Section 2 – JavaScript Language Fundamentals (3 of 3)

This is the last of 3 posts dealing with JavaScript Fundamentals from Brad Traversy‘s Modern JavaScript From the Beginning course on Udemy. It compares the course with Lambda material, from the pre-course and the full-stack developer track. (See part 1 here and part 2 here.)

If Statements & Comparison Operators

This lesson looks at if statements, if/else statements and comparison operators. It explains that if statements are use to evaluate a condition and then do something based on that condition, or do something else if the condition isn’t met.

I think that everyone who’s ever looked at a program is familiar with the concept of an if statement, and many have seen other versions of it, like in a flowchart or when learning about logic.

Immediately after introducing the concept of an if statement, the lesson moves into the equal comparison operator (==) and its difference with the assignment operator (=). It then uses both of these to give an example of an if statement by setting a const equal to a number (=) and then writing an if statement that opens by checking if a variable has the same value as that number (==) and console.logs text if it is true. The code is then expanded with an else conditional that console.logs different text if the value is not a match.

Once that’s done, the if statement is reversed by adding a “not” to the equal sign in the form of an exclamation point – so not equal looks like “!=”. I remember my first TL, Reed, showing this to us during JavaScript Fundamentals at Lambda. He said that the convention is to call it a “bang”. So not equal is spelled with a bang and an equal sign. After our group stand-up sessions, he’d often host JavaScript challenges, in which he’d grab problems from Edabit or another site and we’d work on them as a group. I remember him using the bang on several other occasions to reverse entire blocks of logic in certain conditional statements.

With the comparison and assignment operators under our belts, the lesson introduces the third little pig in the form of “===”. So, two equal signs compares the values of two things to see if they’re the same. In the example, the number 100 and the string “100” are equivalent, so they’re a match. However there are times in which the value AND the type need to be the same. This is supposed to help reduce errors and the possibility of bugs, down the road. For this, we need the three equal signs, which compares both value and type. In this case, 100 and “100” are not the same.

Naturally, there are “not” versions of these as well, in she shape of “!=” and “!==”.

The assignment operator (=) and the comparison operator (==) have both been thorns in my side in the past. There have been at least 3 separate occasions in which I’ve written if statements, accidentally used an “=” in the comparison, and not triggered else statements in my code. On two of these occasions, TLs who reviewed my code (first Reed, and then Angel, my 2nd TL, a while later on a different project) discovered my error, and I vowed not to repeat it again, until it craftily happened one more time.

Lambda went over comparison operators during the pre-course. I remember seeing “>”, “<“, “>=”, “<=”, “===”, “!==” and “!”. They cautioned against using the double equal sign, citing its use as a bad practice because it doesn’t compare type, only value. The convention at Lambda is to use the triple equal sign. They also continued from there to go over logical operators, including “&&” (and) and “||” (or).

Ok. Next, the lesson showed something I don’t think I’ve seen before – it tested the value of a variable, returning its value if it was set, and returning a different message if it wasn’t. When tested with “if(variable)” the result was that the value was console.logged. However, when tested after commenting out the variable, the result wasn’t the other message – it was an error that the variable was undefined.

The correct way to test, and avoid the undefined error, is to use logic like:

if(typeof variable !== 'undefined') {
  [do something]
} else {
  [do something else];
}

So, this apparently checks first, to make sure that the variable exists, before it runs code that executes based on the value of the variable.

Further tests checked against greater than (>), less than (<), greater than or equal to (>=) and less than or equal to (<=). The lesson then moved on to if/else.

If/else differs from if in a significant way – its not just that a response can be provided if an initial condition isn’t met – its that it can test for additional conditions.

const bassist = "Alex Webster";

if(bassist === 'Alex Webster'){
  console.log('Spector Alex Webster Signature Edition');
} else if(bassist === 'Steve DiGiorgio'){
  console.log('Fretless Ibanez BTB1605E');
} else if(bassist === 'Jeroen Thesseling'){
  console.log('Fretless Warwick Thumb NT 7-string');
} else {
  console.log('Bassist and equipment are unknown.');
}

With if/else under our belts, the lesson moved on to logical operators, starting with using the && (and) operator to include two different conditions before executing a result. For example:

if(temperature > 65 && temperature < 80){
  console.log('Its a comfortable day, outside.');
} else if(temperature >=50 && temperature <=64){
  console.log('Its chilly, outside.');
} else {
  console.log('The temperature is crazy for this time of year!');
}

Next came the || (or) operator. The difference between this and && is that && checks to see if each condition its testing is true before executing a code block. || will execute if any included condition is true – exactly like truth tables, back in junior high school math.

The ternary operator followed – its essentially a single-line method of writing an if/else statement. During JavaScript Fundamentals, Reed showed this to our group, and one other person who had been to another coding bootcamp also knew it, but it was new to the rest of us. Lambda officially showed it to us later on in the curriculum, during the first lesson of Intro to React, when we started exploring conditional rendering.

One important tidbit, for me, is that when using React, we can’t use if statements in JSX, which is the HTML-equivalent embedded into React that’s used to render output to the screen. It threw me for a loop for the longest time when working on v3 of my portfolio. However, we can use ternary operators in place of if/else, and if we have more than one condition to test against, we can use switch statements, which are covered in the next lesson in Modern JS, but were covered much later at Lambda.

Finally, we’re shown that in JavaScript, we actually don’t need to surround blocks of code in curly braces in an if statement. I never knew this! Its recommended that we use them anyway, but the video gives us an example of an if/else statement without curly braces, and it executes properly.

2-12 if-else and conditionals
Conditional operators

Switches

Switch statements are another type of conditional, and can be used in lieu of if/else statements. This is what our if/else statement from above would look like as a switch statement:

const bassist = "Alex Webster";

switch(bassist){
  case 'Alex Webster': 
    console.log('Spector Alex Webster Signature Edition');
    break;
  case 'Steve DiGiorgio':
    console.log('Fretless Ibanez BTB1605E');
    break;
  case 'Jeroen Thesseling':
    console.log('Fretless Warwick Thumb NT 7-string');
    break;
  default:
    console.log('Bassist and equipment are unknown.');
    break;
}

Modern JS recommends using switches instead of if/else statements if there are many conditions to check. I used them in v3 of my portfolio in React/JSX because if statements can’t be used in JSX (it has something to do with evaluating down to HTML, but I can’t remember the specifics. I’ll post about it when I finish refactoring my portfolio).

Lambda went over these sometime during React, but I was already behind and looking to flex to another unit, so I didn’t get to write about any of that yet, and don’t remember exactly when it was introduced. It must have been in Advanced React, Advanced State Management or Advanced Web Applications though.

2-13 switches
Switch statements

Function Declarations & Expressions

Functions are blocks of code that can be created and called at a later time, or sometimes, executed immediately. They’re like little programs inside of a program that generally do one specific thing. This lesson goes over several kinds:

  1. Function declarations
  2. Function expressions
  3. Immediately invocable function expression (pronounced iffy)
  4. Property methods

Function declarations define a function so it can be called for use later. Generally, these functions return something that can be used outside of the function, via the “return” statement.

function jaco(){
  return 'Jaco only needed four strings!';
}

console.log(jaco()); //calls the function and console.logs its output

Functions can take variables (arguments) when they’re called and use them. If they specify arguments, like if the above example started with “function jaco(name)” then it would expect a name to be passed in. If one weren’t, it would output “undefined” where that argument would have been used, like if the body returned:

return "Jaco only needed four strings, " + name + "!";

One new thing I learned from watching this lesson is how to set default values for functions, so that if no arguments are passed into a function, it still outputs something other than “undefined” where data was missing. The old way looked something like this:

function jaco(name){
  if(typeof name === "undefined"){name = 'Wooten'};
  return "Jaco only needed four strings, " + name + "!";
}

console.log(jaco());

If data is passed in, like “console.log(jaco(‘Jackson’));” then that data overwrites “Wooten” and is used instead.

With ES6, we now have a cleaner way to set default values for a function. We simply include the values directly in the function declaration, like this (and we can rewrite the return using string literals, too!):

function jaco(name = 'Wooten'){
  return `Jaco only needed four strings, ${name}!`;
}

A function expression assigns a function to a variable. They can be named or anonymous, but are usually anonymous. In both cases (declaring  a function or using a function expression) if more than one default value needs to be set, they can be separated using commas (firstName = ‘Anthony’, lastName = ‘Jackson’).

const jaco = function(name = 'Wooten'){
  return `Jaco only needed four strings, ${name}!`;
};

console.log(jaco('Jackson'));

Using function expressions and declaring functions don’t make a huge difference initially. Later on, when dealing with more advanced topics like hoisting and clojures, then favoring one over the other can make a difference.

An Immediately Invocable Function Expression (IIFE) is a function that’s declared and run at the same time. To do this, we turn it into an expression by placing it inside of parenthesis. We also have to remember to end it with a trailing set of parenthesis, which is a format requirement for all functions, like this:

(function(name='Wooten'){
  console.log(`Jaco only needed four strings, ${name}!`);
})('Jackson');

Note the default argument value of “Wooten”, that the entire function is inside of a pair of parenthesis, and that the name “Jackson” is being passed to the function in its parenthesis. Modern JS says that IIFEs are useful in certain design patterns, like the module design pattern. That’s a topic that hasn’t been covered yet, where I am in the curriculum at Lambda and looks like it will be addressed in Modern JS in chapter 11.

Finally, functions can be included inside of objects, instead of in the global scope – something we saw briefly when we looked at object literals. When a function is inside of an object, its called a method (hence, array methods, object methods, string methods, etc.).

const humanEraDeath {
  guitarVox: 'Chuck Schuldiner',
  guitar: 'Paul Masvidal',
  bass: 'Steve DiGiorgio',
  drums: 'Sean Reinert'
  newMember: function(role, name){
    console.log(role, name);
}

humanEraDeath.newMember('Gene Hoglan', 'drums');

The above would simply console.log a new member of the band Death – but in this case, we’re not updating the object because the newMember method wasn’t written to do so, since the lineup during the Human album is already presented, and because Gene Hoglan played drums on the next album, Individual Thought Patterns, not on Human.

We can also see that to call newMember, we have to do so from the humanEraDeath object, because its a method inside of that object. Oh, and additional methods can be added to the object from outside of the object by declaring them using dot notation, like this:

humanEraDeath.additionalInfo = function(year=1991, label='Relativity Records'){
  console.log(`Released: ${year} by ${label}`);
}

The Lambda pre-course had several sections dedicated to functions, and the main web developer course also went further into them. This lesson from Modern JS touched on declaring and calling functions, but didn’t dive into many of their other properties. I’m certain that subsequent lessons will explore this though.

Some of what the Lambda pre-course covered includes anatomy of a function, passing data into a function, parameters, arguments, scope and the return statement. In the web developer course, JavaScript Fundamentals then added on arrow functions (including when not to use them), hoisting, anonymous functions, closure and callback functions. This will probably come later in Modern JS.

2-14 functions
Functions and methods

General Loops

This lesson focuses on loops and iteration. Modern JS describes a loop as a specific instruction that repeats until a condition is reached. It then tells us that the three most common loops are the for loop, while loop and the do while loop. They’re present in most programming languages. The lesson will also look at array-specific iteration with .forEach and .map, and the for/in statement, which is used to iterate through objects to get key/value pairs.

We get an example of a for loop, which is something that was also available in the Lambda pre-course. Two interesting bits that weren’t in the Lambda material are the ability for the loop to do something different for a specific pass, and then breaking out of the loop.

The first was illustrated by creating a loop that console.logs the numbers 0-9. However, when it loops through 2, it console.logs something else through an if statement that uses the === operator to determine if its reached a specific point in the loop. Then, it returns to looping, as normal.

While doing this, it also console.logged 2, so it ran the if statement in addition to its usual output. By adding a “continue” statement, it skips that iteration of its regular loop and then continues on with 3. Its almost like an abridged “break” statement in that it stops the current loop and continues on, instead of stopping a function and exiting.

The other interesting bit is actually the “break” statement, which causes the loop to stop and exit. It was also included in an if statement that uses the === operator to stop at a specific iteration and leave the loop.

Next comes the while loop. A general piece of advice we’re given is to use a for loop when we know how many iterations the loop will go through, and to use a while loop when its unclear how many times a loop will need to repeat. My understanding is that a for loop runs for a specific count. A while loop runs until a specific condition is met.

let i = 0;

while(i < 100){
  console.log(`The count is ${i}`);
i++
}

The do while loop differs from the while loop in that it will always run once, no matter what. A while loop might never run, if the condition to make it go isn’t present. From what I can see, this is due to the structure of the loop. The while loop starts by checking if a condition is met before it begins. Then it performs an action and increments its count. The do while loop, on the other hand, starts by performing an action, then increments its count, and lastly checks a condition to see if it should continue.

let i = 11

do {
  console.log(`The count is ${i}`);
  i++
}
while(i < 10);

To close out the section, we look at array methods like .forEach and .map, which were also two of the first methods we learned at Lambda and the for/in loop, which is generally used with objects, to get data from key/value pairs. I know I’ve seen the for/in loop before, and I think I recall my original TL talking about it during a group standup, but I can’t remember if it was in the Lambda materials or if I came across it from an outside source while working on a project at Lambda.

2-15 loops

A Look At The Window Object

When dealing with web development, the window (or browser) is the global environment. According to JavaScript.info, the global object provides variables and functions that are available throughout a program. In the browser, the name for the global object is “window”.

Modern JS shows us that if we type “window” in the console in the Chrome developer tools, we see an object called “window” that has dozens of methods, properties and objects (including “document” which is the heart of the DOM). Its basically everything that’s available to us in the browser. When we render web pages, its really the window object that’s performing all of the tasks needed to do anything onscreen.

The pre-course makes no mention of it, but I remember being introduced to the document object and the window object when we started DOM manipulation at Lambda. It was overwhelming, the sheer number of properties and methods, and objects that had their own methods, that were available for use and for informational purposes. All of JavaScript is embedded in the global environment. Seeing it was like realizing that I was one out of billions of people on the earth, or that the earth was only a speck of dust in the cosmos. For purposes of rendering web pages and DOM manipulation, we were only concerned with a small subsection of what was available, but we were also encouraged to visit MDN for more information about the rest of the document and global environment.

After JavaScript Language Fundamentals, the next part of the Modern JS course deals with DOM manipulation and is likely akin to the Lambda curriculum. Lambda’s pre-course doesn’t have an introduction to this part of JavaScript. I’m up in the air about whether or not it should, because on the one hand, its a somewhat advanced topic, but on the other, its a key piece of web development technology. Maybe the idea of it should be included in the pre-course, just to put it in the back of new students’ minds that this is even a concept. Regardless, here’s some of what Modern JS went over in this lesson:

Some window methods:

  • .alert (produces a popup in the browser with a provided message)
  • .prompt (like .alert, but takes an input, which is a user-typed string)
  • .confirm (like alert, but with buttons to accept or reject onscreen prompt)

Some window properties:

  • .outerheight (gives height of whole browser)
  • .outerwidth (gives width of whole browser)
  • innerheight (gives height of window, including scrollable area)
  • .innerwidth (gives width of window, including scrollable area)
  • .scrollY (shows where user is on the page with regard to scrolling vertically – good for triggering animations as specific points)
  • .scrollX (like .scrollY, but horizontal)

Some window objects and their methods:

  • .location (gives information about the current page/URL)
    • .hostname
    • .port
    • .href
    • .search
    • .reload()
  • .history (returns the browsing history, can be used to go to visited URLs)
    • .go()
    • .length
  • .navigator (returns information about the browser program)
    • .appName
    • .appVersion
    • .userAgent
    • .platform
    • .vendor
    • .language
2-16 document object
Methods of the Document object

Block Scope With let & const

At last! The final video in JavaScript Language Fundamentals! It took a while to get here, as I watched this unit twice – once when I was initially going through it, and a 2nd time, on 1.5 speed, when I got the bright idea to blog about it and try and compare it to what we’ve covered at Lambda. So, I’ve effectively turned a 21-hour course into something like a 36-hour one. Yay…

I am excited to get to the DOM section though.

Anyway, block scope with let and const – scope is a topic that was covered at Lambda in both the pre-course and again, during the main web developer curriculum. Modern JS introduces it here, and it might get looked at again later on – we’ll learn that as we go through.

The gist of it is this. There are three variable types in JavaScript: var, let and const.

  • var is the original way of declaring a variable, and literally means “variable”. It has global scope, which means that a variable declared using var is the same variable throughout the program, except if the name is used again inside of a function, which has its own scope.
  • let is a little more restricted. It has block-level scope, which means that even in the global scope, if a “block” of code is created, like an if statement, for example, variables declared inside of that block of code using “let” are not the same as variables with the same name declared in the global scope.
  • const, like let, has block-level scope, in addition to not being directly alterable.

Global scope vs block-level scope looks like this:

Example 1:

//Global Scope
//Human-era lineup
var bassist = 'Steve DiGiorgio';
let drummer = 'Sean Reinert';
const guitarist = 'Paul Masvidal';
const guitarVox = 'Chuck Schuldiner';

console.log('Human lineup: ', bassist, drummer, guitarist, guitarVox);

These variables are all in the global scope. They’re not inside of a function or block of code. There’s a var, let and a const. Output:

Human lineup: Steve DiGiorgio, Sean Reinert, Paul Masvidal, 
  Chuck Schuldiner

Example 2:

//Global Scope
//Human-era lineup
var bassist = 'Steve DiGiorgio';
let drummer = 'Sean Reinert';
const guitarist = 'Paul Masvidal';
const guitarVox = 'Chuck Schuldiner';

function symbolic(){
  var bassist = 'Kelly Conlon';
  let drummer = 'Gene Hoglan';
  const guitarist = 'Bobby Koelble';
  const guitarVox = 'Chuck Schuldiner'; 

  console.log('Symbolic lineup: ', 
    bassist, drummer, guitarist, guitarVox);
}

symbolic();
console.log('Human lineup: ', bassist, drummer, guitarist, guitarVox);

The global scope variables are still there. A function has been added. Functions have function-level scope, so even if variables in a function have the same name as variables from the global scope, they’re not the same variables. Output:

Symbolic lineup: Kelly Conlon, Gene Hoglan, Bobby Koelble, 
  Chuck Schuldiner
Human lineup: Steve Digiorgio, Sean Reinert, Paul Masvidal, 
  Chuck Schuldiner

Note that even though the variable names are the same (bassist, drummer, guitarist, guitarVox) the output is different. The bassist, drummer and guitarist changed between Human and Symbolic. Even though some of these variables are “const” or fixed/unchanging and have the same name, they’re different variables based on scope. Variables inside a function are not the same as variables with the same name that are outside of a function (in this case, in the global scope).

Example 3:

//Global Scope
//Human-era lineup
var bassist = 'Steve DiGiorgio';
let drummer = 'Sean Reinert';
const guitarist = 'Paul Masvidal';
const guitarVox = 'Chuck Schuldiner';

function symbolic(){
  var bassist = 'Kelly Conlon';
  let drummer = 'Gene Hoglan';
  const guitarist = 'Bobby Koelble';
  const guitarist = 'Chuck Schuldiner';  

  console.log('Symbolic lineup: ', 
    bassist, drummer, guitarist, guitarVox);
}

if(true){
  var bassist = 'Scott Clendenin';
  let drummer = 'Richard Christy';
  const guitarist = 'Shannon Hamm';
  const guitarVox = 'Chuck Schuldiner';

  console.log('The Sound of Perseverance lineup: ', 
    bassist, drummer, guitarist, guitarVox);
}

symbolic();
console.log('Human lineup: ', bassist, drummer, guitarist, guitarVox);

Ok. We’ve added an “if” statement in the main body of the code (not in a function) and set its value to true, so it’ll just execute. In this final example, output will run in this order:

  1. If statement (block-level scope, The Sound of Perseverance album)
  2. Function (function-level scope, Symbolic album)
  3. Global (global-level scope, Human album)

Our output would look like this:

The Sound of Perseverance lineup: Scott Clendenin, Richard Christy, 
  Shannon Hamm, Chuck Schuldiner
Symbolic lineup: Kelly Conlon, Gene Hoglan, Bobby Koelble, 
  Chuck Schuldiner
Human lineup: Scott Clendenin, Sean Reinert, Paul Masvidal, 
  Chuck Schuldiner

What we’re noting here is that in the Human-era lineup, Steve Digiorgio has been changed to Scott Clendenin. Why is this? Its because that “if” statement is a code block and let and const have block-level scope, so any variables declared inside of that code block using let or const are only available inside of the block. Var, on the other hand has global scope. A variable declared in a block of code using var is the same as a variable declared globally. The only exception, of course, is a variable declared in a function.

In this case, “bassist” is declared as a var, so the “bassist” variable inside of the “if” statement is the same as the one declared globally, at the start of the code. So, we get the wrong bassist for the Human album. If “bassist” was declared as a const, it would have given us an error, because we can’t change the value of a const.

2-17 block scope
Block-level scope with let & var

Final thoughts

I’ve come across questions online about learning to code via online tutorials like those found on Udemy or even freely available on YouTube or elsewhere vs learning at a bootcamp – and also all of those vs getting a computer science degree from a school. These were questions that I’ve wondered about, as well. Ultimately, I decided to go with a bootcamp (Lambda School) because of the structure of the classes, the network available for help and accountability, and the resources available for career coaching – resume help, portfolio help, general counsel regarding job searches, etc. Lambda’s ISA (Income Share Agreement) was the deciding factor in my going with them, plus their curriculum seemed more in-depth that many other bootcamps I looked at.

Since going through HTML/CSS, JavaScript, React and parts of Redux and other things at Lambda, my discovery (which might only apply to myself, and not necessarily anyone else – maybe its a block-level thought then, not a global one) is that it IS possible to self-teach coding using resources available online, but that process would be difficult and time-consuming for those who are not strongly self-driven and who have any issues with adequacy or self-esteem. This is taking into account that its a difficult process even before going it alone.

That said, I switched from full-time to part-time at Lambda, and even now, I’m on a 6-week hiatus from part-time while I go through JavaScript and React materials myself, before my (hopefully) triumphant return to the fold. Learning at someone else’s pace – in this case the cohort’s pace – is not the same as learning at your own pace. Udemy courses, books, websites – going through materials delivered in these formats allows us to progress at a comfortable pace. We can review material at our discretion. There’s less time-driven stress than that which comes with trying to keep up with a coding bootcamp (and possibly a school). The stresses are still real though, and staying motivated can also become a bigger issue in solitary confinement.

My balance, so far, has been to take time off in-between large units at Lambda, to use what I’ve learned and review material that I’m not as strong with. We’re not allowed to take a hiatus more than once, so this will be my sole one. We can, however, stretch time before returning, if we flex to a new cohort, which I did the first time I flexed.

Lambda is something like shock therapy to me. The pace and the deluge of projects and exercises takes me out of my comfort zone and forces me to try to learn and absorb information. Backing away from it to practicing what I’ve been exposed to, and making use of outside resources like this course from Brad Traversy, is the counterbalance. It lets me methodically take apart a concept, analyze it and learn in a more controlled manner. I’m not young anymore, and I think I’m now something of a slow learner, so these breaks are vital to me, for really driving home new concepts.

For people like myself, I don’t think there’s a single path to learning. I think that using complimentary resources to advance is a strong option. I really admire people who are able to absorb and use this material with their first pass, but ultimately, its not a race. Its really about building proficiency. I’m happy to be alive in an age in which all of this is even an option. When I graduated high school, in the early 1990s, bootcamps weren’t a thing. The internet wasn’t anything like it is today, college computer science degrees taught COBOL and Fortran and I didn’t have a clear idea of how to learn what I needed to become a programmer. I wanted to write games for Sega. There was no roadmap to that. Schools still looked down on gaming as a waste of time. Now, the world is a different place. Gaming is the largest money-maker in the entertainment industry, and I actually don’t want to be a game programmer anymore. I want to build web applications, and I want to further causes that I align with.

Anyway, my big takeaway is that all of these resources are a blessing. Try and determine a path forward using them, if you’re interested in web development. Talk to people online, and to any programmers you might know in real life. Last year, I reached out to people on Reddit and got good advice, in spite of the site’s sometimes troubling reputation. Try out front-end and back-end coding, to see what you like. You might surprise yourself and favor one over the other, or you might actually find that you enjoy building projects from soup-to-nuts.

There’s a lot to be said about the job market, domestically and internationally, but my perception is that its growing, and that there are programmers who are capable and have foresight and experience, and there are those who are less proficient or who have stagnated. There’s room for more of us. The field is expanding. There are sub-fields still waiting to be created (I work in a field that didn’t exist when my parents were born). Thank to Lambda for showing me that this is even possible, and for creating a model that makes it available to a large swath of people who want to learn to code and become developers; and thanks to Brad Traversy for proving that people can overcome overwhelming adversity in life and become empowering figures who help to guide others through their learning and experiences.

I hope we all succeed.

This post should have been two posts. I need to plan a little more in the future.

Ok. I’m going to work through the DOM material next.

One thought on “Modern JavaScript From The Beginning: Section 2 – JavaScript Language Fundamentals (3 of 3)

Leave a comment