Skip to content

file-upload.js

js
const handleClick = async () => {
  const files = await getFiles();

  if (files.length) {
    // 업로드 API 실행
    console.log(files);
  }
};

const getFiles = () => {
  return new Promise((resolve) => {
    const fileInput = document.createElement("input");
    const handler = () => {
      resolve(fileInput.files);
    };

    fileInput.setAttribute("type", "file");
    fileInput.setAttribute("accept", "image/*");
    fileInput.setAttribute("multiple", "true");

    fileInput.onchange = handler;
    fileInput.oncancel = handler;

    fileInput.click();
  });
};

debounce.js

js
/**
 * Debounce
 *
 * @param callback {Function} Callback function
 * @param _delay {Number} Delay time
 * @return {Function} Event Listener
 */
const debounce = (callback, ms) => {
  let timer = null

  return function(...args){
    const self = this
    clearTimeout(timer)
    timer = setTimeout(() => {
      callback.apply(self, args)
    }, ms)
  }
}

const log = debounce(console.log, 100)
log('1')
log('2')
log('3')
log('4')

// 4

debounce.ts

ts
export const debounce = (callback, ms = 100) => {
  let timer

  return function(...args: any[]) {
    clearTimeout(timer)
    timer = setTimeout(() => {
      callback(...args)
    }, ms)
  }
}

highlight.js

js
const highlight = (target, keyword, template = `<span>$1</span>`) => {
  if (!keyword) {
    return target
  }
  const reg = new RegExp(`(${keyword})`, 'gi')
  return target.replace(reg, template)
}

is-primitive.js

js
const isPrimitive = value => {
  switch (true) {
    case value === undefined:
    case value === null:
      return true
    case typeof value === 'object':
    case typeof value === 'function':
    case Number.isNaN(value):
      return false
    default:
      return true
  }
}

module.exports = {isPrimitive}

is-object.js

js
const isNull = value => value === null;
const isArray = value => Array.isArray(value);
const isObject = value => [
  !isNull(value),
  !isArray(value),
  typeof value === 'object',
].every(v => v);

const arr = [null, undefined, {}, '', []];
console.log(arr.map(isObject)); // [false, false, true, false, false]
console.log(arr.map(isArray)); // [false, false, false, false, true]

is-valid-url.js

js
const isValidUrl = url => {
  try {
    new URL(url)
    return true
  } catch (e) {
    return false
  }
}

console.log(isValidUrl('http://www.naver.com')) // true
console.log(isValidUrl('http:/')) // false

more-text.html

html
<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport"
        content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <style>
    .txt{
      width: 200px;
      max-height: 35px;
      line-height: 20px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: normal;
      word-wrap: break-word;
      display: -webkit-box;
      -webkit-line-clamp: 2;
      -webkit-box-orient: vertical;
    }
    .txt.show{display:block;max-height:none}
    .txt.show + .more{display:none}
  </style>
</head>
<body>
<div class="wrap">
  <div class="txt">
    가나다라마가나다라마가나다라마가나다라마가나다라마가나다라마가나다라마가나다라마가나다라마가나다라마가나다라마
    가나다라마가나다라마가나다라마가나다라마가나다라마가나다라마가나다라마가나다라마가나다라마가나다라마가나다라마
  </div>
  <a href="#" class="more" onclick="toggle()">More</a>
</div>
<script>
  const toggle = () => {
    const txt = document.querySelector('.txt').classList
    if (txt.contains('show')) {
      txt.remove('show')
    } else {
      txt.add('show')
    }
  }
</script>
</body>
</html>

overlap.js

js
const isOverlap = (base, target) => {
  if (target.end <= base.begin) return false
  if (target.begin >= base.end) return false
  return true
}


const assert = v1 => v2 => console.log(v1 === v2)
const base = {begin: 2, end: 4}

assert(false)(isOverlap(base, {begin: 0, end: 1})) // true
assert(false)(isOverlap(base, {begin: 1, end: 2})) // true
assert(true)(isOverlap(base, {begin: 2, end: 3})) // true
assert(true)(isOverlap(base, {begin: 3, end: 4})) // true
assert(false)(isOverlap(base, {begin: 4, end: 5})) // true
assert(false)(isOverlap(base, {begin: 5, end: 6})) // true
assert(true)(isOverlap(base, {begin: 2, end: 4})) // true
assert(true)(isOverlap(base, {begin: 1, end: 5})) // true

query-to-string.js

js
const queryToString = obj => {
  if (!obj) {
    return ''
  }

  const query = Object
    .entries(obj)
    .map(item => item.join('='))
    .join('&')
  return `?${query}`
}

console.log(queryToString({
  name: 'Peter.Cho',
  address: 'Korea'
}))

stepper.ts

ts
export class Stepper {
  readonly min: number
  readonly max: number
  readonly step: number
  private position: number

  private constructor(min: number, max: number, step: number, position: number) {
    this.min = min
    this.max = max
    this.step = step
    this.position = position
  }

  get isMax(): boolean {
    return this.position === this.max
  }
  get isMin(): boolean {
    return this.position === this.min
  }
  get currentPosition(): number {
    return this.position
  }

  next(): void {
    this.changePosition(this.position + this.step)
  }
  prev(): void {
    this.changePosition(this.position - this.step)
  }
  moveTo(position: number): void {
    this.changePosition(position)
  }

  private changePosition(position: number): void {
    this.position = this.calibratePosition(position)
  }
  private calibratePosition(position: number): number {
    return position > this.max
      ? this.max
      : position < this.min
        ? this.min
        : position
  }

  static create(max: number): Stepper {
    return new Stepper(1, max, 1, 1)
  }
}

subset.js

js
// base: [begin: number, end: number]
// target: [begin: number, end: number]
const isSubset = (base, target) => {
  if (base[0] > target[0]) return false
  if (base[1] < target[1]) return false
  if (base[0] >= target[1] ) return false
  if (base[1] <= target[0] ) return false
  return true
}


const assert = v1 => v2 => console.log(v1 === v2)
const base = [2, 4]

assert(false)(isSubset(base, [0, 1]))
assert(false)(isSubset(base, [1, 2]))
assert(true)(isSubset(base, [2, 3]))
assert(true)(isSubset(base, [3, 4]))
assert(false)(isSubset(base, [4, 5]))
assert(false)(isSubset(base, [5, 6]))

assert(true)(isSubset(base, [2, 4]))
assert(false)(isSubset(base, [1, 5]))

throttle.js

js
/**
 * Throttle
 *
 * @param callback {Function} Callback function
 * @param _threshhold {Number} Throttle time
 * @return {Function} Event Listener
 */
const throttle = (callback, ms = 100) => {
  let timer = null
  let last = 0

  return function (...args) {
    const self = this
    const now = +new Date

    if (last && now < last + ms){
      clearTimeout(timer)
      timer = setTimeout(() => {
        last = now
        callback.apply(self, args)
      }, ms)
    } else {
      last = now
      callback.apply(self, args)
    }
  }
}


const log = throttle(console.log, 1000)
setInterval(() => {
  console.log('------')
  log('1000')
  console.log('------')
}, 500)

throttle.ts

ts
export const throttle = (callback, ms = 100) => {
  let timer
  let last = 0

  return function(...args: any[]) {
    const now = Date.now()

    if (last && now < last + ms) {
      clearTimeout(timer)
      timer = setTimeout(() => {
        last = now
        callback(...args)
      }, ms)
    } else {
      last = now
      callback(...args)
    }
  }
}

toggle.ts

ts
export class ToggleHelper {
  private state: boolean
  private constructor(state: boolean) {
    this.state = state
  }
  on(): void {
    this.state = true
  }
  off(): void {
    this.state = false
  }
  toggle(): void {
    this.state = !this.state
  }
  get isOn(): boolean {
    return this.state
  }
  static create(state: boolean): ToggleHelper {
    return new ToggleHelper(state)
  }
}