Week 1
๐ ๋ํ ๋ถ์: ์ฌ์ฉ์๋์ ์ง๋ฌธ ํจํด
์ง๋ฌธ ์นดํ ๊ณ ๋ฆฌ๋ณ ๋ถ๋ฅ
| ์นดํ ๊ณ ๋ฆฌ | ์ง๋ฌธ ๋ด์ฉ | ๋น๋ |
|---|---|---|
| JavaScript ๊ธฐ๋ณธ | Array methods (map, filter, sort), localeCompare | ๐ด๐ด๐ด |
| Svelte ๊ฐ๋ | Reactive statement ($:), ์ธ์ ์ฌ์ฉ? | ๐ด๐ด๐ด |
| ๋ฐ์ดํฐ ํ๋ฆ | MQTT ์ค์๊ฐ ์ ๋ฐ์ดํธ, ์ ๋ ฌ ํ์ด๋ฐ | ๐ด๐ด |
| ๋ธ๋ผ์ฐ์ API | history.replaceState, localStorage | ๐ด๐ด |
| ์ํคํ ์ฒ | App.svelte ๋์, routes ๋ฐฐ์ด ์์ | ๐ด |
| ๋๋ฒ๊น | โ์ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ๋์ฌ๊น?โ, Edge case | ๐ด |
๐ฏ ์ฝ์ ๋ถ์
- JavaScript ๋ฐฐ์ด/๊ฐ์ฒด ๋ฉ์๋ ์ดํด ๋ถ์กฑ ๐ด๐ด๐ด
์ฆ๊ฑฐ:
- โalertData์์ ์ ๋ฐฐ์ด ๋ง๋๋ ๋ฐฉ๋ฒ?โ
- โlocaleCompare๊ฐ ๋ญ์ผ?โ
- โparseInt() vs localeCompare ์ฐจ์ด?โ
- โ์ ๋ ฌ ์ฃผ์์ฒ๋ฆฌํด๋ ๊ฒฐ๊ณผ๊ฐ ๊ฐ๋๋ผโ
๋ฌธ์ :
- Array.map(), filter(), reduce() ๋์ ์๋ฆฌ ๋ถ๋ช ํ
- Set์ ์์ ๋ณด์ฅ ๊ฐ๋ ๋ชจ๋ฆ
- ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ ์ดํด ๋ถ์กฑ
- Svelte Reactive Statement ๊ฐ๋ ํผ๋ ๐ด๐ด๐ด
์ฆ๊ฑฐ:
- โ$: ์์ด ๊ตฌํํ ์ ์์๊น?โ
- โ์๋์ด๋ $:๋ฅผ ์ซ์ดํ๋ ๊ฒ ๊ฐ์โ
- โMQTT ๋ฐ์ดํฐ๊ฐ ์ถ๊ฐ๋๋ฉด ์๋์ผ๋ก ์ ๋ ฌ ์ ๋์ง?โ
๋ฌธ์ :
- $:์ ๋์ ์์ ๋ถ๋ช ํ
- ์ธ์ ์ฌ์ฉํด์ผ ํ๋์ง ํ๋จ ๋ชป ํจ
- Reactive vs Imperative ์ฐจ์ด ์ดํด ๋ถ์กฑ
- ๋ฐ์ดํฐ ํ๋ฆ๊ณผ ํ์ด๋ฐ ์ดํด ๋ถ์กฑ ๐ด๐ด
์ฆ๊ฑฐ:
- โ์ต์ด ํ์ด์ง ๋ก๋ ์ alertData๊ฐ ์๋์ผ๋ก ์ ๋ ฌ ์ ๋์ง?โ
- โMQTT๋ก ๋ฐ์ดํฐ ์ถ๊ฐํ๋ฉด ์ด๋ป๊ฒ ๋๋?โ
๋ฌธ์ :
- ์ด๊ธฐ ์คํ vs ๋ฐํ์ ์ ๋ฐ์ดํธ ์ฐจ์ด ๋ชจ๋ฆ
- ๋ถ๋ณ์ฑ(Immutability) ๊ฐ๋ ๋ถ์กฑ
- App.svelte ๊ฐ์ โํฐ ๊ทธ๋ฆผโ ์ดํด ๋ถ์กฑ ๐ด
์ฆ๊ฑฐ:
- โApp.svelte๊ฐ ํ๋ ์ผ์ด ์ดํด๊ฐ ์ ๊ฐโ
- โroutes[2]๋ ์๋ ๊ฑฐ ์๋๊ฐ?โ
๋ฌธ์ :
- ์ปดํฌ๋ํธ ์๋ช ์ฃผ๊ธฐ ์ดํด ๋ถ์กฑ
- ๋ฐฐ์ด ์ธ๋ฑ์ฑ ๊ธฐ๋ณธ ๊ฐ๋ ๋ถ์กฑ
๐ช ๊ฐ์ ๋ถ์
โ ์ํ๋ ๊ฒ๋ค
- ์ง๋ฌธ์ ์ ํจ: ์ดํด ์ ๋๋ฉด ๋ฐ๋ก ๋ฌผ์ด๋ด
- ์ง์ ํ ์คํธ: ์ฝ๋ ์์ ํ๊ณ ์ฝ์ ์ฐ์ด๋ด
- Step-by-step ์ฌ๊ณ : โํ ์ค์ฉ ๋์ง์ด ๊ฐ๋ฉด์ ๋์ ์ ๊ฒโ
- ํผ๋๋ฐฑ ์์ฉ: ์๋์ด ์กฐ์ธ ์ ๊ทน ๋ฐ์
๐ ๋ง์ถคํ ํ์ต ์ปค๋ฆฌํ๋ผ
๐ Phase 1: JavaScript ๊ธฐ์ด ๋ค์ง๊ธฐ (1-2์ฃผ)
Week 1: ๋ฐฐ์ด ์๋ฒฝ ์ ๋ณต
Day 1-2: ๋ฐฐ์ด ๋ฉ์๋ ๊ธฐ๋ณธ
- MDN: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/map
- MDN: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
- MDN: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
์ค์ต ๊ณผ์ : // ๊ณผ์ 1: alertData์์ ์ธต ๋ชฉ๋ก ์ถ์ถ (์ค๋ณต ์ ๊ฑฐ) const alertData = [ { floorName: โ1Fโ, status: โAlertโ }, { floorName: โ2Fโ, status: โClosedโ }, { floorName: โ1Fโ, status: โOfflineโ }, ];
// TODO: Set ์ฌ์ฉํด์ [โ1Fโ, โ2Fโ] ๋ง๋ค๊ธฐ const floors = [โฆnew Set(alertData.map(a => a.floorName))]; console.log(floors);
// ๊ณผ์ 2: Status๋ณ ๊ฐ์ ์ธ๊ธฐ // ๊ฒฐ๊ณผ: { Alert: 1, Closed: 1, Offline: 1 } const statusCount = alertData.reduce((acc, item) => { acc[item.status] = (acc[item.status] || 0) + 1; return acc; }, {});
๋ฐฉ๋ฒ 1: ์ด์ค reduce ์ฌ์ฉ (๊ณ ๊ธ)
๊ฐ ๊ฑด๋ฌผ์ ์ธต ๋ฐฐ์ด์ ์ํํ๋ฉด์ alertCount๋ฅผ ๋์ :
function calculateTotalAlerts() {
const total = MOCK_CENTER_ALARM_STAT.reduce((sum, buildingObj) => {
// 1. ๊ฑด๋ฌผ ๊ฐ์ฒด์์ ๊ฑด๋ฌผ๋ช
ํค ์ฐพ๊ธฐ (A๋, B๋)
const buildingKey = Object.keys(buildingObj).find(key => key !== 'total');
const floors = buildingObj[buildingKey]; // ์ธต ๋ฐฐ์ด
// 2. ๊ฐ ์ธต์ alertCount ํฉ์ฐ
const buildingTotal = floors.reduce((floorSum, floor) => {
return floorSum + floor.alertCount;
}, 0);
return sum + buildingTotal;
}, 0);
return total;
}
๋๋ฒ๊น
์ฉ console.log ์ถ๊ฐ ๋ฒ์ :
function calculateTotalAlerts() {
const total = MOCK_CENTER_ALARM_STAT.reduce((sum, buildingObj) => {
const buildingKey = Object.keys(buildingObj).find(key => key !== 'total');
const floors = buildingObj[buildingKey];
console.log('๊ฑด๋ฌผ:', buildingKey, '์ธต ๊ฐ์:', floors.length);
const buildingTotal = floors.reduce((floorSum, floor) => {
console.log(' ์ธต:', floor.floorName, 'alertCount:', floor.alertCount);
return floorSum + floor.alertCount;
}, 0);
console.log('๊ฑด๋ฌผ ํฉ๊ณ:', buildingTotal);
return sum + buildingTotal;
}, 0);
console.log('๐ฅ ์ต์ข
์ ์ฒด ํฉ๊ณ:', total);
return total;
}
---
๋ฐฉ๋ฒ 2: forEach ์ค์ฒฉ (์ด๋ณด์ ์นํ์ )
reduce๊ฐ ์ด๋ ต๋ค๋ฉด forEach๋ก ๋จผ์ ์ฐ์ต:
function calculateTotalAlerts() {
let total = 0;
MOCK_CENTER_ALARM_STAT.forEach(buildingObj => {
// ๊ฑด๋ฌผ ํค ์ฐพ๊ธฐ
const buildingKey = Object.keys(buildingObj).find(key => key !== 'total');
const floors = buildingObj[buildingKey];
// ๊ฐ ์ธต์ alertCount ๋ํ๊ธฐ
floors.forEach(floor => {
console.log('์ถ๊ฐ:', floor.floorName, floor.alertCount);
total += floor.alertCount;
});
});
console.log('์ต์ข
ํฉ๊ณ:', total);
return total;
}
---
๋ฐฉ๋ฒ 3: flatMap ์ฌ์ฉ (๋ชจ๋ JavaScript)
๊ฐ์ฅ ๊น๋ํ ๋ฐฉ๋ฒ:
function calculateTotalAlerts() {
const total = MOCK_CENTER_ALARM_STAT
.flatMap(buildingObj => {
const buildingKey = Object.keys(buildingObj).find(key => key !== 'total');
return buildingObj[buildingKey]; // ๋ชจ๋ ์ธต์ ํ๋์ ๋ฐฐ์ด๋ก ํํํ
})
.reduce((sum, floor) => sum + floor.alertCount, 0);
return total;
}
---
๐ฏ ํ์ต ํฌ์ธํธ
Object.keys() ์ดํดํ๊ธฐ
const obj = { A๋: [...], total: 9 };
Object.keys(obj); // ['A๋', 'total']
find()๋ก ์กฐ๊ฑด ํํฐ๋ง
const keys = ['A๋', 'total'];
const buildingKey = keys.find(key => key !== 'total'); // 'A๋'
์ด์ค reduce์ ํ๋ฆ
์ธ๋ถ reduce: ๊ฑด๋ฌผ๋ณ ์ํ (A๋ โ B๋)
โ
๋ด๋ถ reduce: ์ธต๋ณ ์ํ (1F โ 2F โ 3F โ 4F)
โ
alertCount ๋์
---
๐ก ์ถ์ฒ ํ์ต ์์
1. ๋จผ์ ๋ฐฉ๋ฒ 2 (forEach)๋ก ์์ โ ๋ก์ง ์ดํดํ๊ธฐ ์ฌ์
2. ๋ฐฉ๋ฒ 1 (์ด์ค reduce)๋ก ๋์ โ ํจ์ํ ํ๋ก๊ทธ๋๋ฐ ์ฐ์ต
3. ๋ฐฉ๋ฒ 3 (flatMap) โ ๊ณ ๊ธ ๊ธฐ๋ฒ ๋ง๋ณด๊ธฐ
function getFloorAlertCount(bldgName, floorID) {
// 1. MOCK_CENTER_ALARM_STAT์์ ๊ฑด๋ฌผ ์ฐพ๊ธฐ
// 2. ๊ฑด๋ฌผ์ ์ธต ๋ฐฐ์ด์์ floorID ๋งค์นญ
// 3. alertCount ๋ฐํ (์์ผ๋ฉด 0)
}
ํ
ํ๋ฆฟ์์ ์ฌ์ฉ:
{#each bldg.floorList || [] as floor}
<div class="text-center fw-bold text-mute">
{getFloorAlertCount(bldg.bldgName, floor.floorID)}
</div>
{/each}
Day 3-4: ์ ๋ ฌ๊ณผ ๋น๊ต
- MDN: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
- MDN: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare
์ค์ต ๊ณผ์ : // ๊ณผ์ 3: ๋ค์ํ ์ ๋ ฌ ๋ฐฉ๋ฒ ๋น๊ต const floors = [โ10Fโ, โ2Fโ, โ1Fโ, โB1โ, โRoofโ];
// ๋ฐฉ๋ฒ 1: ๊ธฐ๋ณธ ์ ๋ ฌ (๋ฌธ์์ด) console.log([โฆfloors].sort()); // ๊ฒฐ๊ณผ: [โ1Fโ, โ10Fโ, โ2Fโ, โB1โ, โRoofโ] โ 10F๊ฐ 2F ์์!
// ๋ฐฉ๋ฒ 2: localeCompare console.log([โฆfloors].sort((a, b) => a.localeCompare(b))); // ๊ฒฐ๊ณผ: ๊ฐ์
// ๋ฐฉ๋ฒ 3: localeCompare + numeric console.log([โฆfloors].sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))); // ๊ฒฐ๊ณผ: [โ1Fโ, โ2Fโ, โ10Fโ, โB1โ, โRoofโ] โ ์ฌ๋ฐ๋ฅธ ์์!
// ๊ณผ์ 4: ์ ์ด๋ฐ ์ฐจ์ด๊ฐ ์๊ธฐ๋์ง ์ดํดํ๊ธฐ
Day 5: Set๊ณผ ์์
- MDN: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Set
- ๋ธ๋ก๊ทธ: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Set#%EC%84%A4%EB%AA%85
์ค์ต ๊ณผ์ : // ๊ณผ์ 5: Set์ ์์ ์ดํดํ๊ธฐ const data = [ { time: โ09:00:02โ, floor: โ3Fโ }, { time: โ09:00:01โ, floor: โ1Fโ }, { time: โ09:00:01โ, floor: โ2Fโ }, ];
// Q: Set์ ์ฝ์ ์์๋ฅผ ๋ณด์ฅํ๋ค. ๊ฒฐ๊ณผ๋? const floors1 = [โฆnew Set(data.map(a => a.floor))]; console.log(โ์ ๋ ฌ ์ :โ, floors1); // [โ3Fโ, โ1Fโ, โ2Fโ]
// Q: ๋ฐ์ดํฐ๋ฅผ ๋จผ์ ์ ๋ ฌํ๋ฉด? const sortedData = data.sort((a, b) => a.floor.localeCompare(b.floor, undefined, { numeric: true })); const floors2 = [โฆnew Set(sortedData.map(a => a.floor))]; console.log(โ์ ๋ ฌ ํ:โ, floors2); // [โ1Fโ, โ2Fโ, โ3Fโ]
// ๊ฒฐ๋ก : Set์ ์์๋ฅผ ๋ณด์ฅํ์ง๋ง, ์ ๋ ฅ ์์๋ฅผ ๋ณด์ฅํ๋ค!
Week 2: ๊ฐ์ฒด์ ์ฐธ์กฐ
Day 1-2: ์์ ๋ณต์ฌ vs ๊น์ ๋ณต์ฌ
- MDN: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Spread_syntax
- MDN: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
์ค์ต ๊ณผ์ : // ๊ณผ์ 6: ๋ถ๋ณ์ฑ ์ดํดํ๊ธฐ let alertData = [ { time: โ09:00:01โ, status: โAlertโ } ];
// โ ์๋ชป๋ ๋ฐฉ๋ฒ (์๋ณธ ๋ณ๊ฒฝ) alertData.push({ time: โ09:00:02โ, status: โClosedโ });
// โ ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ (์ ๋ฐฐ์ด ์์ฑ) alertData = [โฆalertData, { time: โ09:00:02โ, status: โClosedโ }];
// Svelte์์๋ ์ ํ์๋ฅผ ์ ํธํ ๊น? (๋ฐ์์ฑ ๋๋ฌธ!)
Day 3-5: ๋ธ๋ผ์ฐ์ API
- MDN: https://developer.mozilla.org/ko/docs/Web/API/History_API
- MDN: https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage
์ค์ต ๊ณผ์ : // ๊ณผ์ 7: URL ๋ณ๊ฒฝ ์์ด ์ํ ์ ๋ฐ์ดํธ // ํ์ฌ URL: http://localhost:5173/floor/1?spaceID=3
// history.replaceState๋ก ์ฟผ๋ฆฌ์คํธ๋ง ์ ๊ฑฐ const newUrl = window.location.pathname; window.history.replaceState(null, โโ, newUrl); // ๊ฒฐ๊ณผ: http://localhost:5173/floor/1
// ๊ณผ์ 8: localStorage ํ์ฉ localStorage.setItem(โselectedFloorโ, โ2Fโ); const floor = localStorage.getItem(โselectedFloorโ); console.log(floor); // โ2Fโ
๐ Phase 2: Svelte ํต์ฌ ๊ฐ๋ (1์ฃผ)
Day 1-3: Reactive Statements ์์ ์ ๋ณต
- https://svelte.dev/tutorial/reactive-declarations
- https://svelte.dev/docs/svelte-components#script-3-$-marks-a-statement-as-reactive
์ค์ต ๊ณผ์ : // ๊ณผ์ 9: $:์ ๋์ ์์ ์ดํด let count = 0;
// Q1: ์ด ์ฝ๋๋ ์ธ์ ์คํ๋ ๊น? $: doubled = count * 2; $: console.log(โcount changed:โ, count);
// Q2: ๋ฒํผ ํด๋ฆญ ์ ๋ช ๋ฒ ์คํ๋ ๊น? function increment() { count += 1; count += 1; count += 1; } // ๋ต: console.log๋ 1๋ฒ๋ง ์คํ! (Svelte๊ฐ batch ์ฒ๋ฆฌ)
// ๊ณผ์ 10: ์์กด์ฑ ์ดํด let firstName = โJohnโ; let lastName = โDoeโ;
$: fullName = ${firstName} ${lastName};
// Q: firstName๋ง ๋ฐ๋๋ฉด? โ fullName ์ฌ๊ณ์ฐ
// Q: lastName๋ง ๋ฐ๋๋ฉด? โ fullName ์ฌ๊ณ์ฐ
// Q: ๋ ๋ค ์ ๋ฐ๋๋ฉด? โ ์ฌ๊ณ์ฐ ์ ํจ
Day 4-5: ์๋ช ์ฃผ๊ธฐ
- https://svelte.dev/tutorial/onmount
- https://svelte.dev/tutorial/ondestroy
์ค์ต ๊ณผ์ : // ๊ณผ์ 11: onMount vs $: ์ฐจ์ด let data = [];
// ๋ฐฉ๋ฒ 1: onMount onMount(() => { data = fetchData(); // 1๋ฒ๋ง ์คํ });
// ๋ฐฉ๋ฒ 2: $: $: { data = fetchData(); // data๊ฐ ๋ฐ๋ ๋๋ง๋ค ์คํ (๋ฌดํ ๋ฃจํ!) }
// Q: ์ธ์ onMount๋ฅผ ์ฐ๊ณ , ์ธ์ $:๋ฅผ ์ธ๊น?
๐ Phase 3: ์ค์ ํจํด (์งํ ์ค)
์ง๊ธ ์์ ํ๋ ํ๋ก์ ํธ๋ก ํ์ต
ํจํด 1: MQTT ์ค์๊ฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ // โ ์ด๋ณด์ ์ฝ๋ let alertData = [โฆ].sort(โฆ); // ์ด๊ธฐ๋ง ์ ๋ ฌ
// โ ํ๋ก ์ฝ๋ let alertData = [โฆ]; $: sortedData = alertData.slice().sort(โฆ); // ํญ์ ์ ๋ ฌ
ํจํด 2: ์บ์ค์ผ์ด๋ฉ ํํฐ // โ ์ด๋ณด์ ์ฝ๋ function updateSpaceList() { โฆ } function updateFilteredData() { โฆ }
// โ ํ๋ก ์ฝ๋ $: spaceList = selectedFloor === โallโ ? โฆ : โฆ; $: filteredData = alertData.filter(โฆ);
๐ 2์ฃผ ํ์ต ํ๋
Week 1: JavaScript ๊ธฐ์ด
์: Array.map(), filter() ์ฐ์ต ํ: Array.reduce() ์ฐ์ต ์: ์ ๋ ฌ (sort, localeCompare) ๋ชฉ: Set, ์์ ๋ณด์ฅ ๊ฐ๋ ๊ธ: ๋ณต์ต + ํด์ฆ ์ฃผ๋ง: ์ค์ ๊ณผ์ (Bldg.svelte ๋ฆฌํฉํ ๋ง)
Week 2: Svelte + ์ค์
์: Reactive statements ($:) ํ: $: ์์กด์ฑ ์ถ์ ์: onMount, onDestroy ๋ชฉ: ์ค์ ํจํด (MQTT) ๊ธ: EventLog.svelte ์ง์ ๊ตฌํ ์ฃผ๋ง: ์ ์ฒด ๋ณต์ต
๐ฏ ํ์ต ๋ฐฉ๋ฒ ๊ถ์ฅ
- MDN ๋ฌธ์ ์ฝ๋ ๋ฒ
1๏ธโฃ ์์ ๋ถํฐ ์ฝ๊ธฐ (์ด๋ก ์ ๋์ค์) 2๏ธโฃ ์ฝ์์์ ์ง์ ์คํ 3๏ธโฃ ๋ณํํด๋ณด๊ธฐ (์ซ์ ๋ฐ๊พธ๊ธฐ, ์กฐ๊ฑด ๋ฐ๊พธ๊ธฐ) 4๏ธโฃ ์ด๋ก ์ฝ๊ธฐ 5๏ธโฃ ์ค์ ํ๋ก์ ํธ์ ์ ์ฉ
- ๋งค์ผ 30๋ถ ์ฝ๋ฉ ์ฑ๋ฆฐ์ง
// ๋งค์ผ ์์นจ ๋ฃจํด const data = [/* ๋๋ค ๋ฐ์ดํฐ */];
// Day 1: map ์ฌ์ฉํด์ ํน์ ํ๋๋ง ์ถ์ถ // Day 2: filter ์ฌ์ฉํด์ ์กฐ๊ฑด ํํฐ๋ง // Day 3: reduce ์ฌ์ฉํด์ ๊ทธ๋ฃนํ // โฆ
- ์๋์ด์๊ฒ ์ง๋ฌธํ๊ธฐ ์ ์ฒดํฌ๋ฆฌ์คํธ
โ MDN ๋ฌธ์ ์ฝ์ด๋ดค๋๊ฐ? โ ์ฝ์์์ ํ ์คํธํด๋ดค๋๊ฐ? โ ์๋ฌ ๋ฉ์์ง๋ฅผ ๊ตฌ๊ธ๋งํด๋ดค๋๊ฐ? โ ๋น์ทํ ์ฝ๋๋ฅผ ํ๋ก์ ํธ์์ ์ฐพ์๋ดค๋๊ฐ?
๐ ์ฒซ ์ฃผ ์์ํ๊ธฐ
์ค๋ ๋น์ฅ ์์ํ ์ ์๋ ๊ฒ:
- MDN Array.map() ์ฝ๊ธฐ (10๋ถ)
- ์ฝ์ ์ด๊ณ ๊ณผ์ 1 ํ๊ธฐ (20๋ถ)
- Bldg.svelte์์ map() ์ฐพ์๋ณด๊ธฐ (10๋ถ)
์ด 40๋ถ์ด๋ฉด ์ฒซ ์คํ ์๋ฃ!
โ ๐ ๋ํ ๋ถ์: ์ฌ์ฉ์๋์ ์ง๋ฌธ ํจํด
์ง๋ฌธ ์นดํ ๊ณ ๋ฆฌ๋ณ ๋ถ๋ฅ
| ์นดํ ๊ณ ๋ฆฌ | ์ง๋ฌธ ๋ด์ฉ | ๋น๋ |
|---|---|---|
| JavaScript ๊ธฐ๋ณธ | Array methods (map, filter, sort), localeCompare | ๐ด๐ด๐ด |
| Svelte ๊ฐ๋ | Reactive statement ($:), ์ธ์ ์ฌ์ฉ? | ๐ด๐ด๐ด |
| ๋ฐ์ดํฐ ํ๋ฆ | MQTT ์ค์๊ฐ ์ ๋ฐ์ดํธ, ์ ๋ ฌ ํ์ด๋ฐ | ๐ด๐ด |
| ๋ธ๋ผ์ฐ์ API | history.replaceState, localStorage | ๐ด๐ด |
| ์ํคํ ์ฒ | App.svelte ๋์, routes ๋ฐฐ์ด ์์ | ๐ด |
| ๋๋ฒ๊น | โ์ ๊ฐ์ ๊ฒฐ๊ณผ๊ฐ ๋์ฌ๊น?โ, Edge case | ๐ด |
๐ฏ ์ฝ์ ๋ถ์
- JavaScript ๋ฐฐ์ด/๊ฐ์ฒด ๋ฉ์๋ ์ดํด ๋ถ์กฑ ๐ด๐ด๐ด
์ฆ๊ฑฐ:
- โalertData์์ ์ ๋ฐฐ์ด ๋ง๋๋ ๋ฐฉ๋ฒ?โ
- โlocaleCompare๊ฐ ๋ญ์ผ?โ
- โparseInt() vs localeCompare ์ฐจ์ด?โ
- โ์ ๋ ฌ ์ฃผ์์ฒ๋ฆฌํด๋ ๊ฒฐ๊ณผ๊ฐ ๊ฐ๋๋ผโ
๋ฌธ์ :
- Array.map(), filter(), reduce() ๋์ ์๋ฆฌ ๋ถ๋ช ํ
- Set์ ์์ ๋ณด์ฅ ๊ฐ๋ ๋ชจ๋ฆ
- ์ ๋ ฌ ์๊ณ ๋ฆฌ์ฆ ์ดํด ๋ถ์กฑ
- Svelte Reactive Statement ๊ฐ๋ ํผ๋ ๐ด๐ด๐ด
์ฆ๊ฑฐ:
- โ$: ์์ด ๊ตฌํํ ์ ์์๊น?โ
- โ์๋์ด๋ $:๋ฅผ ์ซ์ดํ๋ ๊ฒ ๊ฐ์โ
- โMQTT ๋ฐ์ดํฐ๊ฐ ์ถ๊ฐ๋๋ฉด ์๋์ผ๋ก ์ ๋ ฌ ์ ๋์ง?โ
๋ฌธ์ :
- $:์ ๋์ ์์ ๋ถ๋ช ํ
- ์ธ์ ์ฌ์ฉํด์ผ ํ๋์ง ํ๋จ ๋ชป ํจ
- Reactive vs Imperative ์ฐจ์ด ์ดํด ๋ถ์กฑ
- ๋ฐ์ดํฐ ํ๋ฆ๊ณผ ํ์ด๋ฐ ์ดํด ๋ถ์กฑ ๐ด๐ด
์ฆ๊ฑฐ:
- โ์ต์ด ํ์ด์ง ๋ก๋ ์ alertData๊ฐ ์๋์ผ๋ก ์ ๋ ฌ ์ ๋์ง?โ
- โMQTT๋ก ๋ฐ์ดํฐ ์ถ๊ฐํ๋ฉด ์ด๋ป๊ฒ ๋๋?โ
๋ฌธ์ :
- ์ด๊ธฐ ์คํ vs ๋ฐํ์ ์ ๋ฐ์ดํธ ์ฐจ์ด ๋ชจ๋ฆ
- ๋ถ๋ณ์ฑ(Immutability) ๊ฐ๋ ๋ถ์กฑ
- App.svelte ๊ฐ์ โํฐ ๊ทธ๋ฆผโ ์ดํด ๋ถ์กฑ ๐ด
์ฆ๊ฑฐ:
- โApp.svelte๊ฐ ํ๋ ์ผ์ด ์ดํด๊ฐ ์ ๊ฐโ
- โroutes[2]๋ ์๋ ๊ฑฐ ์๋๊ฐ?โ
๋ฌธ์ :
- ์ปดํฌ๋ํธ ์๋ช ์ฃผ๊ธฐ ์ดํด ๋ถ์กฑ
- ๋ฐฐ์ด ์ธ๋ฑ์ฑ ๊ธฐ๋ณธ ๊ฐ๋ ๋ถ์กฑ
๐ช ๊ฐ์ ๋ถ์
โ ์ํ๋ ๊ฒ๋ค
- ์ง๋ฌธ์ ์ ํจ: ์ดํด ์ ๋๋ฉด ๋ฐ๋ก ๋ฌผ์ด๋ด
- ์ง์ ํ ์คํธ: ์ฝ๋ ์์ ํ๊ณ ์ฝ์ ์ฐ์ด๋ด
- Step-by-step ์ฌ๊ณ : โํ ์ค์ฉ ๋์ง์ด ๊ฐ๋ฉด์ ๋์ ์ ๊ฒโ
- ํผ๋๋ฐฑ ์์ฉ: ์๋์ด ์กฐ์ธ ์ ๊ทน ๋ฐ์
๐ ๋ง์ถคํ ํ์ต ์ปค๋ฆฌํ๋ผ
๐ Phase 1: JavaScript ๊ธฐ์ด ๋ค์ง๊ธฐ (1-2์ฃผ)
Week 1: ๋ฐฐ์ด ์๋ฒฝ ์ ๋ณต
Day 1-2: ๋ฐฐ์ด ๋ฉ์๋ ๊ธฐ๋ณธ
- MDN: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/map
- MDN: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
- MDN: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
์ค์ต ๊ณผ์ : // ๊ณผ์ 1: alertData์์ ์ธต ๋ชฉ๋ก ์ถ์ถ (์ค๋ณต ์ ๊ฑฐ) const alertData = [ { floorName: โ1Fโ, status: โAlertโ }, { floorName: โ2Fโ, status: โClosedโ }, { floorName: โ1Fโ, status: โOfflineโ }, ];
// TODO: Set ์ฌ์ฉํด์ [โ1Fโ, โ2Fโ] ๋ง๋ค๊ธฐ const floors = [โฆnew Set(alertData.map(a => a.floorName))]; console.log(floors);
// ๊ณผ์ 2: Status๋ณ ๊ฐ์ ์ธ๊ธฐ // ๊ฒฐ๊ณผ: { Alert: 1, Closed: 1, Offline: 1 } const statusCount = alertData.reduce((acc, item) => { acc[item.status] = (acc[item.status] || 0) + 1; return acc; }, {});
Day 3-4: ์ ๋ ฌ๊ณผ ๋น๊ต
- MDN: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
- MDN: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare
์ค์ต ๊ณผ์ : // ๊ณผ์ 3: ๋ค์ํ ์ ๋ ฌ ๋ฐฉ๋ฒ ๋น๊ต const floors = [โ10Fโ, โ2Fโ, โ1Fโ, โB1โ, โRoofโ];
// ๋ฐฉ๋ฒ 1: ๊ธฐ๋ณธ ์ ๋ ฌ (๋ฌธ์์ด) console.log([โฆfloors].sort()); // ๊ฒฐ๊ณผ: [โ1Fโ, โ10Fโ, โ2Fโ, โB1โ, โRoofโ] โ 10F๊ฐ 2F ์์!
// ๋ฐฉ๋ฒ 2: localeCompare console.log([โฆfloors].sort((a, b) => a.localeCompare(b))); // ๊ฒฐ๊ณผ: ๊ฐ์
// ๋ฐฉ๋ฒ 3: localeCompare + numeric console.log([โฆfloors].sort((a, b) => a.localeCompare(b, undefined, { numeric: true }))); // ๊ฒฐ๊ณผ: [โ1Fโ, โ2Fโ, โ10Fโ, โB1โ, โRoofโ] โ ์ฌ๋ฐ๋ฅธ ์์!
// ๊ณผ์ 4: ์ ์ด๋ฐ ์ฐจ์ด๊ฐ ์๊ธฐ๋์ง ์ดํดํ๊ธฐ
Day 5: Set๊ณผ ์์
- MDN: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Set
- ๋ธ๋ก๊ทธ: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Set#%EC%84%A4%EB%AA%85
์ค์ต ๊ณผ์ : // ๊ณผ์ 5: Set์ ์์ ์ดํดํ๊ธฐ const data = [ { time: โ09:00:02โ, floor: โ3Fโ }, { time: โ09:00:01โ, floor: โ1Fโ }, { time: โ09:00:01โ, floor: โ2Fโ }, ];
// Q: Set์ ์ฝ์ ์์๋ฅผ ๋ณด์ฅํ๋ค. ๊ฒฐ๊ณผ๋? const floors1 = [โฆnew Set(data.map(a => a.floor))]; console.log(โ์ ๋ ฌ ์ :โ, floors1); // [โ3Fโ, โ1Fโ, โ2Fโ]
// Q: ๋ฐ์ดํฐ๋ฅผ ๋จผ์ ์ ๋ ฌํ๋ฉด? const sortedData = data.sort((a, b) => a.floor.localeCompare(b.floor, undefined, { numeric: true })); const floors2 = [โฆnew Set(sortedData.map(a => a.floor))]; console.log(โ์ ๋ ฌ ํ:โ, floors2); // [โ1Fโ, โ2Fโ, โ3Fโ]
// ๊ฒฐ๋ก : Set์ ์์๋ฅผ ๋ณด์ฅํ์ง๋ง, ์ ๋ ฅ ์์๋ฅผ ๋ณด์ฅํ๋ค!
Week 2: ๊ฐ์ฒด์ ์ฐธ์กฐ
Day 1-2: ์์ ๋ณต์ฌ vs ๊น์ ๋ณต์ฌ
- MDN: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Spread_syntax
- MDN: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
์ค์ต ๊ณผ์ : // ๊ณผ์ 6: ๋ถ๋ณ์ฑ ์ดํดํ๊ธฐ let alertData = [ { time: โ09:00:01โ, status: โAlertโ } ];
// โ ์๋ชป๋ ๋ฐฉ๋ฒ (์๋ณธ ๋ณ๊ฒฝ) alertData.push({ time: โ09:00:02โ, status: โClosedโ });
// โ ์ฌ๋ฐ๋ฅธ ๋ฐฉ๋ฒ (์ ๋ฐฐ์ด ์์ฑ) alertData = [โฆalertData, { time: โ09:00:02โ, status: โClosedโ }];
// Svelte์์๋ ์ ํ์๋ฅผ ์ ํธํ ๊น? (๋ฐ์์ฑ ๋๋ฌธ!)
Day 3-5: ๋ธ๋ผ์ฐ์ API
- MDN: https://developer.mozilla.org/ko/docs/Web/API/History_API
- MDN: https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage
์ค์ต ๊ณผ์ : // ๊ณผ์ 7: URL ๋ณ๊ฒฝ ์์ด ์ํ ์ ๋ฐ์ดํธ // ํ์ฌ URL: http://localhost:5173/floor/1?spaceID=3
// history.replaceState๋ก ์ฟผ๋ฆฌ์คํธ๋ง ์ ๊ฑฐ const newUrl = window.location.pathname; window.history.replaceState(null, โโ, newUrl); // ๊ฒฐ๊ณผ: http://localhost:5173/floor/1
// ๊ณผ์ 8: localStorage ํ์ฉ localStorage.setItem(โselectedFloorโ, โ2Fโ); const floor = localStorage.getItem(โselectedFloorโ); console.log(floor); // โ2Fโ
๐ Phase 2: Svelte ํต์ฌ ๊ฐ๋ (1์ฃผ)
Day 1-3: Reactive Statements ์์ ์ ๋ณต
- https://svelte.dev/tutorial/reactive-declarations
- https://svelte.dev/docs/svelte-components#script-3-$-marks-a-statement-as-reactive
์ค์ต ๊ณผ์ : // ๊ณผ์ 9: $:์ ๋์ ์์ ์ดํด let count = 0;
// Q1: ์ด ์ฝ๋๋ ์ธ์ ์คํ๋ ๊น? $: doubled = count * 2; $: console.log(โcount changed:โ, count);
// Q2: ๋ฒํผ ํด๋ฆญ ์ ๋ช ๋ฒ ์คํ๋ ๊น? function increment() { count += 1; count += 1; count += 1; } // ๋ต: console.log๋ 1๋ฒ๋ง ์คํ! (Svelte๊ฐ batch ์ฒ๋ฆฌ)
// ๊ณผ์ 10: ์์กด์ฑ ์ดํด let firstName = โJohnโ; let lastName = โDoeโ;
$: fullName = ${firstName} ${lastName};
// Q: firstName๋ง ๋ฐ๋๋ฉด? โ fullName ์ฌ๊ณ์ฐ
// Q: lastName๋ง ๋ฐ๋๋ฉด? โ fullName ์ฌ๊ณ์ฐ
// Q: ๋ ๋ค ์ ๋ฐ๋๋ฉด? โ ์ฌ๊ณ์ฐ ์ ํจ
Day 4-5: ์๋ช ์ฃผ๊ธฐ
- https://svelte.dev/tutorial/onmount
- https://svelte.dev/tutorial/ondestroy
์ค์ต ๊ณผ์ : // ๊ณผ์ 11: onMount vs $: ์ฐจ์ด let data = [];
// ๋ฐฉ๋ฒ 1: onMount onMount(() => { data = fetchData(); // 1๋ฒ๋ง ์คํ });
// ๋ฐฉ๋ฒ 2: $: $: { data = fetchData(); // data๊ฐ ๋ฐ๋ ๋๋ง๋ค ์คํ (๋ฌดํ ๋ฃจํ!) }
// Q: ์ธ์ onMount๋ฅผ ์ฐ๊ณ , ์ธ์ $:๋ฅผ ์ธ๊น?
๐ Phase 3: ์ค์ ํจํด (์งํ ์ค)
์ง๊ธ ์์ ํ๋ ํ๋ก์ ํธ๋ก ํ์ต
ํจํด 1: MQTT ์ค์๊ฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ // โ ์ด๋ณด์ ์ฝ๋ let alertData = [โฆ].sort(โฆ); // ์ด๊ธฐ๋ง ์ ๋ ฌ
// โ ํ๋ก ์ฝ๋ let alertData = [โฆ]; $: sortedData = alertData.slice().sort(โฆ); // ํญ์ ์ ๋ ฌ
ํจํด 2: ์บ์ค์ผ์ด๋ฉ ํํฐ // โ ์ด๋ณด์ ์ฝ๋ function updateSpaceList() { โฆ } function updateFilteredData() { โฆ }
// โ ํ๋ก ์ฝ๋ $: spaceList = selectedFloor === โallโ ? โฆ : โฆ; $: filteredData = alertData.filter(โฆ);
๐ 2์ฃผ ํ์ต ํ๋
Week 1: JavaScript ๊ธฐ์ด
์: Array.map(), filter() ์ฐ์ต ํ: Array.reduce() ์ฐ์ต ์: ์ ๋ ฌ (sort, localeCompare) ๋ชฉ: Set, ์์ ๋ณด์ฅ ๊ฐ๋ ๊ธ: ๋ณต์ต + ํด์ฆ ์ฃผ๋ง: ์ค์ ๊ณผ์ (Bldg.svelte ๋ฆฌํฉํ ๋ง)
Week 2: Svelte + ์ค์
์: Reactive statements ($:) ํ: $: ์์กด์ฑ ์ถ์ ์: onMount, onDestroy ๋ชฉ: ์ค์ ํจํด (MQTT) ๊ธ: EventLog.svelte ์ง์ ๊ตฌํ ์ฃผ๋ง: ์ ์ฒด ๋ณต์ต
๐ฏ ํ์ต ๋ฐฉ๋ฒ ๊ถ์ฅ
- MDN ๋ฌธ์ ์ฝ๋ ๋ฒ
1๏ธโฃ ์์ ๋ถํฐ ์ฝ๊ธฐ (์ด๋ก ์ ๋์ค์) 2๏ธโฃ ์ฝ์์์ ์ง์ ์คํ 3๏ธโฃ ๋ณํํด๋ณด๊ธฐ (์ซ์ ๋ฐ๊พธ๊ธฐ, ์กฐ๊ฑด ๋ฐ๊พธ๊ธฐ) 4๏ธโฃ ์ด๋ก ์ฝ๊ธฐ 5๏ธโฃ ์ค์ ํ๋ก์ ํธ์ ์ ์ฉ
- ๋งค์ผ 30๋ถ ์ฝ๋ฉ ์ฑ๋ฆฐ์ง
// ๋งค์ผ ์์นจ ๋ฃจํด const data = [/* ๋๋ค ๋ฐ์ดํฐ */];
// Day 1: map ์ฌ์ฉํด์ ํน์ ํ๋๋ง ์ถ์ถ // Day 2: filter ์ฌ์ฉํด์ ์กฐ๊ฑด ํํฐ๋ง // Day 3: reduce ์ฌ์ฉํด์ ๊ทธ๋ฃนํ // โฆ
- ์๋์ด์๊ฒ ์ง๋ฌธํ๊ธฐ ์ ์ฒดํฌ๋ฆฌ์คํธ
โ MDN ๋ฌธ์ ์ฝ์ด๋ดค๋๊ฐ? โ ์ฝ์์์ ํ ์คํธํด๋ดค๋๊ฐ? โ ์๋ฌ ๋ฉ์์ง๋ฅผ ๊ตฌ๊ธ๋งํด๋ดค๋๊ฐ? โ ๋น์ทํ ์ฝ๋๋ฅผ ํ๋ก์ ํธ์์ ์ฐพ์๋ดค๋๊ฐ?
๐ ์ฒซ ์ฃผ ์์ํ๊ธฐ
์ค๋ ๋น์ฅ ์์ํ ์ ์๋ ๊ฒ:
- MDN Array.map() ์ฝ๊ธฐ (10๋ถ)
- ์ฝ์ ์ด๊ณ ๊ณผ์ 1 ํ๊ธฐ (20๋ถ)
- Bldg.svelte์์ map() ์ฐพ์๋ณด๊ธฐ (10๋ถ)
์ด 40๋ถ์ด๋ฉด ์ฒซ ์คํ ์๋ฃ!
This line appears after every note.
Notes mentioning this note
There are no notes linking to this note.