AI๋กœ ์ƒ์„ฑํ•ด ๋ดค์Šต๋‹ˆ๋‹ค. ์˜คํƒ€๊ฐ€ ์žˆ์ง€๋งŒ ๋‚˜์˜์ง€ ์•Š๋„ค์š”!

 

์ดํ„ฐ๋Ÿฌ๋ธ”(Iterable)

์ •์˜

  • ๋ฐ˜๋ณต ๊ฐ€๋Šฅํ•œ ๊ฐ์ฒด
  • `for...of`, `์Šคํ”„๋ ˆ๋“œ(...)`, `๋””์ŠคํŠธ๋Ÿญ์ฒ˜๋ง ํ• ๋‹น` ๋“ฑ์— ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  • ์ดํ„ฐ๋Ÿฌ๋ธ”์€ Symbol.iterator ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ, ์ด ๋ฉ”์„œ๋“œ๊ฐ€ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜

 

์˜ˆ์‹œ

const arr = [1, 2, 3]; // ๋ฐฐ์—ด (๋Œ€ํ‘œ์ ์ธ ์ดํ„ฐ๋Ÿฌ๋ธ”) 
const str = "hi"; // ๋ฌธ์ž์—ด๋„ ์ดํ„ฐ๋Ÿฌ๋ธ” 
const set = new Set([1, 2, 3]); // Set๋„ ์ดํ„ฐ๋Ÿฌ๋ธ” 
for (const val of arr) console.log(val); // 1, 2, 3



์ดํ„ฐ๋ ˆ์ดํ„ฐ(Iterator)

์ •์˜

  • ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ์‹ค์ œ๋กœ ์ˆœํšŒํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜
  • `next()` ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ `{ done: Boolean, value: any }`์™€ ๊ฐ™์€ ํ˜•ํƒœ์˜ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜
  • `done: true` ๊ฐ€ ๋  ๋•Œ๊นŒ์ง€ ์ˆœํšŒ

 

์˜ˆ์‹œ

const arr = [1, 2, 3]; 
const iterator = arr[Symbol.iterator](); 
console.log(iterator.next()); // { done: false, value: 1 } 
console.log(iterator.next()); // { done: false, value: 2 }
console.log(iterator.next()); // { done: false, value: 3 } 
console.log(iterator.next()); // { done: true, value: undefined }



 

์ดํ„ฐ๋Ÿฌ๋ธ”  ↔  ๋ฐฐ์—ด ๋ฉ”์„œ๋“œ ํ™œ์šฉ

  • ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ํ•ด `map`, `filter` ๊ฐ™์€ ๊ณ ์ฐจ ํ•จ์ˆ˜ ํ™œ์šฉ ๊ฐ€๋Šฅ
const set = new Set([1, 2, 3]); 
const doubled = [...set].map(x => x * 2); // [2, 4, 6]
 

 

์žฅ์ 

  1. ์ผ๊ด€๋œ ๋ฐ˜๋ณต ํ”„๋กœํ† ์ฝœ ์ œ๊ณต
    → for...of, ์Šคํ”„๋ ˆ๋“œ, ๋””์ŠคํŠธ๋Ÿญ์ฒ˜๋ง ๋“ฑ ์–ด๋””์„œ๋“  ํ™œ์šฉ ๊ฐ€๋Šฅ
  2. ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ํ™•์žฅ ๊ฐ€๋Šฅ
    → ํŠธ๋ฆฌ, ๊ทธ๋ž˜ํ”„ ๊ฐ™์€ ์‚ฌ์šฉ์ž ์ •์˜ ๊ตฌ์กฐ์—์„œ๋„ ์›ํ•˜๋Š” ์ˆœ์„œ(DFS, BFS ๋“ฑ)๋กœ ์ˆœํšŒ ์ •์˜ ๊ฐ€๋Šฅ
  3. ์œ ์—ฐ์„ฑ
    → ์–ด๋–ค ์ˆœ์„œ, ์–ด๋–ค ์กฐ๊ฑด์œผ๋กœ๋“  ๋ฐ˜๋ณต ๋™์ž‘์„ ์ง์ ‘ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Œ

 

 

ํ•œ๊ณ„

  1. ์„ฑ๋Šฅ ๋ฌธ์ œ
    • ๋Œ€๊ทœ๋ชจ ๋ฐ์ดํ„ฐ ์ˆœํšŒ ์‹œ next() ํ˜ธ์ถœ ๋น„์šฉ ๋ˆ„์ 
    • ๋ณต์žกํ•œ ๊ตฌ์กฐ์ผ์ˆ˜๋ก ์ ‘๊ทผ ๋น„์šฉ ์ฆ๊ฐ€
  2. ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰ ์ฆ๊ฐ€
    • ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋Š” ์ƒํƒœ(state)๋ฅผ ์ €์žฅํ•ด์•ผ ํ•˜๋ฏ€๋กœ ๋™์‹œ์— ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ์“ฐ๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋ถ€๋‹ด
// ์ƒํƒœ ๋ˆ„์  ์˜ˆ์‹œ
  [Symbol.iterator]() {
    this.current = this.from;
    return this;
  },

 

 

  3. ๋ฐฐ์—ด ๋ฉ”์„œ๋“œ ์ง์ ‘ ์‚ฌ์šฉ ๋ถˆ๊ฐ€

  • ์ดํ„ฐ๋Ÿฌ๋ธ” ์ž์ฒด๋Š” map, filter ๊ฐ™์€ ๋ฐฐ์—ด ๋ฉ”์„œ๋“œ๋ฅผ ๋ฐ”๋กœ ์“ธ ์ˆ˜ ์—†์Œ → ๋ฐฐ์—ด๋กœ ๋ณ€ํ™˜ํ•ด์•ผ ํ•จ

 

๊ฐœ์„ ๋ฐฉ์•ˆ

  1. ์ œ๋„ˆ๋ ˆ์ดํ„ฐ(Generator)
    • ์ดํ„ฐ๋Ÿฌ๋ธ”+์ดํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ ์‰ฝ๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ๋ฒ•
    • yield๋ฅผ ์‚ฌ์šฉํ•ด ํ•„์š”ํ•  ๋•Œ๋งŒ ๊ฐ’์„ ์ƒ์„ฑ (lazy evaluation)
    • ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์ 
    • `function* numbers() { yield 1; yield 2; yield 3; } for (const n of numbers()) { console.log(n); // 1, 2, 3 }`
  2. Lazy Evaluation ๊ธฐ๋ฒ• ํ™œ์šฉ
    • ์ „์ฒด ๋ฐ์ดํ„ฐ๋ฅผ ํ•œ๊บผ๋ฒˆ์— ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ฆฌ์ง€ ์•Š๊ณ , ํ•„์š”ํ•œ ์ˆœ๊ฐ„์—๋งŒ ๊ณ„์‚ฐ/๋ฐ˜ํ™˜

 

์œ ์‚ฌ ๋ฐฐ์—ด(array-like object)

์ •์˜

  • ์ธ๋ฑ์Šค์™€ `length` ํ”„๋กœํผํ‹ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์–ด ๋ฐฐ์—ด์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ
  • `next()` ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ `{ done: Boolean, value: any }`์™€ ๊ฐ™์€ ํ˜•ํƒœ์˜ ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜
  • ๋ฐ˜๋“œ์‹œ `Symbol.iterator`๊ฐ€ ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹˜ → for...of, ์Šคํ”„๋ ˆ๋“œ ๋ถˆ๊ฐ€

์˜ˆ์‹œ

const obj = {0: 'a', 1: 'b', length: 2};
console.log(obj[0]); // 'a'
console.log(obj.length); // 2
// [...obj] // Error! ์œ ์‚ฌ ๋ฐฐ์—ด์€ ์Šคํ”„๋ ˆ๋“œ ๋ถˆ๊ฐ€

 

๋ณ€ํ™˜ ๋ฐฉ๋ฒ•

Array.from(obj); // ['a','b']

 

์ฃผ์˜ํ•  ์ 

  • ์œ ์‚ฌ ๋ฐฐ์—ด๊ณผ ์ดํ„ฐ๋Ÿฌ๋ธ”์„ ํ—ท๊ฐˆ๋ฆฌ๊ธฐ ์‰ฌ์›€
  • ์œ ์‚ฌ ๋ฐฐ์—ด์ด๋ฉด์„œ ์ดํ„ฐ๋Ÿฌ๋ธ”์ธ ๊ฒฝ์šฐ๋„ ์กด์žฌ
    • ์˜ˆ: arguments, NodeList, HTMLCollection ๋“ฑ
    • ์ด๋Ÿฐ ๊ฒฝ์šฐ๋Š” for...of๋‚˜ ์Šคํ”„๋ ˆ๋“œ(...) ์‚ฌ์šฉ ๊ฐ€๋Šฅ

๊ด€๊ณ„ ์ •๋ฆฌ

์ดํ„ฐ๋Ÿฌ๋ธ”(Iterable)
 โ””โ”€ Symbol.iterator ๋ฉ”์„œ๋“œ ์กด์žฌ
      โ””โ”€ ๋ฐ˜ํ™˜ → ์ดํ„ฐ๋ ˆ์ดํ„ฐ(Iterator)
             โ””โ”€ next() ํ˜ธ์ถœ๋กœ ์‹ค์ œ ๋ฐ˜๋ณต ์ˆ˜ํ–‰
                 โ””โ”€ { value, done } ๋ฐ˜ํ™˜

์œ ์‚ฌ ๋ฐฐ์—ด(array-like)
 โ””โ”€ ์ธ๋ฑ์Šค + length๋งŒ ์กด์žฌ
      โ””โ”€ Symbol.iterator ์—†์œผ๋ฉด for...of/์Šคํ”„๋ ˆ๋“œ ๋ถˆ๊ฐ€
      โ””โ”€ Symbol.iterator ์žˆ์œผ๋ฉด ์ดํ„ฐ๋Ÿฌ๋ธ”์ฒ˜๋Ÿผ ์‚ฌ์šฉ ๊ฐ€๋Šฅ (์˜ˆ: arguments, NodeList)

 

 

 

์ •๋ฆฌ

  • ์ดํ„ฐ๋Ÿฌ๋ธ”(Iterable): “๋ฐ˜๋ณตํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด” (๋ฐฐ์—ด, ๋ฌธ์ž์—ด, Set, Map ๋“ฑ)
  • ์ดํ„ฐ๋ ˆ์ดํ„ฐ(Iterator): “์‹ค์ œ๋กœ ๋ฐ˜๋ณต์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋„๊ตฌ” (next() ์‚ฌ์šฉ)
  • ๊ด€๊ณ„: ์ดํ„ฐ๋Ÿฌ๋ธ”์€ Symbol.iterator๋ฅผ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๊ณ , ์ด ๋ฉ”์„œ๋“œ๊ฐ€ ์ดํ„ฐ๋ ˆ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜
  • ๊ฐ•์ : ์ผ๊ด€๋œ ๋ฐ˜๋ณต ํ”„๋กœํ† ์ฝœ, ๋‹ค์–‘ํ•œ ๊ตฌ์กฐ ์ง€์›, ์œ ์—ฐํ•œ ์ˆœํšŒ
  • ํ•œ๊ณ„: ๋Œ€๊ทœ๋ชจ ๋ฐ์ดํ„ฐ์—์„œ ์„ฑ๋Šฅ·๋ฉ”๋ชจ๋ฆฌ ๋ถ€๋‹ด
  • ๋ณด์™„: ์ œ๋„ˆ๋ ˆ์ดํ„ฐ์™€ lazy evaluation ํ™œ์šฉ

 

 

๐Ÿ“ƒ ์ฐธ๊ณ  ๋ฌธํ—Œ  
์ฝ”์–ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ
Inpa Dev - ์ดํ„ฐ๋Ÿฌ๋ธ” & ์ดํ„ฐ๋ ˆ์ดํ„ฐ
F-Lab - ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—์„œ์˜ ๋ฐ˜๋ณต ํ”„๋กœํ† ์ฝœ ์ดํ•ดํ•˜๊ธฐ

 

TOAST UI - ํ„ฐ์น˜์™€ ํด๋ฆญ ์ด๋ฒคํŠธ ๊ธ€์—์„œ ์ƒ๊ธด ์˜๋ฌธ์„ ์ •๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๊ธ€์ž…๋‹ˆ๋‹ค.

 

ํ„ฐ์น˜ & ํด๋ฆญ ?!

 

ํ„ฐ์น˜ ์ด๋ฒคํŠธ๋ฅผ ๋‹ฌ์•˜๋Š”๋ฐ ์™œ ํด๋ฆญ ์ด๋ฒคํŠธ๊นŒ์ง€ ๋ฐœ์ƒํ•˜๋‚˜์š”?

  • ํ„ฐ์น˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋‚ด๊ฐ€ ๋ณ„๋„๋กœ ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ๋‹ฌ์ง€ ์•Š์•˜์–ด๋„ click ์ด๋ฒคํŠธ๊ฐ€ ์ค‘๋ณต์œผ๋กœ ๋ฐœ์ƒํ•ด ๋ฒ„๋ฆฝ๋‹ˆ๋‹ค.
    ์™œ ์ด๋Ÿฐ ๋™์ž‘์ด ์ผ์–ด๋‚˜๋Š” ๊ฑธ๊นŒ์š”?
  • ์›น์€ ์˜ค๋žซ๋™์•ˆ ๋งˆ์šฐ์Šค ํด๋ฆญ ์ค‘์‹ฌ์œผ๋กœ ์„ค๊ณ„๋˜๊ณ  ๋ฐœ์ „ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ์ง€๊ธˆ๊นŒ์ง€ ๋งŽ์€ ์‚ฌ์ดํŠธ๊ฐ€ ์˜ค์ง click ์ด๋ฒคํŠธ๋งŒ ๋“ฃ๊ณ  ๋™์ž‘ํ•˜๋„๋ก ๋งŒ๋“ค์–ด์ ธ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋ชจ๋ฐ”์ผ ๋ธŒ๋ผ์šฐ์ €๋Š” ํ˜ธํ™˜์„ฑ ์œ ์ง€๋ฅผ ์œ„ํ•ด ํ„ฐ์น˜ ์‹œ ์ž๋™์œผ๋กœ click ์ด๋ฒคํŠธ๋„ ํ•จ๊ป˜ ๋ฐœ์ƒ์‹œํ‚ค๋„๋ก ์„ค๊ณ„๋ผ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ์— ํ„ฐ์น˜์Šคํฌ๋ฆฐ ํ™˜๊ฒฝ์—์„œ๋„ ๊ธฐ์กด ๋งˆ์šฐ์Šค ์ค‘์‹ฌ ์‚ฌ์ดํŠธ๋“ค์ด ๋ณ„๋„ ์ˆ˜์ • ์—†์ด ๋™์ž‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

ํ„ฐ์น˜ ์ด๋ฒคํŠธ ํ›„ click ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒŒ ์™œ ํŽธ์˜์ผ๊นŒ์š”?

  • ์—ฌ๋Ÿฌ ์ž๋ฃŒ์—์„œ ์ด๊ฑธ ํŽธ์˜๋ผ๊ณ  ํ•˜๋˜๋ฐ ํ‘œํ˜„์ด ๋„ˆ๋ฌด ํฌ๊ด„์ ์œผ๋กœ ๋А๊ปด์ ธ์„œ ๊ทธ๋Ÿฐ์ง€ ์ฒ˜์Œ์—๋Š” ์ดํ•ด๊ฐ€ ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ์•„๋ž˜๋Š” ์ œ๊ฐ€ ์ฐพ์•„๋ณธ ํ›„ ์ดํ•ดํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค!
    • ๋ธŒ๋ผ์šฐ์ €๋Š” ์ด ์‚ฌ์ดํŠธ๊ฐ€ ํ„ฐ์น˜/ํด๋ฆญ ๋‘˜ ๋‹ค ์ง€์›ํ•˜๋Š”์ง€, ์–ด๋–ค ์‹์œผ๋กœ ์˜๋„ํ–ˆ๋Š”์ง€ ์•Œ ๋ฐฉ๋ฒ•์ด ์—†์Šต๋‹ˆ๋‹ค.
    • ๊ทธ๋ž˜์„œ ์ผ๊ด„์ ์œผ๋กœ, ํ„ฐ์น˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ๋ฐ˜๋“œ์‹œ click ์ด๋ฒคํŠธ๋„ ๊ฐ™์ด ๋ฐœ์ƒํ•˜๋„๋ก ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.
    • ๋ธŒ๋ผ์šฐ์ €๋Š” ์ €ํฌ๊ฐ€ ๋งŒ๋“  ์‚ฌ์ดํŠธ๋งŒ ๋„์šฐ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์•„์ฃผ ๋งŽ์€ ์‚ฌ์ดํŠธ๋ฅผ ๋™์‹œ์— ์ง€์›ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋ฐ”์ผ ๋„์ž… ์ดˆ๊ธฐ์—” ๋Œ€๋ถ€๋ถ„ ์˜ค์ง ํด๋ฆญ ์ด๋ฒคํŠธ๋งŒ ์‚ฌ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—, ํ„ฐ์น˜ ์ด๋ฒคํŠธ๋งŒ ๋ฐœ์ƒ์‹œ ํด๋ฆญ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋ฉด ์˜›๋‚  ์‚ฌ์ดํŠธ๋“ค์ด ๋ชจ๋ฐ”์ผ์—์„œ ๋จนํ†ต์ด ๋  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ํ„ฐ์น˜ ์‹œ ์ž๋™์œผ๋กœ ํด๋ฆญ ์ด๋ฒคํŠธ๋„ ๋ฐœ์ƒ์‹œํ‚ค๋„๋ก ์„ค๊ณ„๋˜์—ˆ๊ณ  ๊ธฐ์กด ํด๋ฆญ ๊ธฐ๋ฐ˜ ์‚ฌ์ดํŠธ์™€์˜ ํ˜ธํ™˜์„ฑ๋„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

 

React ๋“ฑ์—์„œ๋„ ํด๋ฆญ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ• ๊นŒ์š”?

  • ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” React ๊ธฐ์ค€์œผ๋กœ ์—ฌ๊ธฐ์„œ๋„ ๋ธŒ๋ผ์šฐ์ €์˜ ์ด๋ฒคํŠธ ์œ„์ž„ ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ๊ทธ๋Œ€๋กœ ๋”ฐ๋ž์Šต๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €์˜ ๋„ค์ดํ‹ฐ๋ธŒ ์ด๋ฒคํŠธ ์‹œ์Šคํ…œ์„ ๊ทธ๋Œ€๋กœ ํ™œ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋™์ผํ•œ ๋™์ž‘์ด ๋ฐœ์ƒํ•ด์š”.
  • ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ„ฐ์น˜ ์ด๋ฒคํŠธ ํ›„ ์ž๋™์œผ๋กœ ๋งˆ์šฐ์Šค์™€ ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋Š”๊ฑด React ์ด์ „ ๋‹จ๊ณ„์—์„œ ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค.
  • React๋Š” ๋ธŒ๋ผ์šฐ์ €์˜ ๋„ค์ดํ‹ฐ๋ธŒ ์ด๋ฒคํŠธ๋ฅผ ๊ฐ์‹ธ๋Š” SyntheticEvent๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์–ด์š”. ํ•˜์ง€๋งŒ ๋ธŒ๋ผ์šฐ์ €์˜ ๊ธฐ๋ณธ ์ด๋ฒคํŠธ ๋™์ž‘์€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  ์ด๋ฒคํŠธ ์œ„์ž„์„ ์‚ฌ์šฉํ•˜์ง€๋งŒ ์ด๊ฑด ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์„ ์ตœ์ ํ™”ํ•˜๋Š” ๊ฒƒ์ด์ง€ ๋ธŒ๋ผ์šฐ์ €์˜ ๊ธฐ๋ณธ ์ด๋ฒคํŠธ ๋™์ž‘์„ ๋ฐ”๊พธ๋Š”๊ฒŒ ์•„๋‹™๋‹ˆ๋‹ค.
  • ๊ด€๋ จ ํ† ๋ก ์ธ GitHub ์ด์Šˆ #9809๋ฅผ ์ •๋ฆฌํ•ด๋ณด๋ฉด,
    • preventDefault() ๋ฌดํšจํ™”: React์˜ ํ•ฉ์„ฑ ์ด๋ฒคํŠธ์—์„œ e.prevnetDefault()๊ฐ€ ํด๋ฆญ ์ด๋ฒคํŠธ ๋ฐฉ์ง€์— ์‹คํŒจ
    • ๋„ค์ดํ‹ฐ๋ธŒ DOM API๋Š” ์ž‘๋™: addEventListener๋กœ ์ง์ ‘ ๋“ฑ๋กํ•˜๋ฉด preventDefault()๊ฐ€ ์ •์ƒ ๋™์ž‘
    • ๋ธŒ๋ผ์šฐ์ €๋ณ„ ์ฐจ์ด: Chrome, Firefox, Safari์—์„œ ๊ฐ๊ฐ ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ (์ถ”๊ฐ€ ํ™•์ธ์ด ํ•„์š”)
  • ์œ„์˜ ๋‚ด์šฉ์€ ๊ด€๋ จ ์ด์Šˆ๋ฅผ ์ง์ ‘ ๋ณด๊ณ  ์ƒ์„ธ ๋‚ด์šฉ๊ณผ ์ด์œ ๋ฅผ ํ™•์ธํ•ด ๋ณด๋Š”๊ฑธ ์ถ”์ฒœ๋“œ๋ฆฝ๋‹ˆ๋‹ค!
  • ์ด์Šˆ์—์„œ ์ œ์‹œ๋œ ํ•ด๊ฒฐ์ฑ…๋“ค๋„ ์งง๊ฒŒ๋ผ๋„ ์ •๋ฆฌํ•ด ๋ณด๊ฒŸ์Šต๋‹ˆ๋‹ค.
// ๋ฐฉ๋ฒ• 1: ๋„ค์ดํ‹ฐ๋ธŒ DOM API ์‚ฌ์šฉ
componentDidMount() {
  this.elem.addEventListener('touchstart', e => {
    e.preventDefault(); // ์ด๊ฑด ์ž‘๋™ํ•จ
  });
}

// ๋ฐฉ๋ฒ• 2: ํ”Œ๋ž˜๊ทธ ์‚ฌ์šฉ
handleTouchStart(event) {
  this.hasBeenTouchedRecently = true;
  setTimeout(() => { 
    this.hasBeenTouchedRecently = false; 
  }, 500);
}

handleMouseDown(event) {
  if(this.hasBeenTouchedRecently) {
    return; // ํ„ฐ์น˜ ํ›„ ๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ ๋ฌด์‹œ
  }
}

 

 

 

๋ทฐํฌํŠธ ๋ฉ”ํƒ€ ํƒœ๊ทธ์™€ ๋ฐ์Šคํฌํƒ‘/๋ชจ๋ฐ”์ผ ๋™์‹œ ์ง€์›์˜ ๋ฌธ์ œ๋Š” ์—†์„๊นŒ์š”?

 <meta name="viewport" content="width=device-width">
  •  ์œ„ ์ฝ”๋“œ๋ฅผ ๋„ฃ์œผ๋ฉด ๋ชจ๋ฐ”์ผ์—์„œ ํ„ฐ์น˜ ๋”œ๋ ˆ์ด๊ฐ€ ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค.
  • ์ด ํƒœ๊ทธ๋Š” ๋ชจ๋ฐ”์ผ๋งŒ์ด ์•„๋‹ˆ๋ผ ๋ฐ์Šคํฌํƒ‘์— ํฌํ•จํ•ด๋„ ๋ฌด๋ฐฉํ•ด์š”.

 

ํ„ฐ์น˜/ํด๋ฆญ ๋”œ๋ ˆ์ด๋Š” 2025๋…„์—๋„ ๋˜‘๊ฐ™์ด ๋ฐœ์ƒํ• ๊นŒ์š”?

  • ๊ณผ๊ฑฐ์—” 300ms์˜ ํ„ฐ์น˜→ํด๋ฆญ ๋”œ๋ ˆ์ด๊ฐ€ ์žˆ์—ˆ์ง€๋งŒ ํ˜„์žฌ ์ตœ์‹  ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” ๋ทฐํฌํŠธ ๋ฉ”ํƒ€ ํƒœ๊ทธ๋‚˜ CSS ์„ธํŒ…๋งŒ ์ž˜ ํ•˜๋ฉด ๋”œ๋ ˆ์ด ๋ฌธ์ œ๋Š” ๊ฑฐ์˜ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

 

 

๐Ÿ“ƒ ์ฐธ๊ณ  ๋ฌธํ—Œ  
Chrome ๊ฐœ๋ฐœ์ž ๋ธ”๋กœ๊ทธ - A More Compatible, Smoother Touch
quirksmode

 

์˜ค๋Š˜์€ ๋ณ„๋„ ์ปจํ…์ŠคํŠธ๋ฅผ ๊ฐ€์ง„ ์ƒˆ ์ฐฝ์„ ๋„์šฐ๋Š” ๊ฐœ๋ฐœ์„ ํ•˜๋ฉฐ ์•Œ๊ฒŒ๋œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•ด๋ณด๋ ค ํ•ฉ๋‹ˆ๋‹ค.

 

window.open

 

์™œ ์•„์ง๋„ window.open์ด ํ•„์š”ํ•œ๊ฐ€?

 

์‹œ์ž‘์ „์— ํŒ์—…๊ณผ ๋ชจ๋‹ฌ์˜ ๋ณธ์งˆ์  ์ฐจ์ด๋ถ€ํ„ฐ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

ํŒ์—…์ฐฝ

  • ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์™„์ „ํžˆ ๋ถ„๋ฆฌ๋œ ์ƒˆ ์ฐฝ(๋˜๋Š” ํƒญ)์œผ๋กœ ๋™์ž‘
  • ๋ธŒ๋ผ์šฐ์ €์˜ ํŒ์—… ์ฐจ๋‹จ ๊ธฐ๋Šฅ์— ์˜ํ–ฅ์„ ๋ฐ›๊ณ 
  • ๋ถ€๋ชจ ํŽ˜์ด์ง€์™€ ๋ณ„๋„์˜ ๋ธŒ๋ผ์šฐ์ € ์ปจํ…์ŠคํŠธ๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค.
  • ์ฐฝ์˜ ์œ„์น˜, ํฌ๊ธฐ, ์Šคํฌ๋กค๋ฐ” ๋“ฑ ๋‹ค์–‘ํ•œ ์†์„ฑ์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ถ€๋ชจ ์ฐฝ์ด ์ƒˆ๋กœ๊ณ ์นจ๋˜๊ฑฐ๋‚˜ ์ด๋™ํ•ด๋„ ํŒ์—…์€ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.
  • ๋ธŒ๋ผ์šฐ์ € ํŒ์—… ์ฐจ๋‹จ ๊ธฐ๋Šฅ์— ์˜ํ•ด ์‚ฌ์šฉ์ž๊ฐ€ ํŒ์—…์„ ๋ชป ๋ณผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•˜๋Š”๊ฒŒ ์ข‹์Šต๋‹ˆ๋‹ค. ๊ทธ ์™ธ์—๋Š” ๋ชจ๋‹ฌ์ด ๊ถŒ์žฅ๋ฉ๋‹ˆ๋‹ค.

๋ชจ๋‹ฌ์ฐฝ

  • ๊ธฐ์กด ํŽ˜์ด์ง€ ์œ„์— ์˜ค๋ฒ„๋ ˆ์ด ๋ ˆ์ด์–ด๋กœ ๊ตฌํ˜„
  • ๋ถ€๋ชจ ํŽ˜์ด์ง€์— ์ข…์†๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ธŒ๋ผ์šฐ์ €์˜ ํŒ์—… ์ฐจ๋‹จ ๊ธฐ๋Šฅ๊ณผ ๋ฌด๊ด€ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ถ€๋ชจ ํŽ˜์ด์ง€๊ฐ€ ์ด๋™ ๋˜๋Š” ์ƒˆ๋กœ๊ณ ์นจ๋˜๋ฉด ๋ชจ๋‹ฌ๋„ ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค.
  • ๋ณ„๋„์˜ ๋ธŒ๋ผ์šฐ์ € ์ปจํ…์ŠคํŠธ๊ฐ€ ์•„๋‹ˆ๋ฏ€๋กœ, ์™ธ๋ถ€ ๋„๋ฉ”์ธ ํŽ˜์ด์ง€๋ฅผ ์ง์ ‘ ํฌํ•จํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด๋•Œ iframe์„ ์ƒ๊ฐํ•˜์‹ค ์ˆ˜ ์žˆ๋Š”๋ฐ ๋ณด์•ˆ์ƒ ์ œ์•ฝ์ด ๋งŽ์•„ ๋ถˆํŽธํ•ฉ๋‹ˆ๋‹ค.

 

React์—์„œ๋Š” ์ƒํƒœ(state)๋ฅผ ํ™œ์šฉํ•œ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง์œผ๋กœ ํŒ์—…์„ ๊ตฌํ˜„ํ•˜๊ฑฐ๋‚˜, Toss์˜ ์˜ค๋ฒ„๋ ˆ์ด ํ‚คํŠธ(Overlay Kit)๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฐ๋ฐ๋„ ์—ฌ์ „ํžˆ window.open()์ด ํŽธ๋ฆฌํ•˜๊ฑฐ๋‚˜ ํ•„์š”ํ•œ ์ƒํ™ฉ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

  1. ์™ธ๋ถ€ ๋„๋ฉ”์ธ๊ณผ์˜ ์—ฐ๋™: OAuth ์ธ์ฆ, ๊ฒฐ์ œ ์‹œ์Šคํ…œ ์—ฐ๋™ ๋“ฑ ๋‹ค๋ฅธ ๋„๋ฉ”์ธ์˜ ํŽ˜์ด์ง€๋ฅผ ์—ด์–ด์•ผ ํ•  ๋•Œ
    • OAuth ์ธ์ฆ์ด๋‚˜ ์™ธ๋ถ€ ๊ฒฐ์ œ ์‹œ์Šคํ…œ ์—ฐ๋™ ์‹œ, ๋ณด์•ˆ์ด๋‚˜ ์‚ฌ์šฉ์ž ์ธ์ฆ ํ›„ ์ฝœ๋ฐฑ๋“ฑ์˜ UX ์ ์ธ ์ด์œ ๋กœ ๋ณ„๋„ ์ฐฝ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
    • ์ด๋•Œ window.open()์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ถ€๋ชจ-์ž์‹ ์ฐฝ ๊ฐ„ ํ†ต์‹ ์ด๋‚˜ ์ฐฝ ๋‹ซํž˜ ๊ฐ์ง€ ๋“ฑ์˜ ์ฒ˜๋ฆฌ๊ฐ€ ์‰ฌ์›Œ์ ธ์š”.
    • ๋ชจ๋‹ฌ๋กœ๋Š” ์™ธ๋ถ€ ๋„๋ฉ”์ธ ํŽ˜์ด์ง€๋ฅผ iframe์œผ๋กœ ๋„์šฐ๋Š” ๊ฒƒ์ด CORS, X-Frame-Options ๋˜๋Š” Content-Security-Policy ๋“ฑ์˜ ๋ณด์•ˆ ์ •์ฑ…๋“ฑ์˜ ์ด์œ ๋กœ ๋ถˆํŽธํ•ฉ๋‹ˆ๋‹ค.
  2. ํ”„๋ฆฐํŠธ ๊ธฐ๋Šฅ: ํŠน์ • ์ฝ˜ํ…์ธ ๋งŒ ํ”„๋ฆฐํŠธํ•˜๊ธฐ ์œ„ํ•œ ๋ณ„๋„ ์ฐฝ์ด ํ•„์š”ํ•  ๋•Œ
    • ์ƒˆ ์ฐฝ์— ํ•ด๋‹น ์ฝ˜ํ…์ธ ๋งŒ ๋ Œ๋”๋งํ•˜๊ณ  window.print()๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ์‹์ด ๋งŽ์ด ์‚ฌ์šฉ๋์Šต๋‹ˆ๋‹ค.
    • ๋ชจ๋‹ฌ์ด๋‚˜ ์˜ค๋ฒ„๋ ˆ์ด๋กœ๋Š” ์ „์ฒด ํŽ˜์ด์ง€์˜ ์ผ๋ถ€๋งŒ ๊น”๋”ํ•˜๊ฒŒ ์ธ์‡„ํ•˜๋Š” ์ธ์‡„ ๋ฒ”์œ„ ์ œ์–ด๊ฐ€ ์–ด๋ ค์›Œ ๊ธฐ์กด ํŽ˜์ด์ง€ ์ „์ฒด๊ฐ€ ์ธ์‡„๋ฉ๋‹ˆ๋‹ค.
    • ๋”ฐ๋ผ์„œ ์ƒˆ ์ฐฝ์ด ๊ฐ€์žฅ ๊ฐ„๋‹จํ•˜๊ณ  ํ™•์‹คํ•œ ๋ฐฉ๋ฒ•์ด๋ผ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
  3. ๋ฉ€ํ‹ฐํƒœ์Šคํ‚น UX: ์‚ฌ์šฉ์ž๊ฐ€ ๋‘ ํ™”๋ฉด์„ ๋™์‹œ์— ๋ณด๋ฉฐ ์ž‘์—…ํ•ด์•ผ ํ•  ๋•Œ
    • ๋‘ ๊ฐœ์˜ ์ฐฝ์„ ๋™์‹œ์— ํ™”๋ฉด์— ๋„์›Œ ์ƒํ˜ธ ๋น„๊ต ์ž‘์—…ํ•˜๋ ค๋ฉด ์ฐฝ ๋ถ„๋ฆฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
    • ๋ชจ๋‹ฌ์€ ํ•ญ์ƒ ๋ถ€๋ชจ ์ฐฝ ์œ„์— ๋–  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‘ ํ™”๋ฉด์„ ๋™์‹œ์— ๋ณผ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
    • ๋”ฐ๋ผ์„œ ์ƒˆ ์ฐฝ์„ ๋„์šฐ๋Š” ๊ฒƒ์ด ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
  4. ๋ ˆ๊ฑฐ์‹œ ์‹œ์Šคํ…œ ํ†ตํ•ฉ: ๊ธฐ์กด ์‹œ์Šคํ…œ๊ณผ์˜ ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ
    • ๊ธฐ์กด ์‹œ์Šคํ…œ์—์„œ ํŒ์—… ์ฐฝ์„ ํ†ตํ•œ ๋ฐ์ดํ„ฐ ๊ตํ™˜์ด๋‚˜ ์ธ์ฆ ๋“ฑ์˜ ๊ตฌ์กฐ๊ฐ€ ์ด๋ฏธ window.open()์— ๋งž์ถฐ์ ธ ์žˆ๋‹ค๋ฉด, ์ด๋ฅผ ๋ชจ๋‹ฌ๋กœ ๋Œ€์ฒดํ•˜๋Š” ๊ฒฝ์šฐ ํ˜ธํ™˜์„ฑ ์ด์Šˆ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  5. ๋ณ„๋„ ์œˆ๋„์šฐ ๊ธฐ๋Šฅ: ๋ถ€๋ชจ ์ฐฝ์˜ ์ƒˆ๋กœ๊ณ ์นจ์ด๋‚˜ ์ด๋™์—๋„ ์œ ์ง€๋˜์–ด์•ผ ํ•˜๋Š” ๋…๋ฆฝ์  ๊ธฐ๋Šฅ
    • ๋ชจ๋‹ฌ์ด๋‚˜ SPA ์ปดํฌ๋„ŒํŠธ๋กœ๋Š” ๊ตฌํ˜„์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
    • ์ƒˆ๋กœ์šด ํŒ์—…์ฐฝ๋งŒ์ด ์™„์ „ํžˆ ๋ณ„๋„์˜ ๋ธŒ๋ผ์šฐ์ € ์ปจํ…์ŠคํŠธ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

 

์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” window.open()์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์•ˆ์ „ํ•˜๊ณ  ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

window.open('javascript:focus()', 'myPopup', 'width=800,height=600');

 

๊ฒ‰๋ณด๊ธฐ์—” ์ž˜ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ด ๋ฐฉ์‹์€ ๋ณด์•ˆ์ƒ ๋ฌธ์ œ๊ฐ€ ์žˆ์œผ๋ฉฐ ๊ณต์‹์ ์œผ๋กœ ๊ถŒ์žฅ๋˜์ง€ ์•Š๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

์ด๋ฒˆ ๊ธ€์—์„  ๊ทธ ์ด์œ ์— ๋Œ€ํ•ด ์ ์–ด๋ณด๋ คํ•ฉ๋‹ˆ๋‹ค! ๋˜ํ•œ ์–ด๋–ค ๋ฐฉ์‹์ด ์•ˆ์ „ํ•˜๊ณ  ํ‘œ์ค€์— ๋ถ€ํ•ฉํ•˜๋Š”์ง€๋„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

 

 

javascript:focus() ๋ฐฉ์‹์˜ ์œ„ํ—˜์„ฑ

์ด ๋ฐฉ์‹์€ javascript: URL ์Šคํ‚ด์„ ์ด์šฉํ•ด ์ƒˆ ์ฐฝ์„ ์—ด๋ฉด์„œ focus() ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋ ค๋Š” ์˜๋„์ž…๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Ÿฐ ๋ฐฉ์‹์€ ๋ณด์•ˆ์ƒ ์ทจ์•ฝํ•ฉ๋‹ˆ๋‹ค.

 

MDN ๊ณต์‹ ๋ฌธ์„œ์—์„œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ช…ํ™•ํžˆ ๊ฒฝ๊ณ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

"Use of javascript: URLs on the web is discouraged as it may lead to execution of arbitrary code, similar to the ramifications of using eval()."

 

๋˜ํ•œ, ESLint์—์„œ๋„ no-script-url ๊ทœ์น™์„ ํ†ตํ•ด javascript: URL ์Šคํ‚ด ์‚ฌ์šฉ์„ ๊ธˆ์ง€ํ•˜๊ฑฐ๋‚˜ ๊ฒฝ๊ณ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ์ฝ”๋“œ๊ฐ€ ์™ธ๋ถ€ ์ž…๋ ฅ์— ์˜ํ•ด ์กฐ์ž‘๋˜๊ฑฐ๋‚˜ ์•…์šฉ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

 

์š”์•ฝํ•˜์ž๋ฉด

  • ๋ณด์•ˆ์ƒ ์œ„ํ—˜ (์ž„์˜ ์ฝ”๋“œ ์‹คํ–‰ ๊ฐ€๋Šฅ์„ฑ)
  • XSS(ํฌ๋กœ์Šค ์‚ฌ์ดํŠธ ์Šคํฌ๋ฆฝํŒ…) ๊ณต๊ฒฉ์˜ ๋ฒกํ„ฐ๊ฐ€ ๋  ์ˆ˜ ์žˆ์Œ
  • ์ตœ์‹  ๋ธŒ๋ผ์šฐ์ € ๋ฐ ๋ฆฐํ„ฐ ์ฐจ๋‹จ ๋Œ€์ƒ
  • ์œ ์ง€๋ณด์ˆ˜์™€ ์˜๋„ ํŒŒ์•…์ด ์–ด๋ ค์›€

 

ํ‘œ์ค€์ ์ด๊ณ  ์•ˆ์ „ํ•œ ๋ฐฉ๋ฒ•: about:blank ๋˜๋Š” ๋นˆ ๋ฌธ์ž์—ด

ํŒ์—…์„ ์•ˆ์ „ํ•˜๊ฒŒ ์—ด๊ณ  ์‹ถ๋‹ค๋ฉด, ๊ถŒ์žฅ๋˜๋Š” ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

const popup = window.open('about:blank', 'myPopup', 'width=800,height=600');
if (popup) {
  popup.location.href = '/your-target-page';
  popup.focus(); // ํ•„์š” ์‹œ ํฌ์ปค์Šค ์ด๋™
}

 

๋˜๋Š” ์•„์˜ˆ ๋นˆ ๋ฌธ์ž์—ด๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const popup = window.open('', 'myPopup', 'width=800,height=600');

 

์ด ๋ฐฉ์‹์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋ณด์•ˆ์ƒ ์•ˆ์ „ํ•จ
  • ํ‘œ์ค€ ์›น API ์‚ฌ์šฉ๋ฒ•์„ ์ค€์ˆ˜
  • ์ฝ”๋“œ ์˜๋„๊ฐ€ ๋ช…ํ™•ํ•จ
  • ๊ณต์‹ ๋ฌธ์„œ(MDN, W3C ๋“ฑ)์—์„œ๋„ ๊ถŒ์žฅํ•˜๋Š” ๋ฐฉ์‹

 

javascript:focus()์˜ ๋ชฉ์ ๊ณผ ์˜คํ•ด

๋งŽ์€ ๊ฐœ๋ฐœ์ž๋“ค์ด javascript:focus()๋ฅผ ์ดˆ๊ธฐ URL๋กœ ๋„ฃ๋Š” ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ๋นˆ ์ฐฝ์„ ์—ด ๋•Œ ํŒ์—…์ด ์ฐจ๋‹จ๋˜๋Š” ํ˜„์ƒ์„ ์šฐํšŒํ•˜๋ ค๊ณ 
  • ์ฐฝ์„ ์—ฐ ์งํ›„ ์ž๋™์œผ๋กœ ํฌ์ปค์Šค๋ฅผ ์ฃผ๋ ค๊ณ 

ํ•˜์ง€๋งŒ ์ตœ์‹  ๋ธŒ๋ผ์šฐ์ €๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŠน์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ์‚ฌ์šฉ์ž ํด๋ฆญ ์ด๋ฒคํŠธ ๋‚ด๋ถ€์—์„œ window.open()์„ ํ˜ธ์ถœํ•˜๋ฉด ๋Œ€๋ถ€๋ถ„ ์ฐจ๋‹จํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค
  2. ํฌ์ปค์Šค๊ฐ€ ํ•„์š”ํ•˜๋‹ค๋ฉด popup.focus()๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ๋” ๋ช…ํ™•ํ•˜๊ณ  ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค
  3. ์ผ๋ถ€ ์ตœ์‹  ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” ๋ณด์•ˆ ์ •์ฑ…์œผ๋กœ ์ธํ•ด javascript: URL์ด ์ž‘๋™ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

์ฆ‰, javascript:focus()๋Š” ๊ณผ๊ฑฐ์—๋Š” ํ†ตํ–ˆ์„์ง€ ๋ชฐ๋ผ๋„, ํ˜„๋Œ€ ์›น ๋ณด์•ˆ ํ™˜๊ฒฝ์—์„œ๋Š” ์ ์ ˆํ•˜์ง€ ์•Š์€ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

 

URL ๊ฐ์ฒด์™€ javascript: URL์€ ์™„์ „ํžˆ ๋‹ค๋ฆ…๋‹ˆ๋‹ค

ํ˜น์‹œ URL์ด๋ผ๋Š” ๋‹จ์–ด ๋•Œ๋ฌธ์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ๋ฒ•์„ ๋– ์˜ฌ๋ฆฌ์‹  ๋ถ„๋„ ๊ณ„์‹ค ํ…๋ฐ์š”?!

const url = new URL(window.location.href);
const tag = url.searchParams.get('tag');

 

์ด๊ฑด URL ์ •๋ณด๋ฅผ ๋ถ„์„ํ•˜๊ณ  ์กฐ์ž‘ํ•˜๊ธฐ ์œ„ํ•œ ๊ฐ์ฒด๋กœ, ์ฃผ์†Œ ํŒŒ์‹ฑ์„ ์œ„ํ•ด ์•„์ฃผ ์œ ์šฉํ•˜๊ฒŒ ์“ฐ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ์ถ”์ถœ, ๊ฒฝ๋กœ ์กฐ์ž‘ ๋“ฑ์— ์ž์ฃผ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

 

๋ฐ˜๋ฉด 'javascript:...'๋Š” ๋ธŒ๋ผ์šฐ์ €์— ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ง์ ‘ ์‹คํ–‰ํ•˜๋ผ๊ณ  ๋ช…๋ นํ•˜๋Š” ์Šคํ‚ด์ด๊ธฐ ๋•Œ๋ฌธ์—, ๋ชฉ์ ๋„ ์“ฐ์ž„๋„ ์™„์ „ํžˆ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

 

ํ•ญ๋ชฉ์„ค๋ช… - ์‚ฌ์šฉ ์šฉ๋„

new URL(...) ์ฃผ์†Œ ํŒŒ์‹ฑ์„ ์œ„ํ•œ URL ๊ฐ์ฒด ์•ˆ์ „ํ•˜๊ณ  ํ‘œ์ค€์ ์ธ ๋ฐฉ๋ฒ•
'javascript:focus()' ์‹คํ–‰ ์ฝ”๋“œ๋ฅผ URL์— ๋„ฃ๋Š” ๋ฐฉ์‹ ๋ณด์•ˆ์ƒ ์œ„ํ—˜, ๋น„๊ถŒ์žฅ ๋ฐฉ์‹

 

๋ถ€๋ชจ-์ž์‹ ์ฐฝ ๊ด€๊ณ„์™€ ์ œ์–ด

window.open()์œผ๋กœ ์—ด๋ฆฐ ํŒ์—…์€ ๋ถ€๋ชจ ํŽ˜์ด์ง€์™€ ๋ฐ€์ ‘ํ•œ ๊ด€๊ณ„๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ์ด๋ฅผ ํ™œ์šฉํ•˜๊ฑฐ๋‚˜ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

๋ถ€๋ชจ ํŽ˜์ด์ง€์—์„œ ์ž์‹ ์ฐฝ ์ œ์–ดํ•˜๊ธฐ

ํŒ์—…์„ ์—ฐ ๋ถ€๋ชจ ํŽ˜์ด์ง€๋Š” ๋ฐ˜ํ™˜๋œ ์ฐธ์กฐ๋ฅผ ํ†ตํ•ด ์ž์‹ ์ฐฝ์„ ์™„์ „ํžˆ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

const popup = window.open('about:blank', 'myPopup');
// ์ž์‹ ์ฐฝ ๋‚ด์šฉ ๋ณ€๊ฒฝ
popup.document.body.innerHTML = '<h1>๋ถ€๋ชจ๊ฐ€ ๋ณ€๊ฒฝํ•œ ๋‚ด์šฉ</h1>';
// ์ž์‹ ์ฐฝ ํฌ๊ธฐ/์œ„์น˜ ์กฐ์ •
popup.resizeTo(500, 300);
popup.moveTo(100, 100);
// ์ž์‹ ์ฐฝ ์ข…๋ฃŒ
popup.close();

 

์ž์‹ ์ฐฝ ์ข…๋ฃŒ ์‹œ๋‚˜๋ฆฌ์˜ค

์—ฌ๋Ÿฌ ์ƒํ™ฉ์—์„œ ์ž์‹ ์ฐฝ์ด ์ž๋™์œผ๋กœ ์ข…๋ฃŒ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ๋ถ€๋ชจ ํŽ˜์ด์ง€ ์ด๋™ ๋˜๋Š” ์ƒˆ๋กœ๊ณ ์นจ ์‹œ
    // ํŽ˜์ด์ง€ ์ด๋™ ์ „์— ์ž์‹ ์ฐฝ ๋‹ซ๊ธฐ
    window.addEventListener('beforeunload', () => {
      if (popup && !popup.closed) {
        popup.close();
      }
    });

     

  2. ๋‹ค๋ฅธ SPA ๋ผ์šฐํŠธ๋กœ ์ด๋™ ์‹œ
     
    // React Router ๋“ฑ์˜ ๋ผ์šฐํŠธ ๋ณ€๊ฒฝ ์ด๋ฒคํŠธ์— ์—ฐ๊ฒฐ
    router.beforeEach((to, from, next) => {
      if (window.myPopup && !window.myPopup.closed) {
        window.myPopup.close();
      }
      next();
    });

 

์ž์‹ ์ฐฝ์ด ๋ถ€๋ชจ ํŽ˜์ด์ง€ ๊ฐ์ง€ํ•˜๊ธฐ

์ž์‹ ์ฐฝ์—์„œ๋Š” ๋ถ€๋ชจ ์ฐฝ์˜ ์กด์žฌ์™€ ์ƒํƒœ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// ์ž์‹ ์ฐฝ์—์„œ ๋ถ€๋ชจ ์ฐฝ ํ™•์ธ ๋ฐ ๋Œ€์‘ํ•˜๊ธฐ
if (window.opener && !window.opener.closed) {
  // ๋ถ€๋ชจ ์ฐฝ์ด ์กด์žฌํ•˜๊ณ  ์—ด๋ ค์žˆ์Œ
  console.log('๋ถ€๋ชจ ์ฐฝ URL:', window.opener.location.href);
} else {
  // ๋ถ€๋ชจ ์ฐฝ์ด ๋‹ซํ˜”๊ฑฐ๋‚˜ ์—†์Œ
  console.log('๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰ ์ค‘');
}

 

๋ธŒ๋ผ์šฐ์ € ํ˜ธํ™˜์„ฑ๊ณผ ์ถ”๊ฐ€ ๊ณ ๋ ค์‚ฌํ•ญ

์ตœ์‹  ๋ธŒ๋ผ์šฐ์ €๋“ค์€ window.open()์— ๋Œ€ํ•ด ์ ์  ๋” ์—„๊ฒฉํ•œ ์ •์ฑ…์„ ์ ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

  • Chrome, Safari: ์‚ฌ์šฉ์ž ์ œ์Šค์ฒ˜(ํด๋ฆญ ๋“ฑ) ์—†์ด window.open()์„ ํ˜ธ์ถœํ•˜๋ฉด ์ฐจ๋‹จ๋ฉ๋‹ˆ๋‹ค
  • Firefox: ํŒ์—… ์ฐจ๋‹จ ์„ค์ •์— ๋”ฐ๋ผ ๋™์ž‘์ด ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค
  • ๋ชจ๋ฐ”์ผ ๋ธŒ๋ผ์šฐ์ €: ๋งŽ์€ ๋ชจ๋ฐ”์ผ ๋ธŒ๋ผ์šฐ์ €์—์„œ ํŒ์—… ์ž์ฒด๋ฅผ ์ œํ•œ์ ์œผ๋กœ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค

๋”ฐ๋ผ์„œ ํŒ์—… ๋Œ€์‹  ๋ชจ๋‹ฌ์ด๋‚˜ ์ธ๋ผ์ธ ์ฝ˜ํ…์ธ ๋ฅผ ๊ณ ๋ คํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋Œ€์•ˆ์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

// ํŠน๋ณ„ํ•œ ์ด์œ ๊ฐ€ ์—†๋‹ค๋ฉด ํŒ์—… ๋Œ€์‹  ๋ชจ๋‹ฌ์„ ๊ณ ๋ คํ•ด๋ณด์„ธ์š”
document.getElementById('openModal').addEventListener('click', () => {
  document.getElementById('myModal').style.display = 'block';
});

 

์š”์•ฝ ๋ฐ ๊ฒฐ๋ก 

  • ๋ชจ๋˜ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์ฃผ๋ฅ˜์ธ ์ง€๊ธˆ๋„ OAuth, ๊ฒฐ์ œ ์—ฐ๋™, ํ”„๋ฆฐํŠธ ๊ธฐ๋Šฅ ๋“ฑ์„ ์œ„ํ•ด window.open()์ด ํ•„์š”ํ•œ ์ƒํ™ฉ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • javascript:focus() ๋ฐฉ์‹์€ ๋ณด์•ˆ์ƒ ์œ„ํ—˜ํ•˜๊ณ , MDN ๋ฐ ESLint์—์„œ๋„ ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ํŒ์—…์„ ์—ด ๋•Œ๋Š” about:blank๋‚˜ ๋นˆ ๋ฌธ์ž์—ด์„ ์‚ฌ์šฉํ•˜๊ณ , ๊ทธ ์ดํ›„์— popup.location.href์™€ popup.focus()๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์ด ๊ฐ€์žฅ ํ‘œ์ค€์ ์ด๊ณ  ์•ˆ์ „ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ถ€๋ชจ ํŽ˜์ด์ง€์—์„œ๋Š” ํŒ์—… ์ฐฝ์„ ์™„์ „ํžˆ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ํŽ˜์ด์ง€ ์ „ํ™˜ ์‹œ ํŒ์—… ์ฐฝ์„ ์ ์ ˆํžˆ ๊ด€๋ฆฌ(์ข…๋ฃŒ)ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • React ๊ฐ™์€ ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ๋Š” useRef์™€ useEffect๋ฅผ ํ™œ์šฉํ•ด ํŒ์—…์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ์ปดํฌ๋„ŒํŠธ์™€ ์—ฐ๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • URL ๊ฐ์ฒด์™€ javascript: URL์€ ๊ฐœ๋…์ด ์™„์ „ํžˆ ๋‹ค๋ฅด๋ฏ€๋กœ ํ˜ผ๋™ํ•˜์ง€ ๋งˆ์„ธ์š”.

ํŠน์ • ์ƒํ™ฉ์—์„œ๋Š” window.open์ด ์—ฌ์ „ํžˆ ์ ์ ˆํ•œ ์„ ํƒ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋„ ๋” ์•ˆ์ „ํ•œ ๋ฐฉ์‹์œผ๋กœ ์ฝ”๋”ฉํ•ด ๋ณด์‹œ๋Š” ๊ฑด ์–ด๋–จ๊นŒ์š”?!

๊ถ๊ธˆํ•˜์‹  ์ ์ด ์žˆ๋‹ค๋ฉด ์–ธ์ œ๋“ ์ง€ ๋Œ“๊ธ€๋กœ ๋‚จ๊ฒจ์ฃผ์„ธ์š”! 

 

 

๐Ÿ“ƒ ์ฐธ๊ณ  ๋ฌธํ—Œ  
JAVASCRIPT.INFO - Popups and window methods
W3 Schools - Window open()
eslint/no-script-url
MDN Web Docs
Popup or Modal

 

์‹œ๊ฐ„์ด ์ง€๋‚œ ํ›„, ์ฝ”๋“œ๋ฅผ ๋ฆฌํŒฉํ† ๋ง ํ•˜๋Š” ๊ณผ์ •์—์„œ ์ž‘์—… ์ด์œ ์— ๋Œ€ํ•ด ์ฐพ์•„๋ณด๊ธฐ ์œ„ํ•ด TIL ์นดํ…Œ๊ณ ๋ฆฌ๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค!

 

์˜ค๋Š˜์€ Vanilla JavaScript๋กœ ์›น ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๋˜ ์ค‘ ๋งˆ์šฐ์Šค ๋‹ค์šด(mousedown) ์ด๋ฒคํŠธ์™€ ๋งˆ์šฐ์Šค ์—…(mouseup) ์ด๋ฒคํŠธ, ๊ทธ๋ฆฌ๊ณ  ํด๋ฆญ(click) ์ด๋ฒคํŠธ ๊ฐ„์˜ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•ด, ๊ฐ ์ด๋ฒคํŠธ์˜ ๋™์ž‘์ด ์„œ๋กœ ๋…๋ฆฝ์ ์œผ๋กœ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋„๋ก ์กฐ์ •ํ•œ ๋‚ด์šฉ์„ ๊ฐ„๋‹จํžˆ ๊ธฐ๋กํ•˜๋ คํ•ฉ๋‹ˆ๋‹ค.

 

 

eventType์— ์™œ click์ด ์˜ค์ง€ ์•Š์„๊นŒ..?!

๋ฌธ์ œ ์ƒํ™ฉ: ๋‘ ๊ฒฝ์šฐ์˜ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋ง

์‚ฌ์šฉ์ž๊ฐ€ ์ƒํ’ˆ ๋ฒ„ํŠผ์„ ํด๋ฆญํ–ˆ์„ ๋•Œ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค:

  1. ์ž”์•ก์ด ๋ถ€์กฑํ•œ ๊ฒฝ์šฐ
  2. ์ž”์•ก์ด ์ถฉ๋ถ„ํ•œ ๊ฒฝ์šฐ
  3. ๋งˆ์šฐ์Šค ๋‹ค์šด/์—… ์ด๋ฒคํŠธ์™€ ํด๋ฆญ ์ด๋ฒคํŠธ์˜ ์ƒํ˜ธ์ž‘์šฉ

์ด๋Ÿฌํ•œ ์ƒํ™ฉ์—์„œ ๋งˆ์šฐ์Šค ์—… ์ด๋ฒคํŠธ์˜ ๋™์ž‘์— ๊ฐ€๋ ค์ ธ ํด๋ฆญ ์ด๋ฒคํŠธ๊ฐ€ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š” ์ƒํ™ฉ์ด ๋ฐœ์ƒํ–ˆ์–ด์š”.

 

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•: ์กฐ๊ฑด๋ถ€ ์ด๋ฒคํŠธ ๋“ฑ๋ก

๋จผ์ € ๊ธฐ์กด ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

  setEvent() {
    const { onSelect, onMouseDown, onMouseUp } = this.props;

    if (onSelect) {
      this.addEvent('click', '.product-button', (e) => {
        const button = e.target.closest('.product-button');
        if (!button) return;
        const productId = Number(button.dataset.id);
        onSelect(productId);
      });
    }

    if (onMouseDown) {
      this.addEvent('mousedown', '.product-button', onMouseDown);
    }

    if (onMouseUp) {
      this.addEvent('mouseup', '.product-button', onMouseUp);
    }
  }

 

๋ณ€๊ฒฝ๋œ ์ฝ”๋“œ์ž…๋‹ˆ๋‹ค.

setEvent() {
  const { onSelect, onMouseDown, onMouseUp, product } = this.props;

  // ๊ฐ€๊ฒฉ์ด ๋ถ€์กฑํ•  ๋•Œ๋งŒ mousedown/mouseup ์ด๋ฒคํŠธ ๋“ฑ๋ก
  if (onMouseDown && this.state.balance < product.price) {
    this.addEvent('mousedown', '.product-button', () => {
      onMouseDown(product);
    });
    this.addEvent('mouseup', '.product-button', () => {
      onMouseUp();
    });
  } else {
    // ๊ฐ€๊ฒฉ์ด ์ถฉ๋ถ„ํ•˜๊ฑฐ๋‚˜ ์กฐ๊ฑด์— ๋งž์ง€ ์•Š์œผ๋ฉด click ์ด๋ฒคํŠธ๋งŒ ๋“ฑ๋ก
    this.addEvent('click', '.product-button', (e) => {
      const button = e.target.closest('.product-button');
      if (!button) return;
      const productId = Number(button.dataset.id);
      onSelect(productId);
    });
  }
}

 

ํ•ต์‹ฌ ์ ‘๊ทผ ๋ฐฉ์‹

  1. ์กฐ๊ฑด๋ถ€ ์ด๋ฒคํŠธ ๋“ฑ๋ก: ํ˜„์žฌ ์ƒํƒœ์— ๋”ฐ๋ผ ์ ์ ˆํ•œ ์ด๋ฒคํŠธ๋ฅผ ๋™์ ์œผ๋กœ ๋ฐ”์ธ๋”ฉํ•ฉ๋‹ˆ๋‹ค.
  2. ์ด๋ฒคํŠธ ์œ„์ž„: closest() ๋ฉ”์„œ๋“œ๋ฅผ ํ™œ์šฉํ•ด ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์„ ํšจ์œจ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. (๊ธ€์—๋Š” ์—†์ง€๋งŒ component.js์—์„œ ์ฒ˜๋ฆฌ)
  3. ์ƒํƒœ ๊ธฐ๋ฐ˜ ๋กœ์ง: balance์™€ product.price๋ฅผ ๋น„๊ตํ•˜์—ฌ ์ด๋ฒคํŠธ ํ๋ฆ„์„ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค.

 

+ Recent posts