Introduction Contemporary Javascript for Programmers of Other Languages
For programmers of other languages.
- Overview
- The Basics
- Objects
- Regular Functions
- Anonymous Functions
- Arrow Functions
- Immediately-Invoked Function Expressions
- Arrays
- Higher-Order Functions
- Asynchronicity
- Using APIs
- Destructuring
- Importing & Exporting Modules
- Implementation Differences
- Conclusions
Overview
Concept
Javascript, also known as ECMAScript, has a few unusual features that trouble programmers of other languages.
-
dynamic and weak typing of variables, with type ‘coercion’
-
prototypal inheritance (no classes!)
-
insular jargon like ‘hoisting’, ‘closures’, ‘destructuring’, and ‘unpacking’
-
two comparison operators, == and ===
-
at least 5 different syntaxes for defining functions
-
several different ways to instantiate objects
-
two very different common use-cases: client-side and server-side programming
-
three different ways to handle asynchronousity
Try it yourself
Try out the code examples in this deck for yourself: https://github.com/nyu-software-engineering/javascript-crash-course
The Basics
Variable declaration
Three keywords to declare a variable:
-
let - for defining block-scoped variables
-
const - for defining block-scoped variables that cannot be reassigned to a new value
-
var - for defining function-scoped variables, or global variables if not declared within a function… supported for legacy purposes and should not be used in new code
Let example
// non-constant variables are declared with the let keyword
let it = true // it's true!
it = it ? false : true // reassign it to be its opposite using the ternary operator
console.log(`It is ${it}!`) // expected output: 'It is false!'
Const example
// constants are declared with the const keyword
const data = [10, 20, 30] // a variable that can't be reassigned!
data[1] = "ha!" // but this is not variable reassignment!
console.log(data) // expected output: [10, 'ha!', 30]
Scope example
Imagine the following code?
let x = 5
{
let x = 10
}
console.log(x)
What is output?
Output to console
Basic output to the console
let stuff = "some text"
console.log("This is " + stuff + ".") // expected output: 'This is some text.'
String templates
Template syntax enapsulating a string with backtics
let stuff = "some text"
console.log(`This is ${stuff}.`) // expected output: 'This is some text.'
Template syntax will accept any expression
const x = 5
const y = 10
console.log(`The result is ${x + y}.`) // expected output: 'The result is 15.'
For loops
The expected behavior.
// iterate 5 times
for (let i = 1; i < 6; i++) {
console.log(`For loop iteration #${i}`)
}
// infinite loop
for (let i = 1; true; i++) {
console.log(`For loop iteration #${i}`)
}
// finite loop
for (someValue in someArray) {
console.log(`The value is ${someValue}`)
}
… there are more for
loop variations when it comes to arrays
While loops
The expected behavior.
// iterate 5 times
let i = 1
while (i < 6) {
console.log(`While loop iteration #${i}`)
i++
}
let i = 0
while (true) {
console.log(`While loop iteration #${i}`)
i++
}
Equality
The ==
operator compares by value with type coercion.
1 == "1" // true
true == 1 // true
undefined == null // true
Equality
The ===
operator compares by value without any type coercion.
1 === "1" // false
true === 1 // false
undefined === null // false
Semi-colons
Semi-colons are optional, as long as each statement is written on its own line.
1 === "1" // false
true === 1 // false
undefined === null // false
- do not use them, if you can help it.
Regular Functions
The function
keyword.
// define a function the most simple way
function doSomething1() {
console.log("doSomething1 is running")
}
doSomething1() // call the function
And with parameters/arguments…
// define a function the most simple way with two parameters
function doSomething2(x, y) {
console.log(`doSomething2 is running with x=${x} and y=${y}.`)
}
doSomething2("hello", "world") // call the function with arguments
And with a return value…
// define a function the most simple way with two parameters and a return value
function doSomething3(x, y) {
const msg = `doSomething3 is running with x=${x} and y=${y}.`
return msg
}
console.log(doSomething3("hello", "world")) // call the function and use its return value
Anonymous Functions
Functions in Javascript can be nameless.
// define an anonymous function
function () {
console.log("doSomething1 is running")
}
You may be wondering how you call a function with no name.
One way to call an anonymous function is to assign a variable to point to it.
// define an anonymous function, but assign a variable to refer to it
const doSomething1 = function () {
console.log("doSomething1 is running")
}
doSomething1() // call the function
And with parameters…
// define an anonymous function with parameters, but assign a variable to refer to it
const doSomething2 = function (x, y) {
console.log(`doSomething2 is running with x=${x} and y=${y}.`)
}
doSomething2("hello", "world") // call the function with arguments
And with a return value…
// define an anonymous function with parameters and a return value, but assign a variable to refer to it
const doSomething3 = function (x, y) {
const msg = `doSomething3 is running with x=${x} and y=${y}.`
return msg
}
console.log(doSomething3("hello", "world")) // call the function and use its return value
Arrow functions
A simplified function syntax without the function
keyword.
// an arrow function with no parameters or return value
const doSomething1 = () => {
console.log("doSomething1 is running")
}
doSomething1() // call the function
And with parameters…
// an arrow function with parameters
const doSomething2 = (x, y) => {
console.log(`doSomething2 is running with x=${x} and y=${y}.`)
}
doSomething2("hello", "world") // call the function with arguments
And with a return value…
// an arrow function with parameters and a return value
const doSomething3 = (x, y) => {
const msg = `doSomething3 is running with x=${x} and y=${y}.`
return msg
}
console.log(doSomething3("hello", "world")) // call the function and use its return value
Function syntax can be even further reduced if all it does is return a value.
const doSomething4 = (x, y) => `doSomething4 is running with x=${x} and y=${y}.`
console.log(doSomething4("hello", "world")) // call the function and use its return value
Even further reduced syntax with no parentheses around a single parameter:
const doSomething5 = x => `doSomething5 is running with x=${x}.`
console.log(doSomething5("hello")) // call the function and use its return value
Note that with this shorthand return statement, if the value returned is an object, that object must be encapsulated in parentheses.
const getFoo = () => ({ first: "Foo", last: "Barstein" })
Immediately-Invoked Function Expressions
Wrapping a function in parentheses turns it into an expression.
;(function doSomething() {
console.log("doing something")
})
Note that it is convention to place a semi-colon (;
) before an immediately-invoked function in order to ensure it is interpreted as a separate statement from whatever comes above it in the code.
This allows it to be immediately called, if desired.
;(function doSomething() {
console.log("doing something")
})()
An anonymous arrow function turned into an IIFE:
;(() => {
console.log("doing something")
})()
Put onto one line.
;(() => {
console.log("doing something")
})()
Similar, but different.
;(message => console.log(message))("doing something")
Objects
Instantiating objects
Javascript objects are usually instantiated directly, without the need for a class.
// an object
const me = {
name: "Foo Barstein",
phone: "212-666-1212",
age: 63,
isRobot: false,
}
Methods can be tacked onto extant objects.
me.speak = function (message) {
console.log(`${this.name} says, "${message}".`)
}
me.speak("Hello!") // expected output: 'Foo Barstein says, "Hello!".'
Instance methods
There is a special shorthand syntax if declaring methods within objects
const fido = {
name: "Fido",
breed: "Schnauzer",
bark(message) {
console.log(`${this.name} the ${this.breed} says, '${message}'`)
},
}
fido.bark("Woof!")
Creating an object from another object
Javascript uses prototypal inheritance, where one object uses another as the prototype
from which it is based.
// make a copy of an object - this is prototypal inheritance
const robotMe = Object.create(me) // creates a new object based on the original as its prototype
robotMe.isRobot = true // modify this new object in some way
console.log(`me ${me.isRobot ? "is indeed" : "is not"} a robot.`) // expected output: "My name is Foo Barstein"
console.log(`robotMe ${robotMe.isRobot ? "is indeed" : "is not"} a robot.`) // expected output: "My name is Foo Barstein"
Changes to methods or properties can be added onto the cloned object to differentiate it from its “parent”.
// add robot-specific speach abilities
robotMe.speak = function (message) {
console.log(
`${this.name} the robot states in monotonous voice, "${message}".`
)
}
Creating an object from another object (continued)
Instead of using Object.create(me)
, we could have constructed the robotMe
from the me
prototype manually, using the special __proto__
field:
const robotMe = {
isRobot: true, // override the prototype's isRobot property
speak(message) {
// override the prototype's speak method
console.log(
`${this.name} the robot states in monotonous voice, "${message}".`
)
},
__proto__: me, // specify which object to use as the prototype
}
Whichever way you do it, the properties and methods of the prototype are inherited, accessible, and writeable, e.g.:
robotMe.age
->63
(inherited fromme
)robotMe.__proto__.isRobot
->false
(property of the prototype)Object.getPrototypeOf(robotMe).isRobot
->false
(alternative way)robotMe.__proto__.age = 65
(modify the prototype’s property)robotMe.__proto__ = {foo: 'bar', baz: 'bum'}
(swap out the prototype entirely)
Methods in objects
The this
keyword refers to the object a method is called on.
// an object with a method belonging to it
const fido = {
name: "Fido",
breed: "Schnauzer",
bark(message) {
console.log(`${this.name} the ${this.breed} says, '${message}'`)
},
}
// call the bark method on the fido object
fido.bark("Woof!") //expected output: "Fido the Schnauzer says, 'Woof!'"
Functions are classes… or classes are functions?!
Objects can alternatively be instantiated by calling a “constructor” function using the new keyword.
function Dog(name, breed) {
this.name = name
this.breed = breed
this.bark = message => {
console.log(`${this.name} the ${this.breed} says, '${message}'`)
}
}
// instantiate an object and call its method
let fido = new Dog("Fido", "Schnauzer")
fido.bark("Woof!")
See more about prototypal inheritance and constructor functions at MDN’s excellent Javascript documentation
Constructing objects with a class definition
Objects can alternatively be instantiated from a class definition. This is syntactic sugar
and not a real feature of the language.
class Dog {
constructor(name, breed) {
this.name = name
this.breed = breed
}
bark(message) {
console.log(`${this.name} the ${this.breed} says, '${message}'`)
}
}
// instantiate an object and call its method
let fido = new Dog("Fido", "Schnauzer")
fido.bark("Woof!")
Arrays
Basics
Arrays behave as expected.
// generate an array from a string
let fruits = "avocado,tomato,banana".split(",") // returns ['avocado, 'tomato', 'banana']
console.log(`Do you love ${fruits[1]}?`) // expected output "Do you love tomato?"
// add an element to an array
fruits.push("pepper") // fruits now has ['avocado, 'tomato', 'banana', 'pepper']
// find index position of element by value
const fruit = "pepper"
let pos = fruits.indexOf(fruit) // returns 3
console.log(`${fruit} is located in the array at index ${pos}.`)
Basics
Continued.
// delete last element from the array
fruits.pop() // fruits now has ['avocado, 'tomato', 'banana']
// indexOf returns -1 if value not found in arraay
pos = fruits.indexOf("pepper") // 'pepper' is no longer there, so -1 is returned
console.log(`${fruit} is now located in the array at index ${pos}.`)
// join all elements in array into a comma-separated string
const stringAgain = fruits.join(",") // returns 'avocado,tomato, banana'
console.log(`The fruits are ${stringAgain}.`)
forEach function
Calls a function for each element in an array.
const numbers = [65, 44, 12, 4]
numbers.forEach(n => {
console.log(n)
})
Map function
Creates a new array containing the results of a function call for each array element. Useful for transforming array values.
const numbers = [65, 44, 12, 4]
const newNumbers = numbers.map(n => n * 10)
// newNumbers now refers to [650, 440, 120, 40]
Filter function
Create a subset of an array.
let fruits = "avocado,tomato,banana".split(",") // ['avocado, 'tomato', 'banana']
// create a new array with a subset of the original values
fruits = fruits.filter((val, i, arr) => {
return val != "banana" // returns true for all fruits except 'banana'
})
console.log(fruits) // expected output: ['avocado', 'tomato']
Arrays of objects
A common data structure used by APIs to pass data between clients and servers is an array of objects.
const products = [
{
id: 1,
title: "Boa, emerald green tree",
price: "$31.82",
description: "Sed ante. Vivamus tortor. Duis mattis egestas metus.",
},
{
id: 2,
title: "Bleu, blue-breasted cordon",
price: "$35.66",
description:
"Praesent blandit. Nam nulla. Integer pede justo, lacinia eget, tincidunt eget, tempus vel, pede.",
}, // imagine there were more product objects...
]
Iterating through an array of objects
Any of the standard array iteration methods (forEach
, map
, or filter
) can be used to iterate through an array of objects, e.g.:
// loop through each product
products.forEach(product => {
// print the title and price of each product
console.log(`${product.title} - ${product.price}`)
})
Higher Order Functions
Functions can be passed as arguments to other functions.
// a simple function that prints out its argument
const foo = val => {
console.log(`val = ${val}`)
}
// another function that takes another function as its argument
const bar = (func, arg) => {
func(arg) // call the function that was received, whatever it is, and pass it the argument that was received
}
// pass the foo function to the bar function as an argument
bar(foo, 5)
Asynchronicity
Overview
Javascript has three features to handle asynchronicity in code.
- Callbacks
- Promises
- Async/await
Callbacks
Callbacks are functions that will be called when a certain task completes.
// a function that accepts two callbacks - one for success, one for failure
let doIt = (callbackSuccess, callbackFailure) => {
const someCondition = doWhateverWorkWeNeedToDo() // imagine this function did an asynchronous task and then...
if (someCondition)
callbackSuccess("hooraah") // call the success callback function
else callbackFailure("boo!") // call the failure callback function
}
// call the function, pass two callback functions to handle its success or failure
doIt(
res => {
console.log(`Success: ${res}`)
},
err => {
console.log(`Failure: ${err}`)
}
)
Promises
Promises are a language feature that allow programmers to specify two functions: one to be called automatically when a certain asynchronous task is successfully completed and another to be called when that task fails.
// a function that returns a Promise
let doIt = () => {
return new Promise((resolve, reject) => {
const someCondition = doWhateverWorkWeNeedToDo() // imagine this function did an asynchronous task and then...
if (someCondition) resolve("hooraah") // call the success callback function
else reject("boo!") // call the failure callback function
})
}
// call the function, pass functions to handle its success or failure, whenever it completes
doIt()
.then(res => {
console.log(`Success: ${res}`)
})
.catch(err => {
console.log(`Failure: ${err}`)
})
Async
The async
keyword works on top of Promises to make their syntax simpler to read.
- It can be placed in front of any function definition - this means the function’s return value is guaranteed to be returned as a Promise, regardless of what the return statement says.
let doIt = async () => {
// this function automatically returns a Promise, even if it doesn't say so
doWhateverWorkWeNeedToDo() // imagine this function did an asynchronous task and then...
return "hoorah!" // 'hoorah' will be automatically passed as the argument to the resolve function of the Promise
}
// we can the function call as if it returns a Promise, which it does.
doIt()
.then(res => {
console.log(`Success: ${res}`)
})
.catch(err => {
console.log(`Failure: ${err}`)
})
Await
The await
keyword forces the program to wait for a Promise to complete before moving on to the next line of code. It allows us to write code in a familiar manner, even when dealing with asynchronous Promises.
let doIt = async () => {
// this function automatically returns a Promise, even if it doesn't say so
doWhateverWorkWeNeedToDo() // imagine this function did an asynchronous task and then...
return "hoorah!" // 'hoorah' will be automatically passed as the argument to the resolve function of the Promise
}
try {
const res = await doIt()
console.log(`Success: ${res}`) // if the line above does not throw an error, then the promise was resolved and we have success!
} catch (err) {
console.log(`Failure: ${err}`) // the promise was rejected, so we have failure
}
Await (continued)
There is only one complication: await
can only be used within an async
function.
let doIt = async () => {
// this function automatically returns a Promise, even if it doesn't say so
doWhateverWorkWeNeedToDo() // imagine this function did an asynchronous task and then...
return "hoorah!" // 'hoorah' will be automatically passed as the argument to the resolve function of the Promise
}
// await is only allowed within an async function, so make an async function
let start = async () => {
try {
const res = await doIt() // run the function that returns a Promise, wait for completion
console.log(`Success: ${res}`) // handle success
} catch (err) {
console.log(`Failure: ${err}`) // handle failure
}
}
start() // immediately call the async function
Await (continued again)
A standard try
/catch
statement is the simplest way to handle both success and failure of a Promise when using await
.
let doIt = async () => {
// this function automatically returns a Promise, even if it doesn't say so
doWhateverWorkWeNeedToDo() // imagine this function did an asynchronous task and then...
return "hoorah!" // 'hoorah' will be automatically passed as the argument to the resolve function of the Promise
}
let start = async () => {
// await is only allowed within an async function
try {
const res = await doIt() // run the function that returns a Promise, wait for completion
console.log(`Success: ${res}`) // handle success
} catch (err) {
console.log(`Failure: ${err}`) // handle failure
}
}
start()
Using APIs
Concept
When a client requests data from a server, that data must be returned in a particular format the client can parse.
- The servers always return text (i.e. strings) in their HTTP responses
- For simple static web content, that format of the data is simple HTML returned by the server
- For more complex needs, Javascript Object Notation (JSON) is the preferred format.
- Once on the client side, this JSON is interpreted as Javascript code.
Example (not recommended)
Fetching data from APIs requires asynchronous programming. Node.js’s built-in https
module can be used to fetch data asynchronously, but its syntax leaves a lot ot be desired.
const https = require("https") // using Node's built-in http module for http requests
const apiUrl = "https://my.api.mockaroo.com/users.json?key=d9ddfc40" // a mock-API for demo purposes that returns a JSON array of objects
// make an HTTP request to the API server
https
.get(apiUrl, response => {
response.on("data", chunk => {
// this callback function is called automatically every time a chunk of data has been recieved from the server.
})
response.on("end", () => {
// this callback function is called automatically when all data has been received from API
})
})
.on("error", err => {
// this callback function is called automatically if there is an error
})
Example (recommended)
A syntactically simpler way to fetch data from APIs would be to use the 3rd-party axios module, which must be downloaded an installed into a project (e.g. npm install axios
).
const axios = require("axios") // using the axios module for http requests
const apiUrl = "https://my.api.mockaroo.com/users.json?key=d9ddfc40" // a mock-API for demo purposes that returns a JSON array of objects
// make an HTTP request to the API server
axios
.get(apiUrl)
.then(response => {
// this callback function is called automatically when all data has been received from API
// do something when the Promise is resolved and response.data is received successfully
})
.catch(err => {
// this callback function is called automatically if there is an error
})
Example (even more recommended)
The same code, but using async
/await
:
const axios = require("axios") // using the axios module for http requests
const apiUrl = "https://my.api.mockaroo.com/users.json?key=d9ddfc40" // a mock-API for demo purposes that returns a JSON array of objects
// make an HTTP request to the API server
// define an async function so we can use the await keyword to wait for the API's response
const start = async () => {
try {
const response = await axios.get(apiUrl) // await the response before moving on
// do something when the Promise is resolved and response.data is received successfully
} catch (err) {
// do something when the Promise is rejected, meaning there is an error
}
}
start() // call the async function immediately
Destructuring
Arrays
Values in an array can be extracted into separate variables upon assignment:
const [a, b] = [10, 20, 30, 40, 50] // a=10, b=20
The remaining values can be lumped together - this is rest syntax:
const [c, d, ...rest] = [10, 20, 30, 40, 50] // c=10, d=20, rest=[30,40,50]
Function parameters can follow this same syntax:
function foo(a, b, ...args) {
console.log(`a = ${a}, b = ${b}`, args = ${args}`) // args = [30, 40, 50]
}
foo(10, 20, 30, 40, 50) // pass values as separate arguments
Spread syntax
Spread syntax is the opposite of rest syntax - it dissolves an array into separate values in particular contexts.
Such as when passing an array of arguments to a function.
// a function that accepts two separate arguments
function sum(x, y) {
return x + y
}
let args = [10, 20]
let total = sum(...args) // spread the values in the array into multiple arguments
Or copying values from one array into another…
let myVals = [1, 2, 3, ...[4, 5, 6]] // [1, 2, 3, 4, 5, 6]
Objects
Values within an object can be destructured.
Take this object with a nested sub-object as a starting point…
const person = {
age: 72,
name: "Foo Barstein",
email: "fb1258@teleworm.us",
address: {
street: "92 Rue Jamil Sedki",
city: "Beni Brahim",
country: "Tunisia",
postalCode: 7040,
},
}
const { name, age } = person // name='Foo Barstein', age=72
console.log(`name = ${name}`) // expected output: 'Foo Barstein'
console.log(`age = ${age}`) // expected output: 72
Objects
Variable names do not need to match field names:
const { name: fullName, age: apparentAge } = person // { fullName: 'Foo Barstein', apparentAge: 72 }
console.log(`fullName = ${fullName}`) // expected output: 'Foo Barstein'
console.log(`apparentAge = ${apparentAge}`) // expected output: 72
Nested objects can be destructured as well:
const {
email,
address: {
city, // create a variable for this field only
},
} = person
console.log(`email = ${email}`) // expected output: 'fb1258@teleworm.us'
console.log(`city = ${city}`) // expected output: 'Beni Brahim''
Importing & Exporting
Confusão organizada
Javascript today allows modular reuse of your own code or that of 3rd parties through its module functionality.
-
the Node Package Manager (
npm
) provides easy ways to manage the download, installation, and configuration of open soure 3rd party code libraries. -
Node supports two different ways of importing/exporting modules: the CommonJS way, and the ECMAScript 2015 (
ES6
) way. -
Node originally supported the
CommonJS
module specification beforeES6
was released, since there was nothing in theECMAScript
specification for importing/exporting at that time. -
Once
ES6
arrived, Node added support for its specification, but a special'type': 'module'
setting must be added to every Node project’s config file namedpackage.json
for theES6
module functionality to kick in. Do this in all new code.
CommonJS exporting
Basic CommonJS exporting syntax:
// imagine you had a variable foo, a function bar, and an object baz - all can be exported
// export these all to make them available for import into another Javscript file
module.exports = { foo, bar, baz } // note the CommonJS syntax!
With CommonJS, you could also have exported each variable individually:
module.exports.foo = 5 // a number
module.exports.bar = () => {
console.log("hello world!")
} // a function
module.exports.baz = { x: 5, y: 10 } // an object
Or even without the module
prefix:
exports.foo = 5 // a number
exports.bar = () => {
console.log("hello world!")
} // a function
exports.baz = { x: 5, y: 10 } // an object
CommonJS importing
Import named exports using the require
function (note the destructuring syntax):
const { foo, bar, baz } = require("./10.exporting")
Or import the entire module and access the named exports separately:
const myModule = require("./10.exporting") // import module as a whole
console.log(myModule.foo) // access a value exported in the module
myModule.bar() // access a function exported in the module
ES6 exporting
Basic ES6 exporting syntax:
// imagine you had a variable foo, a function bar, and an object baz - all can be exported
// export these all to make them available for import into another Javscript file
export { foo, bar, baz } // note the ES6 syntax!
With ES6, you could also have exported each variable individually:
export let foo = 5 // a number
export let bar = () => {
console.log("hello world!")
} // a function
export let baz = { x: 5, y: 10 } // an object
Or you can specify one of them as the default
export, if desired:
export let foo = 5 // a number
export default let bar = () => { console.log('hello world!') } // a function
export let baz = { x: 5, y: 10 } // an object
ES6 importing
Import named exports using the import
keyword (note the destructuring syntax):
import { foo, bar, baz } from "./10.exporting"
Or give each import a different name than in the module:
import { foo as f, bar as b1, baz as b2 } from "./10.exporting"
If the module specified a default
export, we can import only that - note the syntax:
import bar from "./10.exporting"
We can also import the default export in combination with some named exports:
import bar, { foo, baz } from "./10.exporting" // the default export is 'bar'
Which import/export standard should you use?
The ES6
way is now standard for new projects. Use import
and export
in your code, and not require
and module.exports
.
You may still encounter the CommonJS
way in older code.
Implementation Differences
Differences
Javascript can be run either within a web browser (i.e. as client-side code within a web page) or in a more open environment outside of the browser (including as server-side code). There are some key differences.
-
Javascript in the web browser is primarily focused on interacting with the browser’s Document Object Model (
DOM
) - an object created automatically by the browser that provides code access to all the contents, styles, and behaviors of the web page currently loaded in the browser’s memory. Web browsers also “sandbox” the code running within it so that it cannot access the user’s computer or network, among other limitations. -
Node.js runs outside any web browser, so there is no currently-loaded web page and fewer restrictions on what it can do. So the
DOM
does not exist in this environment. Node.js has its own set of built-in variables and objects that are more general-purpose.
Differences (continued)
-
There are myriad web browsers with myriad different versions in active use by people across The World-Wide Web. Programming Javascript that will work in all of them usually means taking a lowest-common denominator approach and sticking to language features that have been supported by browsers for many years.
-
Unlike with the web browser, you control the server, including which version of Javascript is supported. So you can guarantee support for whichever version of Node.js you choose to program in.
-
See a chart of the differences in Javascript support among common browsers/engines
Browser example
Imagine the following HTML code for a button and a picture of a donkey.
<button id="clickme">Click me please</button>
<img id="neigh" src="images/donkey.jpg" />
And let’s say the following CSS code hid the donkey:
/* this will cause the donkey to be hidden when the page first loads */
img#neigh {
display: none;
}
The following client-side Javascript, using the popular JQuery framework, will wait for the user to click the button and then will run the callback function:
$("button#clickme").click(function () {
// make donkey will appear
$("img#neigh").show()
})
Server example
The following server-side code uses the popular Express.js framework.
// set up a 'route'... i.e. a callback function to run when a particular request comes in
app.get("/foo", (request, response) => {
response.send("bar") // send the response
})
// another one just for fun... this one waits for an HTTP POST request for the same URL
app.post("/foo", (request, response) => {
// let's assume the client has sent some POST data with the user's name
response.send(`Hello, ${req.body.name}!`) // send the response
})
Conclusions
You are now primed dive into the web browser’s implementation of Javascript, as well as configuring projects with NPM and Express.js and React’s implementations!
- Thank you. Bye