knowledge-kitchen
/
course-notes
class: center, middle # Javascript Crash Course For programmers of other languages. --- # Agenda 1. [Overview](#overview) 1. [The Basics](#basics) 1. [Objects](#objects) 1. [Regular Functions](#functions) 1. [Anonymous Functions](#anonymous-functions) 1. [Arrow Functions](#arrow-functions) 1. [Immediately-Invoked Function Expressions](#iife) 1. [Arrays](#arrays) 1. [Higher-Order Functions](#higher-order-functions) 1. [Asynchronicity](#asynchronicity) 1. [Using APIs](#apis) 1. [Destructuring](#destructuring) 1. [Importing & Exporting Modules](#modules) 1. [Implementation Differences](#implementations) 1. [Conclusions](#conclusions) --- name: overview # 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 --- template: overview ## Try it yourself Try out the code examples in this deck for yourself: https://github.com/nyu-software-engineering/javascript-crash-course --- name: basics # 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_ --- template: basics ## Let example ```js // 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!' ``` --- template: basics ## Const example ```js // 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] ``` --- template: basics ## Scope example Imagine the following code? ```js let x = 5 { let x = 10 } console.log(x) ``` What is output? --- template: basics ## Output to console Basic output to the console ```js let stuff = "some text" console.log("This is " + stuff + ".") // expected output: 'This is some text.' ``` --- template: basics ## String templates Template syntax enapsulating a string with backtics ```js let stuff = "some text" console.log(`This is ${stuff}.`) // expected output: 'This is some text.' ``` -- Template syntax will accept any expression ```js const x = 5 const y = 10 console.log(`The result is ${x + y}.`) // expected output: 'The result is 15.' ``` --- template: basics ## For loops The expected behavior. ```js // iterate 5 times for (let i = 1; i < 6; i++) { console.log(`For loop iteration #${i}`) } ``` -- ```js // infinite loop for (let i = 1; true; i++) { console.log(`For loop iteration #${i}`) } ``` -- ```js // finite loop for (someValue in someArray) { console.log(`The value is ${someValue}`) } ``` -- ... there are more `for` loop variations when it comes to [arrays](#arrays-foreach) --- template: basics ## While loops The expected behavior. ```js // iterate 5 times let i = 1 while (i < 6) { console.log(`While loop iteration #${i}`) i++ } ``` -- ```js let i = 0 while (true) { console.log(`While loop iteration #${i}`) i++ } ``` --- template: basics ## Equality The `==` operator compares by value _with type coercion_. ```js 1 == "1" // true true == 1 // true undefined == null // true ``` --- template: basics ## Equality The `===` operator compares by value _without any type coercion_. ```js 1 === "1" // false true === 1 // false undefined === null // false ``` --- template: basics ## Semi-colons Semi-colons are optional, as long as each statement is written on its own line. ```js 1 === "1" // false true === 1 // false undefined === null // false ``` -- - do not use them, if you can help it. --- name: functions # Regular Functions -- The `function` keyword. ```js // define a function the most simple way function doSomething1() { console.log("doSomething1 is running") } doSomething1() // call the function ``` --- template: functions And with _parameters_/arguments... ```js // 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 ``` --- template: functions And with a _return_ value... ```js // 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 ``` --- name: anonymous-functions # Anonymous Functions -- Functions in Javascript can be nameless. ```js // define an anonymous function function () { console.log("doSomething1 is running") } ``` -- You may be wondering how you call a function with no name. --- template: anonymous-functions One way to call an anonymous function is to assign a _variable_ to point to it. ```js // define an anonymous function, but assign a variable to refer to it const doSomething1 = function () { console.log("doSomething1 is running") } doSomething1() // call the function ``` --- template: anonymous-functions And with _parameters_... ```js // 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 ``` --- template: anonymous-functions And with a _return_ value... ```js // 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 ``` --- name: arrow-functions # Arrow functions -- A simplified function syntax without the `function` keyword. ```js // an arrow function with no parameters or return value const doSomething1 = () => { console.log("doSomething1 is running") } doSomething1() // call the function ``` --- template: arrow-functions And with parameters... ```js // 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 ``` --- template: arrow-functions And with a return value... ```js // 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 ``` --- template: arrow-functions Function syntax can be even further reduced if all it does is return a value. ```js 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 ``` --- template: arrow-functions Even further reduced syntax with no parentheses around a single parameter: ```js const doSomething5 = x => `doSomething5 is running with x=${x}.` console.log(doSomething5("hello")) // call the function and use its return value ``` --- template: arrow-functions Note that with this shorthand return statement, if the value returned is an object, that object **must** be encapsulated in parentheses. ```js const getFoo = () => ({ first: "Foo", last: "Barstein" }) ``` --- name: iife # Immediately-Invoked Function Expressions -- Wrapping a function in parentheses turns it into an expression. ```js ;(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. --- template: iife This allows it to be immediately called, if desired. ```js ;(function doSomething() { console.log("doing something") })() ``` --- template: iife An anonymous arrow function turned into an IIFE: ```js ;(() => { console.log("doing something") })() ``` --- template: iife Put onto one line. ```js ;(() => { console.log("doing something") })() ``` --- template: iife Similar, but different. ```js ;(message => console.log(message))("doing something") ``` --- name: objects # Objects -- ## Instantiating objects Javascript objects are usually instantiated directly, without the need for a class. ```js // an object const me = { name: "Foo Barstein", phone: "212-666-1212", age: 63, isRobot: false, } ``` -- Methods can be tacked onto extant objects. ```js me.speak = function (message) { console.log(`${this.name} says, "${message}".`) } me.speak("Hello!") // expected output: 'Foo Barstein says, "Hello!".' ``` --- template: objects ## Instance methods There is a special shorthand syntax if declaring methods within objects ```js const fido = { name: "Fido", breed: "Schnauzer", bark(message) { console.log(`${this.name} the ${this.breed} says, '${message}'`) }, } fido.bark("Woof!") ``` --- template: objects ## Creating an object from another object Javascript uses prototypal inheritance, where one object uses another as the `prototype` from which it is based. ```js // 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". ```js // add robot-specific speach abilities robotMe.speak = function (message) { console.log( `${this.name} the robot states in monotonous voice, "${message}".` ) } ``` --- template: objects ## 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: ```js 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 from `me`) - `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) --- template: objects ## Methods in objects The `this` keyword refers to the object a method is called on. ```js // 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!'" ``` --- template: objects ## Functions are classes... or classes are functions?! Objects can alternatively be instantiated by calling a "constructor" function using the **new** keyword. ```js 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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain#constructors) --- template: objects ## 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. ```js 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!") ``` --- name: arrays # Arrays -- ## Basics Arrays behave as expected. ```js // 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?" ``` -- ```js // add an element to an array fruits.push("pepper") // fruits now has ['avocado, 'tomato', 'banana', 'pepper'] ``` -- ```js // 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}.`) ``` --- template: arrays ## Basics Continued. ```js // delete last element from the array fruits.pop() // fruits now has ['avocado, 'tomato', 'banana'] ``` -- ```js // 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}.`) ``` -- ```js // join all elements in array into a comma-separated string const stringAgain = fruits.join(",") // returns 'avocado,tomato, banana' console.log(`The fruits are ${stringAgain}.`) ``` --- template: arrays name: arrays-foreach ## forEach function Calls a function for each element in an array. ```js const numbers = [65, 44, 12, 4] numbers.forEach(n => { console.log(n) }) ``` --- template: arrays ## Map function Creates a new array containing the results of a function call for each array element. Useful for transforming array values. ```js const numbers = [65, 44, 12, 4] const newNumbers = numbers.map(n => n * 10) // newNumbers now refers to [650, 440, 120, 40] ``` --- template: arrays ## Filter function Create a subset of an array. ```js 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'] ``` --- template: arrays ## Arrays of objects A common data structure used by [APIs](#apis) to pass data between clients and servers is an array of objects. ```js 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... ] ``` --- template: arrays ## 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.: ```js // loop through each product products.forEach(product => { // print the title and price of each product console.log(`${product.title} - ${product.price}`) }) ``` --- name: higher-order-functions # Higher Order Functions -- Functions can be passed as arguments to other functions. ```js // a simple function that prints out its argument const foo = val => { console.log(`val = ${val}`) } ``` -- ```js // 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 } ``` -- ```js // pass the foo function to the bar function as an argument bar(foo, 5) ``` --- name: asynchronicity # Asynchronicity -- ## Overview Javascript has three features to handle asynchronicity in code. - Callbacks - Promises - Async/await --- template: asynchronicity ## Callbacks Callbacks are functions that will be called when a certain task completes. ```js // 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}`) } ) ``` --- template: asynchronicity ## 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. ```js // 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}`) }) ``` --- template: asynchronicity ## 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. ```js 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}`) }) ``` --- template: asynchronicity ## 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. ```js 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 } ``` --- template: asynchronicity ## Await (continued) There is only one complication: `await` can only be used within an `async` function. ```js 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 ``` --- template: asynchronicity ## Await (continued again) A standard `try`/`catch` statement is the simplest way to handle both success and failure of a Promise when using `await`. ```js 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() ``` --- name: apis # 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](/content/courses/web-design/slides/html) returned by the server - For more complex needs, [Javascript Object Notation](/content/courses/database-design/json/) (JSON) is the preferred format. - Once on the client side, this JSON is interpreted as Javascript code. --- template: apis ## 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. ```js 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 }) ``` --- template: apis ## Example (recommended) A syntactically simpler way to fetch data from APIs would be to use the 3rd-party [axios](https://www.npmjs.com/package/axios) module, which must be downloaded an installed into a project (e.g. `npm install axios`). ```js 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 }) ``` --- template: apis ## Example (even more recommended) The same code, but using `async`/`await`: ```js 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 ``` --- name: destructuring # Destructuring -- ## Arrays Values in an array can be extracted into separate variables upon assignment: ```js const [a, b] = [10, 20, 30, 40, 50] // a=10, b=20 ``` -- The remaining values can be lumped together - this is _rest syntax_: ```js const [c, d, ...rest] = [10, 20, 30, 40, 50] // c=10, d=20, rest=[30,40,50] ``` -- Function parameters can follow this same syntax: ```js 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 ``` --- template: destructuring ## 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. ```js // 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... ```js let myVals = [1, 2, 3, ...[4, 5, 6]] // [1, 2, 3, 4, 5, 6] ``` --- template: destructuring ## Objects Values within an object can be destructured. Take this object with a nested sub-object as a starting point... ```js const person = { age: 72, name: "Foo Barstein", email: "fb1258@teleworm.us", address: { street: "92 Rue Jamil Sedki", city: "Beni Brahim", country: "Tunisia", postalCode: 7040, }, } ``` -- ```js const { name, age } = person // name='Foo Barstein', age=72 console.log(`name = ${name}`) // expected output: 'Foo Barstein' console.log(`age = ${age}`) // expected output: 72 ``` --- template: destructuring ## Objects Variable names do not need to match field names: ```js 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: ```js 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'' ``` --- name: importing # 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](https://nodejs.org/docs/latest/api/esm.html#esm_differences_between_es_modules_and_commonjs) modules: the [CommonJS](https://en.wikipedia.org/wiki/CommonJS) way, and the [ECMAScript 2015](https://en.wikipedia.org/wiki/ECMAScript#6th_Edition_-_ECMAScript_2015) (`ES6`) way. -- - Node originally supported the `CommonJS` module specification before `ES6` was released, since there was nothing in the `ECMAScript` 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 named `package.json` for the `ES6` module functionality to kick in. **Do this in all new code**. --- template: importing ## CommonJS exporting Basic CommonJS exporting syntax: ```js // 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: ```js 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: ```js exports.foo = 5 // a number exports.bar = () => { console.log("hello world!") } // a function exports.baz = { x: 5, y: 10 } // an object ``` --- template: importing ## CommonJS importing Import named exports using the `require` function (note the [destructuring](#destructuring) syntax): ```js const { foo, bar, baz } = require("./10.exporting") ``` -- Or import the entire module and access the named exports separately: ```js 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 ``` --- template: importing ## ES6 exporting Basic ES6 exporting syntax: ```js // 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: ```js 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: ```js 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 ``` --- template: importing ## ES6 importing Import named exports using the `import` keyword (note the [destructuring](#destructuring) syntax): ```js import { foo, bar, baz } from "./10.exporting" ``` -- Or give each import a different name than in the module: ```js 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: ```js import bar from "./10.exporting" ``` -- We can also import the default export in combination with some named exports: ```js import bar, { foo, baz } from "./10.exporting" // the default export is 'bar' ``` --- template: importing ## 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. --- name: implementations # 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](../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](https://github.com/nyu-software-engineering/node-js-examples) that are more general-purpose. --- template: implementations ## Differences (continued) - There are _myriad web browsers_ with _myriad different versions_ in active use by people across [The World-Wide Web](/content/courses/software-engineering/slides/web-architecture/#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](https://kangax.github.io/compat-table/es6/) --- template: implementations ## Browser example Imagine the following [HTML](/content/courses/web-design/slides/html) code for a button and a picture of a donkey. ```html
Click me please
``` -- And let's say the following [CSS](/content/courses/web-design/slides/css) code hid the donkey: ```css /* 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](/content/courses/web-design/slides/jquery-intro) framework, will wait for the user to click the button and then will run the callback function: ```js $("button#clickme").click(function () { // make donkey will appear $("img#neigh").show() }) ``` --- template: implementations ## Server example The following server-side code uses the popular [Express.js](/content/courses/agile-development-and-devops/slides/express) framework. ```js // 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 }) ``` --- name: conclusions # 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