/**
 * @파일 obj.js
 * @모듈 객체
 */

/**
 * @callback obj:EachCallback
 *
 * @param {혼합} 값
 * 반복되는 개체의 현재 키입니다.
 *
 * @param {문자열} 키
 * 반복되는 객체의 현재 키-값
 */

/**
 * @callback obj:ReduceCallback
 *
 * @param {혼합} 축적
 * 감소 루프를 통해 누적되는 값.
 *
 * @param {혼합} 값
 * 반복되는 개체의 현재 키입니다.
 *
 * @param {문자열} 키
 * 반복되는 객체의 현재 키-값
 *
 * @return {혼합}
 * 새로운 누적 값.
 */
const toString = Object.prototype.toString;

/**
 * 객체의 키 얻기
 *
 * @param {객체}
 * 키를 가져올 객체
 *
 * @return {문자열[]}
 * 개체의 키 배열입니다. 다음과 같은 경우 빈 배열을 반환합니다.
 * 전달된 객체가 유효하지 않거나 키가 없습니다.
 *
 * @사적인
 */
const 키 = 함수(객체) {
  반환 isObject(객체) ? Object.keys(객체) : [];
};

/**
 * 객체에 대한 배열과 같은 반복.
 *
 * @param {객체} 객체
 * 반복할 객체
 *
 * @param {obj:EachCallback} fn
 * 객체의 각 키에 대해 호출되는 콜백 함수.
 */
내보내기 함수 each(object, fn) {
  키(객체).forEach(키 => fn(객체[키], 키));
}

/**
 * 객체에 대한 배열과 같은 리듀스.
 *
 * @param {객체} 객체
 * 축소하려는 객체.
 *
 * @param {함수} fn
 * 객체의 각 키에 대해 호출되는 콜백 함수. 그것
 * 누적된 값과 반복당 값과 키를 받습니다.
 * 인수로.
 *
 * @param {혼합} [이니셜 = 0]
 * 시작 값
 *
 * @return {혼합}
 * 최종 누적 값입니다.
 */
내보내기 함수 reduce(object, fn, initial = 0) {
  return 키(객체).reduce((누적, 키) => fn(accum, object[key], key), initial);
}

/**
 * Object.assign 스타일 객체 얕은 병합/확장.
 *
 * @param {객체} 대상
 * @param {객체} ...소스
 * @return {객체}
 */
내보내기 기능 assign(target, ...sources) {
  if (객체.할당) {
    return Object.assign(대상, ...소스);
  }

  sources.forEach(소스 => {
    경우 (! 소스) {
      반품;
    }

    각각(소스, (값, 키) => {
      대상[키] = 값;
    });
  });

  반환 대상;
}

/**
 * 값이 DOM 노드를 포함하여 모든 종류의 객체인지 여부를 반환합니다.
 * 배열, 정규식 등 그러나 기능은 아닙니다.
 *
 * 이렇게 하면 `null` 값에 `typeof`를 사용하는 문제를 피할 수 있습니다.
 * 결과는 `'객체'`입니다.
 *
 * @param {객체} 값
 * @return {부울}
 */
내보내기 함수 isObject(value) {
  리턴!!값 && typeof 값 === '객체';
}

/**
 * 객체가 "일반" 객체인지 여부를 반환합니다.
 * `Object`의 직접 인스턴스.
 *
 * @param {객체} 값
 * @return {부울}
 */
내보내기 기능 isPlain(value) {
  isObject(값) 반환 &&
    toString.call(값) === '[객체 객체]' &&
    value.constructor === 개체;
}