class: center, middle, lnu-background-yellow ### Grundläggande programmering (1DV021) # Föreläsnig 8 --- class: lnu-background-cc ### Upphovsrätt för detta verk Detta verk är framtaget av Mats Loock i anslutning till kursen Grundläggande programmering (1DV021) vid Linnéuniversitetet. Allt innehåll i detta verk förutom fotografier, ikoner, bild på kurslitteraturen samt Linnéuniversitetets logotyp och symbol, är licensierad under en
Creative Commons Erkännande 4.0 Internationell Licens
. #### Du får använda detta verk så här - kopiera hela eller delar av innehållet - sprida hela eller delar av innehållet - visa hela eller delar av innehållet offentligt och digitalt - konvertera innehållet till annat format - du får även göra om innehållet Om du förändrar innehållet så ta inte med fotografier, ikoner, bild på kurslitteraturen samt Linnéuniversitetets logotyp och symbol i din nya version! Vid all användning måste du ange källan: ”Linnéuniversitetet – Grundläggande programmering (1DV021)” och en länk till https://coursepress.lnu.se/kurs/grundlaggande-programmering och till Creative Common-licensen här ovan. --- # Organisera din kod! - Det är viktigt att skriva kod som är... - lätt att läsa - lätt att förstå - lätt att underhålla - lätt att samarbeta kring - Du har redan organiserat din kod! - Satser som hör samman har du organiserat i __funktioner__. - Funktioner och variabler (som då kallats metoder och egenskaper) som hör samman har du organiserat i __egendefinerade typer__ ("_Constructor/Prototype pattern_", JavaScript classes). - De egendefinierade typerna har du organiserat i...__moduler__(?). --- # Moduler i JavaScript - Vad är en en modul i Javascript? - En modul är helt enkelt en samling med JavaScript-kod som (säkert) kan användas av annan JavaScript-kod. - Varför ska jag organisera min kod i form av moduler? - Genom att organisera din kod i moduler kommer du att dela upp din kod i mindre återanvändbara delar. Vilket är bra eftersom: - Korta kodavsnitt är enklare att förstå och "debugga". - Korta kodavsnitt är enklare att testa. - Det är enklare att återanvända kodavsnitt istället för att duplicera koden. - Beroende på miljö finns det olika sätt att hantera moduler. Node.js använder en egen implementation av CommonJS. På klienten används ECMAScript Modules (ES Modules). --- # Moduler med Node.js - En modul kapslar in kod som hör samman. För att skapa en modul samlar du alla relaterade funktioner i en fil...
src/greetings.js
``` const sayHelloInEnglish = function () { return 'Hello' } const sayHelloInSpanish = function () { return 'Hola' } const sayHelloInSwedish = function () { return 'Hej' } ``` - ...men det räcker inte att samla funktioner i en fil. För att göra dem tillgängliga utanför filen måste de __exporteras__ så att de kan __importeras__ i de filer som behöver använda funktionerna. --- # Exportera funktioner
src/greetings.js
``` const sayHelloInEnglish = function () { return 'Hello' } const sayHelloInSpanish = function () { return 'Hola' } const sayHelloInSwedish = function () { return 'Hej' } // Två funktioner som exporteras; funktionen sayHelloInSwedish är att betrakta som privat inom modulen, // d.v.s. inte tillgänglig utanför filen greetings.js. module.exports.sayHelloInEnglish = sayHelloInEnglish module.exports.sayHelloInSpanish = sayHelloInSpanish ``` - Genom att tilldela `module.exports`, ett objekt som Node.js tillhandahåller, referenser till funktioner kan du bestämma vilka funktioner som ska göras tillgängliga utanför filen, exporteras. --- # Alternativ syntax
src/greetings.js
``` // Två funktioner som exporteras; funktionen sayHelloInSwedish // är att betrakta som privat inom modulen, d.v.s. inte tillgänglig utanför // filen greetings.js. module.exports.sayHelloInEnglish = function () { return 'Hello' } module.exports.sayHelloInSpanish = function () { return 'Hola' } const sayHelloInSwedish = function () { return 'Hej' } ``` --- # Alternativ syntax II
src/greetings.js
``` // Två funktioner som exporteras; funktionen sayHelloInSwedish // är att betrakta som privat inom modulen, d.v.s. inte tillgänglig utanför // filen greetings.js. module.exports = { sayHelloInEnglish : function () { return 'Hello' }, sayHelloInSpanish : function () { return 'Hola' } } const sayHelloInSwedish = function () { return 'Hej' } ``` --- # Exportera en typ
src/User.js
``` function User (name, email) { this.name = name this.email = email } module.exports = User // Använd INTE! //module.exports.User = User ``` - Om du vill att din modulrot ska vara en konstruktorfunktion tilldelar du `module.exports` referensen till konstruktorfunktionen direkt.
(Har betydelse vid import av modulen.)
--- # Importera kod - För att ladda en modul som finns i en underkatalog som filen som laddar den använder du `require` och den relativa sökvägen till filen.
app.js
``` const greetings = require('./src/greetings') console.log(greetings.sayHelloInEnglish()) console.log(greetings.sayHelloInSpanish()) ```
src/playAround.js
``` const greetings = require('./greetings'); console.log(greetings.sayHelloInEnglish()); console.log(greetings.sayHelloInSpanish()); ``` - Du anger alltid den relativa sökvägen, i förhållande till filen som vill använda en modul, till den fil som innehåller modulen du vill ladda. - Det är viktigt att du inleder med `./`, `../` eller `/` för att indikera en fil, annars måste modulen vara en "_core module_" eller återfinnas i katalogen `node_modules`. - Hittas inte filen kommer Node.js att försöka ladda den angivna modulen genom att lägga till filändelserna `.js`, `.json` och slutligen `.node`. --- # Importera och använda en egendefinierad typ
src/User.js
``` function User(name, email) { this.name = name this.email = email } module.exports = User ```
app.js
``` const User = require('./src/User') let user = new User('Ellen Nu', 'en@lnu.se') console.log(user) // OUTPUT: { name: 'Ellen Nu', email: 'en@lnu.se' } ``` --- # Hur kontrollera att en egenskaps värde är formaterat på rätt sätt? ``` function Address (addressLine, postalCode, city) { this.adressLine = addressLine this.postalCode = postalCode this.city = city } let address1 = new Address('Storgatan 1', '123 45', 'Storstaden') // OK adress! let address2 = new Address('Lillgatan 1', 'ingen aning', 'Lillstaden') // felaktigt postnummer! ``` - Att kontrollera att postnumret består av fem siffror med eventuellt mellanslag mellan tredje och fjärde siffran kräver en hel del kod... - ...om vi inte kapslar den publika egenskapen och använder ett __reguljärt uttryck__ vid valideringen av värdet. --- # Reguljärt uttryck till undsättning ``` function Address (addressLine, postalCode, city) { this.adressLine = addressLine this.city = city this.postalCode = postalCode } Object.defineProperty(Address.prototype, 'postalCode', { get: function () { return this._postalCode }, set: function (value) { if (!/^[1-9]\d{2} ?\d{2}$/.test(value)) { throw new Error('postalCode seems to be invalid.') } this._postalCode = value } }) let address1 = new Address('Storgatan 1', '123 45', 'Storstaden') // OK adress! let address2 = new Address('Lillgatan 1', 'ingen aning', 'Lillstaden') // Undantag kastas! ``` - Det reguljära uttrycket defineras av `/^[1-9]\d{2} ?\d{2}$/`. --- # Vad betyder `/^[1-9]\d{2} ?\d{2}$/`? - Reguljära uttryck hanteras av typen
`RegExp`
. - `^`, start av strängen. - `[1-9]`, exakt en förekomst av 1, 2, 3, 4, 5, 6, 7, 8 eller 9. - `\d{2}`, exakt två förekomster av 0 till 9. -
˽
?
, ingen eller en förekomst av ett mellanslag. - `\d{2}`, exakt två förekomster av 0 till 9. - `$`, slut på strängen. - Det finns två sätt att skapa `RegExp`-objekt på: ``` let regexp1 = /^[1-9]\d{2} ?\d{2}$/ // literal let regexp2 = new RegExp('^[1-9]\d{2} ?\d{2}$') // konstruktor ``` --- # Fånga undantag med [`try...catch`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch) - För att kasta ett undantag används `throw`. - Kod som kan leda till att ett undantag kastas placeras i ett `try`-block, som följs av ett... - ...`catch`-block innehållande kod som ska exekveras om ett undantag har kastats. ``` try { // Normalt programflöde i try-blocket. let address = new Address('Lillgatan 1', 'ingen aning', 'Lillstaden') // Undantag kastas! // Gör något med address2... } catch (e) { // Fångar undantaget. // Programflöde i catch-blocket om fel inträffat, d.v.s. om undantag kastats av try-blocket. concole.error(e.message) // Presenterar felmeddelandet "postalCode seems to be invalid.". } ``` --- # Olika sätt att lösa upphöjt problem ``` // imperative let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] for (let i = 0; i < arr.length; i += 1) { arr[i] = Math.pow(arr[i], 2) } console.log(arr) // OUTPUT: [ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81 ] // declarative with anonymous function expression arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] let sqrArr = arr.map(function(num) { return Math.pow(num, 2) }) console.log(sqrArr) // OUTPUT: [ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81 ] // declarative with arrow function (lambda expression) sqrArr = arr.map(num => Math.pow(num, 2)) console.log(sqrArr) // OUTPUT: [ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81 ] ``` - __OBS!__ En _"arrow function"_ kan inte användas för att skapa prototyp-funktioner (har att göra med hur `this` hanteras). --- # Vad är på gång? - [ECMAScript Next](http://kangax.github.io/compat-table/esnext/) ---