---
slideOptions:
spotlight:
enabled: true
fragments: true
---
<style>
.reveal {
font-size: 28px;
}
</style>
# Javascript gotchas
---
- before we start:
- this talk is going to have lots of examples, which I'll type in a repl.it as we go, to save time. but feel free to try them out afterwards.
- there's a lot of info, but i've tried to make it all digestible. some of you may already be familiar with some of these topics, the point is that hopefully there's a takeaway for everyone.
- this method will come in handy for all your object experiments.
```javascript
console.dir()
```
- dissect your objects, don't just get [object Object] printed out.
- but what is [object Object]?
---
## let's talk about scope
---
- scope is a fancy word describing where your variables exist, and where they can be accessed from within your code.
- kind of like roles in a database, you'll want to limit certain variables so they can only be accessed by the bits of code with the right access privileges
---
# Levels of scope
---
```javascript
//not using var-let-const here because i'll explain those in a sec
variableInGlobalScope=2;
function cool(){
variableinFunctionScope=3;
//this is the simplest form of a block.
//usually a block scope occurs in an if statement or a loop though
{
variableInBlockScope=5
}
}
```
- global scope - the outermost level, variables declared here are accessible anywhere.
- function scope - functions have their own scope, and variables declared within a function can't be accessed outside it.
- block scope - anything grouped by curly brackets. if statements, loops, switch, or you can even create a block just using a pair of brackets by itself.
---
```javascript
var variableOutsideFunction = 2
const enteringFunctionScope = () => {
var variableInsideFunction = 3
var enteringBlockScope = true
if(enteringBlockScope){
var variableInsideBlock = 5
}
console.log({variableInsideFunction})
console.log({variableOutsideFunction})
console.log({variableInsideBlock})
}
console.log("entering function scope")
enteringFunctionScope()
console.log("back to global scope")
console.log({variableOutsideFunction})
console.log({variableInsideFunction})
```
- all var! what happens here? let's try it out.
---
### everything works, except trying to access a function scoped variable outside that function.
---
```javascript
var variableOutsideFunction = 2
const enteringFunctionScope = () => {
var variableInsideFunction = 3
var enteringBlockScope = true
if(enteringBlockScope){
let variableInsideBlock = 5
}
console.log({variableInsideFunction})
console.log({variableOutsideFunction})
console.log({variableInsideBlock})
}
console.log("entering function scope")
enteringFunctionScope()
console.log("back to global scope")
console.log({variableOutsideFunction})
console.log({variableInsideFunction})
```
- the block scope variable has been changed to a let.
- let's see what changes (please dont laugh at this pun)
---
### the variable in a block is no longer accessible outside the block, because let is block scoped.
---
```javascript
let variableOutsideFunction = 2
const enteringFunctionScope = () => {
let variableInsideFunction = 3
let enteringBlockScope = true
if(enteringBlockScope){
let variableInsideBlock = 5
}
console.log({variableInsideFunction})
console.log({variableOutsideFunction})
console.log({variableInsideBlock})
}
console.log("entering function scope")
enteringFunctionScope()
console.log("back to global scope")
console.log({variableOutsideFunction})
console.log({variableInsideFunction})
```
- everything is a let
- what do you think would happen now?
---
### same as before, because apart from inside a block, let and var behave the same
---
## closures
- you will probably get asked what a closure is at some point in your web dev career, and it's one of those things that can be frustratingly difficult to explain under pressure.
- I remember this concept with an example of my own.
---
```javascript
const bigFunction = () => {
let outsideVariable = "abcd"
return smallFunction = () => {
return outsideVariable;
}
}
```
- here we have a function bigFunction that returns another function smallFunction.
- smallFunction itself accesses and returns a variable which is in bigFunction, but outside smallFunction.
---
```javascript
const mySmallFunction=bigFunction();
console.log(mySmallFunction())
```
- here, we're assigning the result of bigFunction to a new variable. since bigFunction returns a function, this new variable will be a function.
- this code translates under the hood to:
```javascript
mySmallFunction=smallFunction
```
---
- which would be the same as if we wrote the code below
```javascript
const mySmallFunction=() => {
return outsideVariable;
}
console.log(mySmallFunction())
```
- It would seem that outsideVariable is an undefined variable, since mySmallFunction is in global scope, and outsideVariable is buried inside a function.
- this would be the case if smallFunction was copied to mySmallFunction with no memory of where it was declared.
---
- But that's where closures come in.
- all functions in javascript remember where they were created/declared, and they remember the variables that were in scope when they were declared.
- this combination of a function and the variables it has access to, is called a closure.
- console.dir(mySmallFunction) and this will become super clear.
---
# let's talk about objects
---
## dot notation vs bracket notation
```javascript
const fac19={
coursefacilitator:"Gregor",
students:"lots of smart people"
}
const vincentvangregor="coursefacilitator"
```
---
**dot notation**
- used for string key names. fac19.coursefacilitator looks for a key with a value of "coursefacilitator"
```javascript
console.log(fac19.coursefacilitator)
```
---
**bracket notation**
- tries to evaluate the value within brackets.
- this means we can use variables with bracket notation
- fac19[vincentvangregor] finds the value of vincentvangregor(which is "coursefacilitator") and then looks for a key with that value.
- can also be used for string key names directly.
```javascript
//these will have the same output
console.log(fac19[vincentvangregor])
console.log(fac19["coursefacilitator"])
```
---
**extra**
this bracket notation for variables can also be used in reverse, for assigning key names!
```javascript
let coursefacilitator = prompt("what should we call gregor?");
const fac19 = {
[coursefacilitator]:"Gregor",
students:"lots of smart people"
}
```
- whatever nickname the user enters for gregor will be his new nickname, and his key in the object.
---
## destructuring, spread and rest operators.
*destructuring*
- copies array elements, or object keys.
- creates separate individual variables.
---
- object destructuring:
```javascript
const cookie={chocochip:true,milk:true,flour:"unlikely"}
let {chocochip,milk,flour} = cookie
```
- creates three separate variables chocochip, milk and flour, and assigns their values from the matching keys of the object "cookie"
```javascript
let {chocochip,..otherStuff}=cookie
```
- ... is the rest operator
- copies milk and flour into a new object called otherStuff.
- can be accessed using otherStuff.milk
---
- array destructuring:
```javascript
let [smallNumber,mediumNumber,bigNumber] = [1,50,2000]
```
- creates three separate variables smallNumber, mediumNumber and bigNumber whose values are 1, 50 and 2000 respectively
```javascript
let [smallNumber,...otherNumbers] = [1,50,2000]
```
- ... is the rest parameter. it creates a new array called otherNumbers and inserts 50 and 2000 as the elements.
- otherNumbers[0] would be 50
---
## spread operator
```javascript
let arrayOfNumbers=[1,2,3,4,5]
console.log(Math.max(...arr))
```
- lets you expand an array into multiple function arguments
```javascript
let array1=[1,2,3,4,5]
let array2=[6,7,8,9]
let newArray = [...arrayOfNumbers,...newArray,10,11,12]
console.log(newArray)
```
- also lets you combine arrays (fill a new array with all the elements of another array)
---
## lets talk about this.
- as a javascript developer, we probably ask "what is this" everyday, but then there's an actual thing called this, and you're like "well what is this this".
- yes, that this.
---
- functions inside an object are called "methods" of that object
```javascript
const courseFacilitator = {
sayHello: function(){
console.log(`Hi i'm Gregor`)
},
name:"Gregor"
};
```
- there is a shorthand notation for methods
```javascript
const courseFacilitator = {}
sayHello(){
console.log(`Hi i'm Gregor`)
},
name: "Gregor"
};
```
---
```javascript
const courseFacilitator = {}
sayHello(){
console.log(`Hi i'm Gregor`)
},
name: "Gregor"
};
```
- we see that sayHello could use the name property, instead of hardcoding gregor, so that for the next cf, only the name property would have to change.
- we can use "this" here to refer to the courseFacilitator object
---
```javascript=
const courseFacilitator = {
sayHello(){
console.log(`Hello i'm ${this.name}`)
},
name: "Gregor"
};
```
- one way to think of "this" is that it refers to the object on which the function was called.
- in other words, the object on the left hand side of the dot, when you call it like so:
```javascript
courseFacilitator.sayHello()
```
- the value of "this" within sayHello would be the object used to call the method, which is courseFacilitator here.
- so this.name==courseFacilitator.name
---
**here's a slightly different example**
```javascript=
function sayHello(){
console.log(`Hello i'm ${this.name}`)
}
//shorthand notation for sayHello:sayHello
//makes a new key of sayHello
//with the value being the sayHello function defined above
const courseFacilitator={
name: "Gregor",
sayHello
}
const founder = {
name: "Dan",
sayHello
}
courseFacilitator.sayHello()
founder.sayHello()
```
- for line 17, "this" within sayHello will refer to the courseFacilitator object
- for line 18, "this" within sayHello will refer to the founder object
- we can see that "this" is figured out at runtime, depending on how the function is called.
---
- with this information that "this" is calculated when the function is actually called, and not "bound" permanently, here's yet another example
```javascript=
const courseFacilitator = {
sayHello(){
console.log(`Hello i'm {this.name}`)
},
name: "Gregor"
};
let sayHelloCopy=courseFacilitator.sayHello()
sayHelloCopy();
```
- sayHelloCopy returns undefined because it is called in global scope.
- the value of "this" will be the global object.
- which most likely doesnt have a property of "name"
---
- to fix that, we would have to "bind" the value of this for our newly created function.
- this means we need to point javascript back to the courseFacilitator object, and tell sayHelloCopy to use that object as the value of "this".
```javascript
const courseFacilitator = {
sayHello(){
console.log(`Hello i'm {this.name}`)
},
name: "Gregor"
};
let sayHelloCopy=courseFacilitator.sayHello()
//this line copies over the function, but also makes sure that the value of "this" is explicitly set to be the course
let boundSayHelloCopy=sayHelloCopy.bind(courseFacilitator)
boundSayHelloCopy();
```
- now the value of "this" for boundSayHelloCopy is courseFacilitator.
- there's a lot more to "this", that I can't discuss in such a short time!
---
## Constructors
- they're a way to make multiple similar objects.
**conventions:**
- named with capital letter first.
- should be executed only with "new" operator.
---
```javascript
function CourseFacilitator(name){
this.name=name
this.sayHello(){
console.log(`Hello i'm ${this.name}`)
}
const gregor = new CourseFacilitator("gregor");
const bobby = new CourseFacilitator("bobby");
console.log(bobby)
console.log(gregor)
bobby.sayHello()
gregor.sayHello()
```
- here the "new" keyword creates an empty object.
- the value of "this" will be this empty object
- it runs the constructor function to add a property of name to the object, the value coming from the function argument.
- it then returns this newly created object
- this is what happens when you say new Date(), or new Regexp().. somewhere there is a constructor function that will create a new copy of a date object or a regexp object, and fill it up with certain properties
---
## things i didnt cover, but lead on from here
- strict mode
- the behaviour of arrow functions with regards to "this"
- prototypes, inheritance, classes - this is a talk in itself.
---
# final note
- A lot of this stuff is quite advanced, and you may not directly use it that much in day to day programming.
- however, interviewers like asking the tough questions sometimes :cry:
- I'd be happy if half of this got imbibed today. takes time and practice for some of the tougher concepts.
- I just wanted to share my approach to this, which is to understand the concept from several sources, and then write my own examples for future reference.
- this will save you having to read through wordy mdn explanations.
- It's okay to forget, it's okay to google.
- Keep going, you're all doing great! 🎉
---