Webprogramozás
Horváth Győző
Egyetemi docens
1117 Budapest, Pázmány Péter sétány 1/c., 2.408-as szoba
Tel: (1) 372-2500/8469
horvath.gyozo@inf.elte.hu
document.querySelector('css selector')
document.querySelectorAll('css selector')
elem.addEventListener(típus, fgv)
typeof
operátorAdott érték típusa szövegesen
typeof undefined === "undefined"
typeof null === "object"
typeof true === 'boolean'
typeof 37 === 'number'
typeof 42n === 'bigint'
typeof NaN === 'number'
typeof 'bla' === 'string'
typeof {a: 1} === 'object'
typeof [1, 2, 4] === 'object' // Array.isArray()
typeof new Date() === 'object'
typeof function() {} === 'function'
Number.NaN
(NaN
)Number.POSITIVE_INFINITY
(Infinity
)Number.NEGATIVE_INFINITY
(-Infinity
)Number.isNaN(value)
Number.isFinite(value)
Number.isInteger(value)
Number.parseInt(str[, radix])
Number.parseFloat(str)
// NaN
const a = 'alma' / 2 // NaN
Number.isNaN(a) // true
3 + Number.NaN // NaN
// Infinity
const a = 10/0
isFinite(a) //false
// parseInt, parseFloat
Number.parseInt('123') //123
Number.parseInt('123', 10) //123
Number.parseInt('0101', 2) //5
Number.parseInt('alma', 10) //NaN
Number.parseInt('5alma', 10) //5
Number.parseFloat('4.54') //4.54
numObj.toExponential([fractionDigits])
numObj.toFixed([digits])
: tizedespont utáni számjegyek számanumObj.toPrecision([precision])
: számjegyek számanumObj.toString([radix])
// boxing: literal to numObj
3.toString() // error
(3).toString() // "3"
Number.parseInt(3).toString() // "3"
const n = 3
n.toString() // "3"
// példánymetódusok
(123.456).toExponential(2) // "1.23e+2"
(123.456).toFixed(2) // "123.46"
(123.456).toPrecision(2) // "1.2e+2"
(123.456).toPrecision(4) // "123.5"
(123).toString(2) // "1111011"
253-1-nél nagyobb egész számok ábrázolására
Operátorok: +
, -
, *
, /
, **
const bigint1 = 42n
const bigint2 = BigInt(42)
const bigint3 = BigInt("42")
const bigint4 = BigInt(Number.MAX_SAFE_INTEGER) // 9007199254740991n
const bigint5 = bigint4 + 1n // 9007199254740992n
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Calculating_Primes
function isPrime(p) {
for (let i = 2n; i * i <= p; i++) {
if (p % i === 0n) return false;
}
return true;
}
Date
objektumDate.now()
new Date(year, month, day [, hour, minute, second, millisecond]);
Date.parse(dateString)
: msgetMonth()
, getDay()
, stbsetMonth()
, setDay()
, stb.toLocaleString()
, toGMTString()
// Létrehozás
const d1 = new Date()
const d2 = new Date(2019, 0, 31, 3, 42, 0);
const d3 = new Date("2019-01-31T03:42:00");
const ms1 = Date.now();
const ms2 = Date.parse("2019-01-31T03:42:00");
// Műveletek
d2.getFullYear() // 2019
d3.setFullYear(2020)
d2.toLocaleString('hu-HU') // "2019. 01. 31. 3:42:00"
d2.toLocaleString('en-US') // "1/31/2019, 3:42:00 AM"
// Eltelt idő (ms-okban)
const delta = ms2 - ms1
charAt(i)
, charCodeAt(i)
indexOf(mit, honnan)
, lastIndexOf(mit, honnan)
localeCompare(mivel[, locale])
search(regexp)
, replace(mit, mivel)
, match(regexp)
, matchAll(regexp)
substr(honnan, hossz)
, substring(mettől, meddig)
, slice(mettől, meddig)
split(szeparátor)
startsWith(str)
, endsWith(str)
padStart(length[, str])
, padEnd(length[, str])
repeat(num)
trim()
, trimStart()
, trimEnd()
toLowerCase()
, toUpperCase()
, toLocaleLowerCase(locale)
, toLocaleUpperCase(locale)
'piros alma'.charAt(2) // "r"
'piros alma'.charCodeAt(2) // 114
'piros alma'.indexOf('alma') // 6
'piros alma'.localeCompare('piros körte') // -1
'piros alma'.replace('piros', 'sárga') // "sárga alma"
'piros alma'.substr(2, 3) // "ros"
'piros alma'.split(' ') // ["piros","alma"]
'piros alma'.startsWith('piros') // true
'piros alma'.padStart(15) // " piros alma"
' piros alma'.trim() // "piros alma"
'piros alma'.toUpperCase() // "PIROS ALMA"
encodeURI()
, decodeURI()
encodeURIComponent()
, decodeURIComponent()
const kod = encodeURIComponent('árvíztűrőtükörfúrógép');
//"%C3%A1rv%C3%ADzt%C5%B1r%C5%91t%C3%BCk%C3%B6rf%C3%BAr%C3%B3g%C3%A9p"
const dekod = decodeURIComponent(kod);
//"árvíztűrőtükörfúrógép"
const url = encodeURI('http://server.hu/útvonal szóközökkel');
//"http://server.hu/%C3%BAtvonal%20sz%C3%B3k%C3%B6z%C3%B6kkel"
/minta/flags
test(str)
→ logika értékexec(str)
→ tömbsearch(regexp)
replace(regexp, mire)
match(regexp)
, matchAll(regexp)
split(regexp)
/\d+/.test('alma') //false
/\d+/.test('alma123') //true
/alma/.test('piros alma kukacos'); // true
/alma$/.test('piros alma kukacos') //false
/^\w+/.test('piros alma') //true
/alma/i.test('Piros Alma') //true
"piros alma kukacos".replace(/os/, 'itott') //"piritott alma kukacos"
"piros alma kukacos".replace(/os/g, 'itott') //"piritott alma kukacitott"
"1a234 5b678 90"
.replace(/\D/g, '') // "1234567890"
.replace(/.{4}/g, '$& ') // "1234 5678 90"
"Horvath Gyozo".replace(/(\w+)\s(\w+)/i, "$2, $1") // "Gyozo, Horvath"
'Hófehérke és a 7 törpe meg az 1 herceg'.match(/\d+/g) // ["7", "1"]
/(\w+)\s(\w+)/ig.exec("Horvath Gyozo Horvath Emese")
// [
// 'Horvath Gyozo',
// 'Horvath',
// 'Gyozo',
// index: 0,
// input: 'Horvath Gyozo Horvath Emese',
// groups: undefined
// ]
Array.from("Horvath Gyozo Horvath Emese".matchAll(/(\w+)\s(\w+)/ig))
// [
// [
// 'Horvath Gyozo',
// 'Horvath',
// 'Gyozo',
// index: 0,
// input: 'Horvath Gyozo Horvath Emese',
// groups: undefined
// ],
// [
// 'Horvath Emese',
// 'Horvath',
// 'Emese',
// index: 14,
// input: 'Horvath Gyozo Horvath Emese',
// groups: undefined
// ]
// ]
sin(rad)
, asin(sz)
, cos(rad)
, acos(sz)
, tan(rad)
, atan(sz)
pow(alap, kit)
, exp(n)
, log(n)
, stb.random()
round(n)
, floor(n)
, ceil()
PI
E
SQRT2
LN2
, stb.Math.PI //3.141592653589793
Math.sin(90) //0.8939966636005579
Math.sin(90 * Math.PI / 180) //1
Math.random() //pl. 0.47057095554085615
Math.random() //pl. 0.5286946792885748
Math.round(1.6) //2
Math.floor(1.6) //1
pop()
, push(e)
, shift(e)
, unshift()
reverse()
splice(honnan, mennyit)
join(szeparátor)
indexOf(elem)
includes(elem)
const t = [1, 2, 3, 4, 5]
t.push(6) // [1, 2, 3, 4, 5, 6]
t.pop() // 6, [1, 2, 3, 4, 5]
t.unshift(0) // [0, 1, 2, 3, 4, 5]
t.shift() // 0, [1, 2, 3, 4, 5]
t.reverse() // [5, 4, 3, 2, 1]
t.sort() // [1, 2, 3, 4, 5]
t.splice(2, 1) // [5, 4, 2, 1]
t.join('###') // "5###4###2###1"
[1, 2].concat([3, 4]) // [1, 2, 3, 4]
[1, 2, 3, 4, 5].copyWithin(2, 0, 2) // [1, 2, 1, 2, 5]
[1, 2, 3].fill(4) // [4, 4, 4]
[1, 2, [3, 4]].flat() // [1, 2, 3, 4]
[1, 2, 3, 4].flatMap(x => [x * 2]) // [2, 4, 6, 8]
[1, 2, 3, 4, 5].slice(2, 4) // [ 3, 4 ]
const items = ['réservé', 'premier', 'cliché', 'communiqué', 'café', 'adieu']
items.sort(function (a, b) {
return a.localeCompare(b)
})
set(key, value)
get(key)
has(key)
delete(key)
size
keys()
, values()
, entries()
clear()
const map = new Map()
map.set('some', 'value')
map.get('some') // 'value'
map.has('some') // true
map.delete('some')
const map2 = new Map([['first', 1], ['second', 2]]);
for (const [key, value] of map2.entries()) {
console.log(key + ' = ' + value);
}
// 'first' = 1
// 'second' = 2
add(value)
has(value)
delete(value)
size
values()
clear()
const set = new Set()
set.add(1)
set.has(1) // true
set.delete(1)
const set2 = new Set([1, 2, 3, 4, 1, 2, 3]);
for (const value of set2) {
console.log(value);
}
// 1, 2, 3, 4
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set#Implementing_basic_set_operations
function isSuperset(set, subset) {
for (var elem of subset) {
if (!set.has(elem)) {
return false;
}
}
return true;
}
Böngésző API
setTimeout
timerId = setTimeout(fn, ms)
ms
ms múlvaclearTimeout(timerId)
timerId
-jú időzítő leállítása// Külön függvény
function tick() {
console.log('tick')
}
setTimeout(tick, 1000)
// Helyben függvény
setTimeout(function () {
console.log('tick')
}, 1000)
// Időzítő törlése
const timer = setTimeout(() => {}, 1000)
// do something, or even in an event:
clearTimeout(timer)
setInterval
timerId = setInterval(fn, ms)
ms
ms-onkéntclearInterval(timerId)
timerId
-jú időzítő leállítása// Külön függvény
function tick() {
console.log('tick')
}
setInterval(tick, 1000)
// Helyben függvény
setInterval(function () {
console.log('tick')
}, 1000)
// Időzítő törlése
const timer = setInterval(() => {}, 1000)
// do something, or even in an event:
clearInterval(timer)
Fizikai és logikai egységek
// math.js
const add = (a, b) => a + b
const multiply = (a, b) => a * b
// app.js
console.log(add(40, 2))
<body>
<!-- ... -->
<script src="math.js"></script>
<script src="app.js"></script>
</body>
// math.js
const add = (a, b) => a + b
const multiply = (a, b) => a * b
export { add, multiply }
// app.js
import { add } from "./math.js"
console.log(add(40, 2))
<body>
<!-- ... -->
<script type="module" src="app.js"></script>
</body>
// in-place export
export const add = (a, b) => a + b
export const multiply = (a, b) => a * b
// separate export
const add = (a, b) => a + b
const multiply = (a, b) => a * b
export { add, multiply }
// default export
export default const add = (a, b) => a + b
// rename exports
const add = (a, b) => a + b
const multiply = (a, b) => a * b
export { add as customAdd, multiply as customMultiply }
// export from module
export * from "./other.js"
// import entities
import { add, multiply } from "./math.js"
// import defaults
import add from "./math.js"
// rename imports
import { add as mathAdd } from "./math.js"
// import module object
import * as MyMath from "./math.js"
// import jus for side effects
import "./something.js"
// import URL
import * as MyMath from "http://some.where.hu/math.js"
npx serve
http://localhost:5000
// helper function
function range(n) { return Array.from({length: n}, (e, i) => i+1); }
// HTML generator
function genList(list) {
return `<ul>${list.map(e => `<li>${e}</li>`).join('')}</ul>`
}
// business logic
const add = (a, b) => a + b
// event handler
function onClick(e) {
// ...
}
Egységbe zárás
Globális változók és metódusok
let szam = 0
function novel() {
szam++
}
function init() {
szam = 0
}
novel()
console.log(szam)
Objektum, singleton
const jatek = {
szam: 0,
novel: function() {
this.szam++
},
init: function () {
this.szam = 0
}
}
jatek.init()
jatek.novel()
console.log(jatek.szam)
Osztály
class Jatek {
constructor() {
this.szam = 0
}
novel() {
this.szam++
}
}
const jatek = new Jatek()
jatek.novel()
console.log(jatek.szam)
Függvény, saját hatókörrel (felfedő modul minta)
const jatek = (function () {
let szam = 0
function novel() {
szam++
}
function init() {
szam = 0
}
function getSzam() {
return szam
}
return {
novel: novel,
getSzam: getSzam
}
})()
jatek.novel()
console.log(jatek.getSzam())
Modul, függvény
// game.js
let szam = 0
function novel() {
szam++
}
function init() {
szam = 0
}
function getSzam() {
return szam
}
export { novel, init, getSzam }
// main.js
import { novel, init, getSzam } from "./game.js"
novel()
console.log(getSzam())
Modul, osztály
// game.js
export class Jatek {
constructor() {
this.szam = 0;
}
novel() {
this.counter += 1;
}
}
import { Jatek } from './game.js';
const jatek = new Jatek();
jatek.novel();
console.log(jatek.szam);
Adattárolás
Új elem:
<input>
<button>Hozzáad</button>
<ul></ul>
document.querySelector("button").addEventListener("click", ujElemKattintas);
function ujElemKattintas(e) {
// beolvasás
const ujelem = document.querySelector('input').value
// kiírás
document.querySelector('ul').innerHTML += `<li>${ujelem}</li>`
}
Új elem:
<input>
<button>Hozzáad</button>
<ul></ul>
document.querySelector("button").addEventListener("click", ujElemKattintas);
function ujElemKattintas(e) {
// beolvasás
const ujelem = document.querySelector('input').value
// kiírás
const li = document.createElement('li')
li.innerHTML = ujelem
document.querySelector('ul').appendChild(li)
}
Todo lista elemei
document.querySelector("button").addEventListener("click", ujElemKattintas);
function ujElemKattintas(e) {
// beolvasás
const ujelem = document.querySelector('input').value
const lista =
Array.from(document.querySelectorAll('li'))
.map(li => li.innerText)
// feldolgozás
lista.push(ujelem)
console.log(lista)
// kiírás
const li = document.createElement('li')
li.innerHTML = ujelem
document.querySelector('ul').appendChild(li)
}
const lista = []
document.querySelector("button").addEventListener("click", ujElemKattintas);
function ujElemKattintas(e) {
// beolvasás
const ujelem = document.querySelector('input').value
// feldolgozás
lista.push(ujelem)
console.log(lista)
// kiírás
const li = document.createElement('li')
li.innerHTML = ujelem
document.querySelector('ul').appendChild(li)
}
A felület mint az adat leképezése (függvény)
const lista = []
document.querySelector("button").addEventListener("click", ujElemKattintas);
function ujElemKattintas(e) {
// beolvasás
const ujelem = document.querySelector('input').value
// feldolgozás
lista.push(ujelem)
// kiírás
document.querySelector('ul').innerHTML = genLista(lista)
}
function genLista(lista) {
return `${lista.map(e => `<li>${e}</li>`).join('')}`
}
Felület kezelése
Alap funkcionalitás, kattintás
Tábla generálása
<table>
<tr>
<td>
<div class="card">
<div class="front">1</div>
<div class="back"></div>
</div>
</td>
</tr>
</table>
const table = document.querySelector('table')
table.addEventListener('click', onClick)
function onClick(e) {
const card = e.target.closest('.card')
if (this.contains(card)) {
card.classList.toggle('flipped')
}
}
document.querySelector('button').addEventListener('click', onButtonClick)
function onButtonClick(e) {
const n = parseInt(document.querySelector('input[type=number]').value)
m = genMatrix(n)
table.innerHTML = genTable(m);
}
function random(a, b) {
return Math.floor(Math.random() * (b - a + 1)) + a
}
function genMatrix(n) {
return (new Array(n)).fill(0).map(() => (new Array(n)).fill(0).map(() => random(1, 99)))
}
function genTable(m) {
return `${m.map(row => `
<tr>
${row.map(cell => `
<td>
<div class="card">
<div class="front">${cell}</div>
<div class="back"></div>
</div>
</td>
`).join('')}
</tr>
`).join('')}`
}
1 kattintásra több is változik → újrarajzolás
let m;
const selected = [];
const table = document.querySelector('table')
table.addEventListener('click', onClick)
function onClick(e) {
const card = e.target.closest('.card')
if (this.contains(card)) {
const {x, y} = xyCoord(card)
m[y][x].flipped = !m[y][x].flipped
selected.push({x, y})
if (selected.length > 2) {
const [{x:x1, y:y1}, {x:x2, y:y2}] = selected.splice(0, 2)
m[y1][x1].flipped = !m[y1][x1].flipped
m[y2][x2].flipped = !m[y2][x2].flipped
}
table.innerHTML = genTable(m);
}
}
document.querySelector('button').addEventListener('click', onButtonClick)
function onButtonClick(e) {
const n = parseInt(document.querySelector('input[type=number]').value)
m = genMatrix(n)
table.innerHTML = genTable(m);
}
function xyCoord(card) {
const td = card.closest('td')
const x = td.cellIndex
const tr = td.parentNode
const y = tr. sectionRowIndex
return {x, y}
}
function random(a, b) {
return Math.floor(Math.random() * (b - a + 1)) + a
}
function genMatrix(n) {
return (new Array(n)).fill(0).map(() => (new Array(n)).fill(0).map(() => ({
value: random(1, 99),
flipped: false
})))
}
function genTable(m) {
return `${m.map(row => `
<tr>
${row.map(cell => `
<td>
<div class="card ${cell.flipped ? 'flipped' : ''}">
<div class="front">${cell.value}</div>
<div class="back"></div>
</div>
</td>
`).join('')}
</tr>
`).join('')}`
}
Animáció, újrarajzolás, hibás
.card.flipped {
animation: flip 1s forwards;
}
@keyframes flip {
100% {
transform: rotateY(0deg);
}
}
function onClick(e) {
const card = e.target.closest('.card')
if (this.contains(card)) {
const {x, y} = xyCoord(card)
m[y][x].flipped = !m[y][x].flipped
selected.push({x, y})
if (selected.length > 2) {
const [{x:x1, y:y1}, {x:x2, y:y2}] = selected.splice(0, 2)
m[y1][x1].flipped = !m[y1][x1].flipped
m[y2][x2].flipped = !m[y2][x2].flipped
}
table.innerHTML = genTable(m);
}
}
Animáció, imperatív
function onClick(e) {
const card = e.target.closest('.card')
if (this.contains(card)) {
const { x, y } = xyCoord(card)
m[y][x].flipped = !m[y][x].flipped
selected.push({ x, y })
if (selected.length > 2) {
const [{ x: x1, y: y1 }, { x: x2, y: y2 }] = selected.splice(0, 2)
m[y1][x1].flipped = !m[y1][x1].flipped
m[y2][x2].flipped = !m[y2][x2].flipped
document.querySelector(`table tr:nth-child(${y1+1}) td:nth-child(${x1+1}) .card`).classList.toggle('flipped', m[y1][x1].flipped)
document.querySelector(`table tr:nth-child(${y2+1}) td:nth-child(${x2+1}) .card`).classList.toggle('flipped', m[y2][x2].flipped)
}
selected.forEach(s => {
document.querySelector(`table tr:nth-child(${s.y+1}) td:nth-child(${s.x+1}) .card`).classList.toggle('flipped', m[s.y][s.x].flipped)
})
}
}
Animáció, imperatív
function onClick(e) {
const card = e.target.closest('.card')
if (this.contains(card)) {
const { x, y } = xyCoord(card)
m[y][x].flipped = !m[y][x].flipped
selected.push(card)
if (selected.length > 2) {
const [card1, card2] = selected.splice(0, 2)
const {x:x1, y:y1} = xyCoord(card1)
const {x:x2, y:y2} = xyCoord(card2)
m[y1][x1].flipped = !m[y1][x1].flipped
m[y2][x2].flipped = !m[y2][x2].flipped
card1.classList.toggle('flipped', m[y1][x1].flipped)
card2.classList.toggle('flipped', m[y2][x2].flipped)
}
selected.forEach(s => {
const {x, y} = xyCoord(s)
s.classList.toggle('flipped', m[y][x].flipped)
})
}
}