The Complete Node / The Complete Guide | Captain's Log -> Table of Contents:
In some instances, there was a need to take a tangent with the "Node" course and elaborate on some core concepts. You'll see those "tangents" below...
A) Class, Instance, Object and Everything Else in Between
B) function __construct
A) Functions
1) Named Functions vs Anonymous Asynchronous
2) Anonymous Functions Written in ES6
B) Callback
1) Asynchronous
2) Basic Example
3) Callback Using Function Expression Rather than the Function
4) MongoDB Connection Callback
C) Expressions vs Functions
D) Hoisting
E) Helper Function
F) Spread Operator
G) Using Spread Operator to Concatenate Arrays
H) findIndex
I) Using Spread Operator to Replace a Specific Value in an Array
J) Error Messages
1) Uncaught...
2) Throw
K) JavaScript Objects
❶ <?php class Drumset {
❷ public $snare;
public $kick;
public $hihat;
❸ public function __construct($placeholder_1, $placeholder_2, $placeholder_3)
{
❹ $this->snare=$placeholder_1;
$this->kick=$placeholder_2;
$this->hihat=$placeholder_3;
}
public function hit_me() {
return $this->snare;
}
}
❻ $kit = new Drumset("piccolo", "24 inch", "Sabian");
❼ $set=$kit->hit_me();
❽ echo $set;
?>
piccolo
Now, let's break this down so we're clear on Classes, Objects and Instances.
The double arrow operator, =>, is used as an access mechanism for arrays. This means that what is on the left side of it will have a corresponding value of what is on the right side of it in array context. This can be used to set values of any acceptable type into a corresponding index of an array. The index can be associative (string based) or numeric.
$myArray = array(
0 => 'Big',
1 => 'Small',
2 => 'Up',
3 => 'Down'
);
The object operator, ->, is used in object scope to access methods and properties of an object. It’s meaning is to say that what is on the right of the operator is a member of the object instantiated into the variable on the left side of the operator. Instantiated is the key term here.
// Create a new instance of MyObject into $obj
$obj = new MyObject();
// Set a property in the $obj object called thisProperty
$obj->thisProperty = 'Fred';
// Call a method of the $obj object named getProperty
$obj->getProperty();
① <?php class Drumset { You're setting up a new Class called "Drumset." A Class is generally defined as a blueprint - a magnificent collection of digital ideas and processes that are poised to create something wonderful.
② public $snare... With a Class, you have the option of setting up Properties. You can think of Properties the way you would variables with a function. From that standpoint, you could say that variables within a Class are called Properties the way functions within a Class are called Methods.
Properties are simply placeholders. You have to assign them values. Think of them like empty columns on a spreadsheet. When you create Properties, you're creating a column in a spreadsheet and giving it a specific name.
③ public function __construct($placeholder_1, $placeholder_2, $placeholder_3) Here's where you're giving your Properties some values using what's called a construct.
④ $this is what's referred to as a psuedo-variable. It's a handy way of qualifying something as belonging to whatever it is you're currently working with. In this case, when you say $this->snare, you're referring to the "$snare" property that you created a few lines ago.
You might be wondering, "Why use $this at all? Why wouldn't you just say, "$snare" and be done with it?" The reason is because if you were to say:
$snare=$placeholder_1 rather than $this->snare=$placeholder_1, your code would break (it would come back as an "undefined variable." $snare by itself wouldn't make sense within the public function __constructfunction because $snare doesn't exist - at least not in the mind of the public function __construct function. It has no idea what you're talking about. But when you use $this, now it knows to be looking beyond itself and look for a $snare property within the Class it belongs to.
And if you're wondering what -> is, it's called an "object operator." You can read more about it in the text box to the right.
⑤ public function hit_me() { is a method within the Drumset class. It's going to return the $this->snare property's value. That value is going to be passed into the Class at the time of it being instantiated, which we'll get to in a moment.
The "public" dynamic is definining the method's "visibility." In short, "visibility" is referring to the extent to which that method can be seen by other parts of your code. Sometimes you want to keep certain functions restricted to whatever Class they're associated with. Other times, you want to be able to make that method available to your entire codebase. "Public" says it is accessible to the general public. For more info, you can click here.
⑥ $kit = new Drumset("piccolo", "24 inch", "Sabian"); "$kit" is you "activating" the Drumset class. Prior to you activating it, you can think of it as a greyed-out button. The functionality is there, but it's dormant right up to the point where you make it active. Making it active is called "instantiation" and you're doing that by creating an object. In many ways, the term is very appropriate given the way a class is often defined as a blueprint. You're now creating an "object" with that blueprint.
In your code, you're going to have lots of "objects." What makes those objects unique and / or distinctive is the Class that they reference. That's why when you refer to an Object, you say that they represent an instance of a particular Class.
⑦ $set=$kit->hit_me(); "$set" is nothing more than a variable. It's a digital placeholder that contains the result of a piece of the functionality coming from the $kit object which is an instance of the Drumset class.
For the sake of even more reinforcement, here's a breakdown of the above code from Experts Exchange:
1. Line 20: You create a new Drumset and pass the string "piccolo" in as the first parameter.
2. Line 7: In the Drumset constructor, a new variable called $placeholder_1 is created and it is assigned a value of the string "piccolo"
3. Line 9: The value of $placeholder_1 (the string "piccolo") is retrieved.
4. Line 9: The "piccolo" string value is then copied into the $this->snare class property.
5. Line 21 and 15: You call the hit_me() class method on the $kit instance, which looks at the $this->snare class property and sees that it contains a string, so it makes a copy of that string and returns that copy of the string to whatever called the function/method.
6. Line 21: . Back to line 21, the copy of the "piccolo" string has now been returned, so it now assigns it to a new variable called $set.
B) function __construct (back to top...)
<?php
class Bootcamp {
function __construct($name, $rank) {
$this->name = $name;
$this->rank = $rank;
echo $this->name.' '.$this-> rank;
}
}
$recruit = new Bootcamp("Pearson", "PFC");
?>
This code would result in "Pearson PFC." That's by simply invoking the Class. The "__construct" happens automatically.
A) Functions (back to top...)
1) Named Functions vs Anonymous Functions (back to top...)
Here's a basic function written as a "named" function:
function lidiexy(products) {
console.log(products);
}
lidiexy(4);
Easy! We've got a basic function where we're passing in a variable called, "products" and we're writing that to your console.
We can write the same function like this, only as an "anonymous" function:
lidiexy = function(products) {
console.log(products);
}
lidiexy(4);
For more information on why you would want to use an anonymous function versus a named function, click here. For more detailed info about expressions vs declarations etc, click here.
An anonymous function is a function without a name. It has several different possible uses, but we're only going to focus on one kind for the sake of this discussion. If you want to learn more, refer to the textbox to the right.
There's really not a whole lot of difference between the two, especially with the way you're invoking the function. With one you're using the name of the function, with the anonymous version, you're using the variable that you used to store what amouts to the function expression.
What is a "function expression?" Good question. We're going to cover that in a minute. Let's take a look at how we're going to write an anonymous function using ES6.
2) Anonymous Functions Written in ES6 (back to top...)
Now, let's take a look at how anonymous functions are written in ES6.
First, let's establish some absolutes where terminology is concerned:
In addition to what you see above...- function declaration - it's the actual word, "function." As in function lidiexy.... That's a function declaration.
- function body - although this is the way things are defined in the graphic above, the "function body" is further defined in the context of whether or not it's a named function or it's an anonymous function.
- function statement - If it's a named function, the "function body" is referred to as a "statement."
- function expression - it's the "guts" of a function that doesn't start with the word, "function." Anonymous functions would be the most obvious example of that. Whereas the "guts" of a named function is referred to as a "statement," the "guts" of an anonymous function is called an "expression."
However tempting it may be to confuse "products" as a "name" rather than a parameter, don't give in to that temptation. "lidiexy" is the variable that we're using to invoke the anonymous function and "products" is our parameter. Click here for more info.
Furthermore, everything from "products" on is the "expression" of that function. That's what we talked about just a moment ago. If you wanted to document just the expression, it would look like this:
products => {
console.log(products);
}
Hang on to that thought, because we're going to come back to that in a minute.
B) Callback (back to top...)
Synchronous - on the other hand, means that each photo will be done in turn. It will finish one upload before it moves to the next. All the uploads will be done, but they won't be done all at once and it will take a while.Callback - this is Javascript's way of being able go back to a particular function and run it in its entirety. To go back to our photo uploads, a callback is going to go back and make sure that a previous photo was completely uploaded.
1) Asynchronous (back to top...)
In order to appreciate what a Callback is and why it's so useful, let's go back and rehearse how Javascript processes the code you write.
Imagine a situation where you're uploading a bunch of pictures and envision how each one of those photos generates a progress bar so you can see the status of each photo and the extent to which the uploading process is complete.
Javascript is just like that. It doesn't wait for the first picture to finish before it starts working on the second. This is a good thing when you're uploading photos and it can be a good thing as well for coding. It can be a problem with your application's syntax, however, if your second function needs something from the first function in order to do its job. Now you're in a bind and your page is going to throw an "undefined "error because it went looking for something that was to be created by a process that wasn't finished by the time that something was supposed to be in place.
2) Basic Example (back to top...)
Let's take a look at how this works using some really basic examples.
First of all, in order to mimic that scenario where you have a function that's going to take a bit longer than usual, we're going to use the "setTimeout" function in Javascript. That will give us the necessary "drag" that we need in order to illustrate how a Callback can be a real help.
Here's a scenario that will need a callback in order to get the sequence we're looking for. We're using named funcitons and documenting them using an ES6 format.
let michelle = car => {
console.log(car);
}
const drag = smith => {
setTimeout(function() {
console.log(smith);
}, 200);
}
drag("franklin");
michelle("enclave");
If we run this, we'll get:
enclave
franklin
...in our console. Despite the fact that we positioned drag("franklin") first in our code, because it has the "timeout" dynamic attached to it, it doesn't show up until after michelle
If we want to dictate the sequence in which this code fires, then you have to use a callback and you'll do that like this:
let michelle = car => {
console.log(car);
}
const drag = (smith, cb) => {
setTimeout(function() {
console.log(smith);
cb("enclave");
}, 200);
}
drag("franklin", michelle);
We start with drag. That's the function that is going to fire last if we leave things as they are. We call that first and pass into that function the "franklin" variable and then we follow that with the name of the function we want to fire after drag has completed which, in this case, is michelle.
The actual code for drag is changed in that we're now accepting the "smith" variable as well as what the system is going to understand as callback function represented by "cb."
We put the cb("enclave") code immediately after the console.log(smith) syntax and we're gold! We get:
franklin
enclave
3) Callback Using Function Expression Rather than the Function (back to top...)
Now, if we were to change things up a bit and instead of passing michelle in as an argument, we're going to pass the expression as an argument instead.
Remember, that the "expression" is the "guts" of an anonymous function which, in this case, is michelle. So, that's going to look like this:
/*let michelle = car => {
console.log(car);
}
*/
const drag = (smith, cb) => {
setTimeout(function() {
console.log(smith);
cb("enclave");
}, 200);
}
drag("franklin", car => {
console.log(car);
}
);
Bottom line:
It's the exact same syntax with the exception of what's in bold. Instead of passing in michelle in as an argument, we passed in the function expression associated with michelle and we get the same result!
That's what we did in our project's fetchAll function, remember?
exports.getProducts = (req, res, next) => {
Product.fetchAll(products => {
res.render('shop', {
prods: products,
pageTitle: 'Shop',
path: '/',
hasProducts: products.length > 0,
activeShop: true,
productCSS: true
});
});
}
So, fetchAll() looks like this:
static fetchAll(cb) {
getProductsFromFile(cb);
}
So, your "cb" is "products" and that's being passed into getProductsFromFile(cb)
const getProductsFromFile = cb => {
fs.readFile(p, (err, fileContent) => {
if (err) {
return cb([]);
}
cb(JSON.parse(fileContent));
});
};
Again, a stripped down version of what we did would look something like this:
- Callbacks in JavaScript are functions that are passed as arguments to other functions.
- Callbacks enforce the order of how a particular piece of syntax operates
- You will hear people refer to a function as a "callback" if it's something that will obviously take a moment to finish.
function david(cb) {
❷ cb("george")
}
david(❶ products=> {
console.log(products);
});
database.js (exploded view)
- const mongodb = require("mongodb");
- const MongoClient = mongodb.MongoClient;
- const mongoConnect = callback => {
- MongoClient.connect(
- "mongodb+srv://brucegust:Mu5cular!@brucegust-qhxnz.mongodb.net/test?retryWrites=true"
- )
- .then(client => {
- console.log("Connected");
- callback(client);
- })
- .catch(err => {
- console.log(err);
- });
- };
- mongoConnect(client => {
- console.log(client);
- app.listen(3000);
- });
broken down version
- const drag = callback => {
- callback("arlington");
- }
- drag(michelle => {
- console.log(michelle);
- });
The ".then" block of a Promise is going to receive the result of your callback, whatever that result may be. In this case, it's going to be a successful completion to the database. Click here for more info.
Here's what you have...
"mongoClient" is a constant that "houses" the functionality documented on lines 4-15. We trigger that functionality by referencing the mongoConnect constant on line 17. We pass an anonymous function as an argument to the mongoClient function which is going to be represented by the word "callback" which you can see on line four.
The mongoClient function is actually a "promise" which gives us the opportunity to structure an "IF / ELSE" scenario based on the successful completion of a callback. In this case, the callback that we're most interested in is on line 5-6 where we're grabbing the "mongoClient" and connecting to the database. If that callback happens successfuly, we proceed to the "then" block. As per the way "promises" are structured, we have access to the result of the successful callback as a variable which, in this case, we are calling "client." You read more about the way a "promise" works by clicking here.The "client" variable, which is a successful connection to the database, is passed to the callback which is then going to document the details of that connection (line #18) and we're also going to see "connected" in the console thanks to line #9.
C) Expressions vs Functions (back to top...)
In the midst of talking about callbacks you hear references to "expressions" and "functions" being passed as arguments into another function.
That sounds logical, given what we've discussed, but verbiage is important so let's make sure we know what we're talking about.
Expression -> An expression is any valid set of literals, variables, operators, and expressions that evaluates to a single value. For example:
x = 7
7+3
123
George
"123" is an expression because it involves three integers that combine to form one value. The same thing applies to "George" in that you've got a collection of letters combining to form a string. All of what you see below is processed as a single value.
Functions -> Functions are one of the fundamental building blocks in JavaScript. A function is a JavaScript procedure—a set of statements that performs a task or calculates a value. To use a function, you must define it somewhere in the scope from which you wish to call it.
So, whereas an Expression is going to be a value, a Function is going to calculate a value. An Expression is something, a Function does something (although you can attach a function to an expression).
D) Hoisting (back to top...)
Hoisting - something else that's a little unique to Javascript is the way it will look at a function and gather up all of the variables, position them at the top of the function and take attendance real quick. It won't assign values to those variables, but it will do a quick inventory. That whole approach is called "hoisting."
If the organization of your function happens to leave a variable "blank" - in other words, no value is attached to that variable, it will come back as undefined.
For example, this:
(function() {
var foo = 1;
alert(foo + " " + bar + " " + baz);
var bar = 2;
var baz = 3;
})();
bar and baz will come back "undefined." Your app won't necessarily crash, but it won't work.
This, however, will be a complete train wreck:
(function() {
var foo = 1;
alert(foo + " " + bar + " " + baz);
var bar = 2;
})();
baz isn't even on the radar. Now you're going to get a "ReferenceError" and not just an "undefined."
In the first example, the code was able to make some kind of sense of what had been written because of "hoisting." For all intents and purposes, the code did this behind the scenes:
(function() {
var foo;
var bar;
var baz;
foo = 1;
alert(foo + " " + bar + " " + baz);
bar = 2;
baz = 3;
})();
It took an inventory of all three variables and placed them at the top of the stack, so to speak, and went from there. The facdt that you only assigned a variable to foo and left the other two blank resulted in the "undefined" problem, but the code still understood the presence of all three variables because of the way it "hoisted" everything to the top irrespective of their having been assigned a value.
For more information on Hoisting, click here.
E) Helper Function (back to top...)
The "helper" function is pretty simple. It's just a fancy way of describing the introduction of a function that' contains code that would otherwise be repeated over and over. With a "helper" function, you're doing something very smiliar to an "include."
How that looks, however, is a little more involved. Especially when you're doing callbacks.
const getProductsFromFile = cb => {
fs.readFile(p, (err, fileContent) => {
if (err) {
return cb([]);
}
cb(JSON.parse(fileContent));
});
};
static fetchAll(cb) {
getProductsFromFile(cb);
}
To better understand this, here's a scaled back example of a callback where you're passing an expression into another function as an argument:
basic function w/o helper
const bruce = cb => {
console.log("yes");
}
const michelle = bruce(smith => {
console.log(smith);
});
michelle;
same function w/ helper
const david = cb => {
console.log("yes");
}
const bruce = (cb) => {
david(cb);
}
const michelle = bruce(smith => {
console.log(smith);
});
michelle;{products: {…}, totalPrice: 0}
products:
updated_cart:
id: 1
quantity: 2
totalPrice: 0
H) findIndex (back to top...)
You're going to use this code to locate the index of a value within an array.
Just a quick note: You can't just pass a value into this function. It's expecting a function as an argument. That's the only way it will work.
When you're using ES6, you have the option of writing a bunch of code with very little syntax.
Here's an example of the way you would do it with regular JavaScript:
<!DOCTYPE html>
<html>
<body>
<p>Click the button to check get the index of the first element in the array that has a value of 18 or more.</p>
<button onclick="myFunction()">Try it</button>
<p id="demo"></p>
<p><strong>Note:</strong> The findIndex() method is not supported in IE 11 (and earlier versions).</p>
<script>
var ages = [3, 10, 18, 20];
function checkAdult(age) {
return age >= 18;
}
function myFunction() {
document.getElementById("demo").innerHTML = ages.findIndex(checkAdult);
}
</script>
</body>
</html>


