<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Frontend Developer</title>
    <link>https://agal.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 27 Aug 2026 10:21:06 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>AGAL</managingEditor>
    <item>
      <title>React에서 순환 참조 문제 해결하기</title>
      <link>https://agal.tistory.com/238</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;React 프로젝트를 진행하다 보면 종종 순환 참조(Circular Dependency) 문제에 직면할 때가 있습니다. 순환 참조는 두 개 이상의 모듈이 서로를 직접적으로 또는 간접적으로 참조하는 경우 발생합니다. 이 문제는 런타임 에러를 발생시키고 애플리케이션이 제대로 동작하지 않게 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 글에서는 React에서 &lt;code&gt;React.lazy()&lt;/code&gt;와 &lt;code&gt;import()&lt;/code&gt;를 사용하여 순환 참조 문제를 해결하는 방법에 대해 알아보겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문제 상황&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;React와 Material-UI(MUI)를 사용하여 커스텀 텍스트 필드와 셀렉트 필드 컴포넌트를 개발하던 중 순환 참조(circular dependency) 문제에 직면했습니다. 구체적으로, &lt;code&gt;StyledSelectField&lt;/code&gt; 컴포넌트가 &lt;code&gt;CustomTextField&lt;/code&gt;를 참조하고, 동시에 &lt;code&gt;CustomSelectField&lt;/code&gt;가 &lt;code&gt;StyledSelectField&lt;/code&gt;를 참조하는 상황이었습니다.&lt;/p&gt;
&lt;pre class=&quot;clean&quot;&gt;&lt;code&gt;// StyledCustomField.tsx
import { CustomTextField } from &quot;./CustomTextField&quot;;

// CustomSelectField.tsx
import { StyledCustomField } from &quot;./CustomSelectField.styles&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로 인해 다음과 같은 오류가 발생했습니다:&lt;/p&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;Uncaught ReferenceError: Cannot access 'CustomTextField' before initialization
    at CustomSelectField.styles.tsx:4:41&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;해결 방법: React.lazy()와 동적 import 활용&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 해결하기 위해 React의 &lt;code&gt;lazy()&lt;/code&gt; 함수와 동적 &lt;code&gt;import()&lt;/code&gt;를 사용했습니다. 다음은 해결 코드입니다:&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;import { styled } from &quot;@mui/material&quot;;
import { lazy } from &quot;react&quot;;

const CustomTextField = lazy(() =&amp;gt;
  import(&quot;@design-system/shared/ui/&quot;).then((module) =&amp;gt; ({ default: module.CustomTextField })),
);

export const StyledSelectField = styled(CustomTextField)(() =&amp;gt; ({
  &quot;&amp;amp; .MuiInputBase-input &quot;: {
    lineHeight: &quot;inherit&quot;,
  },
}));&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;코드 설명&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;code&gt;lazy()&lt;/code&gt; 함수: React의 &lt;code&gt;lazy()&lt;/code&gt; 함수는 동적으로 컴포넌트를 불러올 수 있게 해줍니다. 이는 코드 분할(code splitting)을 가능하게 하여, 필요한 시점에 컴포넌트를 로드할 수 있습니다.&lt;/li&gt;
&lt;li&gt;동적 &lt;code&gt;import()&lt;/code&gt;: &lt;code&gt;import()&lt;/code&gt; 함수를 사용하여 &lt;code&gt;CustomTextField&lt;/code&gt; 컴포넌트를 동적으로 불러옵니다. 이 방식은 모듈을 비동기적으로 로드하여 순환 참조 문제를 해결합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;then()&lt;/code&gt; 메서드: 동적 import가 완료된 후, &lt;code&gt;then()&lt;/code&gt; 메서드를 통해 모듈에서 &lt;code&gt;CustomTextField&lt;/code&gt; 컴포넌트를 추출합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;styled()&lt;/code&gt; 함수: MUI의 &lt;code&gt;styled()&lt;/code&gt; 함수를 사용하여 동적으로 불러온 &lt;code&gt;CustomTextField&lt;/code&gt;에 추가적인 스타일을 적용합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 접근 방식은 &lt;code&gt;CustomTextField&lt;/code&gt;의 로딩을 지연시켜 순환 참조 문제를 해결합니다. &lt;code&gt;StyledSelectField&lt;/code&gt;가 정의될 때 &lt;code&gt;CustomTextField&lt;/code&gt;의 실제 구현은 아직 로드되지 않았기 때문에, JavaScript 엔진은 순환 참조를 감지하지 않습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;순환 참조 해결을 위한 다른 방법들&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;모듈 구조 재설계&lt;/b&gt;: 컴포넌트 간의 의존성을 재검토하고, 가능하다면 구조를 변경하여 순환 참조를 제거합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;공통 기본 컴포넌트 생성&lt;/b&gt;: 여러 컴포넌트가 공유하는 기본 스타일과 기능을 가진 새로운 컴포넌트를 만들어 사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;HOC(Higher-Order Component) 패턴 사용&lt;/b&gt;: 스타일을 적용하는 HOC를 만들어 여러 컴포넌트에 재사용합니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Context API 활용&lt;/b&gt;: 공통 스타일이나 속성을 Context를 통해 제공하여 직접적인 import를 줄입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스타일 분리&lt;/b&gt;: 스타일을 별도의 파일로 분리하여 컴포넌트 간 직접적인 의존성을 줄입니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;결론&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순환 참조는 React 애플리케이션 개발 시 자주 마주치는 문제 중 하나입니다. &lt;code&gt;lazy()&lt;/code&gt;와 동적 &lt;code&gt;import()&lt;/code&gt;를 활용한 해결 방법은 코드의 구조를 크게 변경하지 않으면서도 효과적으로 문제를 해결할 수 있는 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방법은 특히 대규모 프로젝트에서 유용하며, 코드 분할의 이점도 함께 얻을 수 있습니다. 그러나 상황에 따라 다른 해결 방법들도 고려해 볼 수 있으며, 프로젝트의 구조와 요구사항에 가장 적합한 방법을 선택하는 것이 중요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순환 참조 문제에 직면했을 때, 이러한 다양한 해결 방법들을 고려하여 가장 적절한 방법을 선택하면, 더 견고하고 유지보수가 용이한 React 애플리케이션을 개발할 수 있을 것입니다.&lt;/p&gt;</description>
      <category>Front-end/React.js</category>
      <author>AGAL</author>
      <guid isPermaLink="true">https://agal.tistory.com/238</guid>
      <comments>https://agal.tistory.com/238#entry238comment</comments>
      <pubDate>Wed, 23 Oct 2024 18:13:28 +0900</pubDate>
    </item>
    <item>
      <title>React 프로젝트에서 SVG 파일 최적화 및 컴포넌트화</title>
      <link>https://agal.tistory.com/237</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;React 프로젝트에서 SVG 파일을 효율적으로 사용하려면, SVGR을 이용해 SVG 파일을 React 컴포넌트로 변환하고, SVGO를 사용해 파일을 최적화할 수 있습니다. 이 글에서는 pnpm, Vite, React, TypeScript 환경에서 이를 구현하는 방법을 단계별로 설명합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 필수 패키지 설치하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저, 필요한 패키지를 설치합니다. &lt;code&gt;pnpm&lt;/code&gt;을 사용하여 프로젝트의 개발 의존성으로 추가합니다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;pnpm add -D @svgr/rollup @svgr/cli svgo&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;code&gt;@svgr/rollup&lt;/code&gt;: Vite에서 SVGR을 사용할 수 있게 해주는 플러그인입니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@svgr/cli&lt;/code&gt;: SVGR의 CLI 도구로, SVG를 React 컴포넌트로 변환합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;svgo&lt;/code&gt;: SVG 파일을 최적화하는 도구입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. Vite 설정에 SVGR 추가하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Vite 설정 파일에 SVGR 플러그인을 추가하여 SVG 파일을 React 컴포넌트로 변환할 수 있도록 합니다.&lt;/p&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import svgr from '@svgr/rollup';

export default defineConfig({
  plugins: [
    react(),
    svgr(),
  ],
});&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: oklch(0.304 0.04 213.681); text-align: left;&quot;&gt;svg.d.ts 파일&lt;/span&gt;&lt;span style=&quot;color: oklch(0.304 0.04 213.681); text-align: left;&quot;&gt;&amp;nbsp;수정하기&lt;/span&gt;&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: oklch(0.304 0.04 213.681); text-align: left;&quot;&gt;TypeScript에서 SVG 파일을 모듈로 인식할 수 있도록 선언 파일을 추가합니다. src 디렉토리에 svg.d.ts 파일을 생성하고 다음 내용을 추가합니다:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;bash&quot; style=&quot;color: #000000; text-align: left;&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;// src/svg.d.ts
declare module '*.svg' {
  import React from 'react';
  const src: string;
  export const ReactComponent: React.FunctionComponent&amp;lt;
    React.SVGProps&amp;lt;SVGSVGElement&amp;gt;
  &amp;gt;;
  export default src;
}&lt;/code&gt;&lt;/pre&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: oklch(0.304 0.04 213.681); text-align: left;&quot;&gt;tsconfig.json 파일&lt;/span&gt;&lt;span style=&quot;color: oklch(0.304 0.04 213.681); text-align: left;&quot;&gt;&amp;nbsp;수정하기&lt;/span&gt;&amp;nbsp;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: oklch(0.304 0.04 213.681); text-align: left;&quot;&gt;TypeScript Config 설정에서 svg.d.ts 파일이 포함되도록 include 옵션에 다음 내용을 추가합니다:&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729498476767&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
	기존 컴파일 설정...
  	&quot;include&quot;: [&quot;src&quot;, &quot;custom.d.ts&quot;, &quot;svg.d.ts&quot;]
   }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;3. SVGO로 SVG 파일 최적화하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SVGO는 SVG 파일에서 불필요한 데이터를 제거하여 최적화합니다. 터미널에서 직접 실행할 수 있습니다:&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;pnpm svgo path/to/your/file.svg -o path/to/your/optimized-file.svg&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또는, SVGR 설정에 SVGO를 통합하여 자동으로 최적화되도록 할 수 있습니다:&lt;/p&gt;
&lt;pre id=&quot;code_1729493966100&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    기존 vite 설정...
    svgr({
      svgoConfig: {
        plugins: [
          {
            name: &quot;preset-default&quot;,
            params: {
              overrides: {
                removeViewBox: false,
              },
            },
          },
        ],
      },
    }),&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;4. React 컴포넌트로 SVG 사용하기&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 프로젝트 내에서 SVG 파일을 React 컴포넌트처럼 사용할 수 있습니다:&lt;/p&gt;
&lt;pre class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot;&gt;&lt;code&gt;import React from 'react';
import { ReactComonent as Logo } from './logo.svg';

const App = () =&amp;gt; (
  &amp;lt;div&amp;gt;
    &amp;lt;Logo /&amp;gt;
  &amp;lt;/div&amp;gt;
);

export default App;&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Front-end/React.js</category>
      <author>AGAL</author>
      <guid isPermaLink="true">https://agal.tistory.com/237</guid>
      <comments>https://agal.tistory.com/237#entry237comment</comments>
      <pubDate>Mon, 21 Oct 2024 10:00:48 +0900</pubDate>
    </item>
    <item>
      <title>Shadow DOM</title>
      <link>https://agal.tistory.com/234</link>
      <description>&lt;p style=&quot;text-align: right;&quot; data-ke-size=&quot;size14&quot;&gt;[출처: &lt;a href=&quot;https://javascript.info/shadow-dom&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://javascript.info/shadow-dom&lt;/a&gt;]&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Shadow DOM&lt;/h2&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;Shadow DOM은 캡슐화를 위해 사용됩니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;이를 통해 구성 요소는 고유한 &quot;섀도우&quot; DOM ​​트리를 가질 수 있으며 기본 문서에서 실수로 액세스할 수 없으며 로컬 스타일 규칙 등을 가질 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Built-in shadow DOM&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;복잡한 브라우저 컨트롤이 어떻게 생성되고 스타일이 지정되는지 생각해 본 적이 있습니까? (예&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;input type=&quot;range&quot;&amp;gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;브라우저는 그것들을 그리기 위해 내부적으로 DOM/CSS를 사용합니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;그 DOM 구조는 일반적으로 우리에게 숨겨져 있지만 개발자 도구에서 볼 수 있습니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;예를 들어 Chrome에서는 개발자 도구에서 &quot;Show user agent shadow DOM&quot; 옵션을 활성화해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;그러면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;lt;input type=&quot;range&quot;&amp;gt;다음과 같이 보입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;145&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MPero/btrTfMN9bbc/M6nBIi3aPpKLrNk0YCIPx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MPero/btrTfMN9bbc/M6nBIi3aPpKLrNk0YCIPx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MPero/btrTfMN9bbc/M6nBIi3aPpKLrNk0YCIPx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMPero%2FbtrTfMN9bbc%2FM6nBIi3aPpKLrNk0YCIPx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;471&quot; height=&quot;145&quot; data-origin-width=&quot;471&quot; data-origin-height=&quot;145&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span&gt;위에&amp;nbsp;&lt;/span&gt;#shadow-root에 보이는 것을 &quot;shadow DOM&quot;이라고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;일반 JavaScript 호출 또는 선택기로 내장된 Shadow DOM 요소를 가져올 수 없습니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;이들은 일반 자식이 아니라 강력한 캡슐화 기술입니다. 위의&amp;nbsp;예에서&amp;nbsp;유용한&amp;nbsp;속성&amp;nbsp;&quot;pseudo&quot;를&amp;nbsp;볼&amp;nbsp;수&amp;nbsp;있습니다.&amp;nbsp;그것은&amp;nbsp;비표준이며&amp;nbsp;역사적인&amp;nbsp;이유로&amp;nbsp;존재합니다.&amp;nbsp;다음과&amp;nbsp;같이&amp;nbsp;CSS와&amp;nbsp;함께&amp;nbsp;스타일&amp;nbsp;하위&amp;nbsp;요소를&amp;nbsp;사용할&amp;nbsp;수&amp;nbsp;있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1670560703748&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;style&amp;gt;
/* make the slider track red */
input::-webkit-slider-runnable-track {
  background: red;
}
&amp;lt;/style&amp;gt;

&amp;lt;input type=&quot;range&quot;&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Shadow tree&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;DOM&amp;nbsp;요소에는&amp;nbsp;두&amp;nbsp;가지&amp;nbsp;유형의&amp;nbsp;DOM&amp;nbsp;하위&amp;nbsp;트리가&amp;nbsp;있을&amp;nbsp;수&amp;nbsp;있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Light tree &amp;ndash; HTML 자식으로 구성된 일반 DOM 하위 트리입니다. 이전 장에서 본 모든 하위 트리는 &quot;가벼움&quot;이었습니다.&lt;/li&gt;
&lt;li&gt;Shadow tree &amp;ndash; HTML에 반영되지 않은 숨겨진 DOM 하위 트리로, 엿보는 눈에서 숨겨집니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;element에 둘 다 있는 경우 브라우저는 그림자 트리만 렌더링합니다. 그러나 우리는 Shadow tree와 Light tree 사이에도 일종의 구성을 설정할 수 있습니다. 구성 요소 내부를 숨기고 구성 요소 로컬 스타일을 적용하기 위해 사용자 지정 요소에서 Shadow tree를 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;br /&gt;&lt;br /&gt;예를 들어 이 &amp;lt;show-hello&amp;gt; 요소는 Shadow tree에서 내부 DOM을 숨깁니다.&lt;/p&gt;
&lt;pre id=&quot;code_1670561007444&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;
customElements.define('show-hello', class extends HTMLElement {
  connectedCallback() {
    const shadow = this.attachShadow({mode: 'open'});
    shadow.innerHTML = `&amp;lt;p&amp;gt;
      Hello, ${this.getAttribute('name')}
    &amp;lt;/p&amp;gt;`;
  }
});
&amp;lt;/script&amp;gt;

&amp;lt;show-hello name=&quot;John&quot;&amp;gt;&amp;lt;/show-hello&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;이것이 Chrome 개발 도구에서 DOM이 보이는 방식이며 모든 콘텐츠는 &quot;#shadow-root&quot; 아래에 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;255&quot; data-origin-height=&quot;71&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uuTJG/btrTcEKjw32/noYBGB8g0nOCoKK0d5BbJK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uuTJG/btrTcEKjw32/noYBGB8g0nOCoKK0d5BbJK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uuTJG/btrTcEKjw32/noYBGB8g0nOCoKK0d5BbJK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuuTJG%2FbtrTcEKjw32%2FnoYBGB8g0nOCoKK0d5BbJK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;255&quot; height=&quot;71&quot; data-origin-width=&quot;255&quot; data-origin-height=&quot;71&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;먼저 elem.attachShadow({mode: &amp;hellip;})를 호출하면 섀도우 트리가 생성됩니다. 두 가지&amp;nbsp;제한&amp;nbsp;사항이&amp;nbsp;있습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;하나의 element 는 하나의 섀도우 루트만 만들 수 있습니다.&lt;/li&gt;
&lt;li&gt;'elem'은 사용자 정의 요소이거나 &amp;ldquo;article&amp;rdquo;, &amp;ldquo;aside&amp;rdquo;, &amp;ldquo;blockquote&amp;rdquo;, &amp;ldquo;body&amp;rdquo;, &amp;ldquo;div&amp;rdquo;, &amp;ldquo;footer&amp;rdquo;, &amp;ldquo;h1&amp;hellip;h6&amp;rdquo;, &amp;ldquo;header&amp;rdquo;, &amp;ldquo;main&amp;rdquo; &amp;ldquo;nav&amp;rdquo;, &amp;ldquo;p&amp;rdquo;, &amp;ldquo;section&amp;rdquo;, or &amp;ldquo;span&amp;rdquo; 이며, &amp;lt;img&amp;gt;와 같은 다른 요소는 Shadow tree를 호스트할 수 없습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;'mode' 옵션은 캡슐화 수준을 설정합니다.&lt;/span&gt;&lt;/span&gt; &lt;span&gt;&lt;span&gt;다음 두 값 중 하나를 가져야 합니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;open&quot; &amp;ndash; Shadow root를 elem.shadowRoot로 사용할 수 있습니다. &lt;br /&gt;모든 코드는 요소의 섀도우 트리에 액세스할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&quot;closed&quot;&amp;nbsp;&amp;ndash;&amp;nbsp;elem.shadowRoot는&amp;nbsp;항상&amp;nbsp;null입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;우리는 attachShadow에 의해 반환된 참조에 의해서만 Shadow DOM에 액세스할 수 있습니다(아마도 클래스 내부에 숨겨져 있을 것입니다). &amp;lt;input type=&quot;range&quot;&amp;gt;와 같은 브라우저 고유의 Shadow tree는 &quot;closed&quot; 이며, 액세스할 방법이 없습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;attachShadow에 의해 반환되는 Shadow root는 element 와 같습니다. innerHTML 또는 DOM 메서드(예: append)를 사용하여 채울 수 있습니다. Shadow root가 있는 요소를 &quot;Shadow tree host&quot;라고 하며 Shadow tree host 속성으로 사용할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1670561574108&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// {mode: &quot;open&quot;}으로 가정하고, 그렇지 않으면 elem.shadowRoot는 null입니다.
alert(elem.shadowRoot.host === elem); // true&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Encapsulation&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;Shadow&amp;nbsp;DOM은&amp;nbsp;기본&amp;nbsp;문서와&amp;nbsp;강력하게&amp;nbsp;구분됩니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Shadow DOM 요소는 light DOM의 querySelector에 표시되지 않습니다. 특히, Shadow DOM 요소는 light DOM의 ID와 충돌하는 ID를 가질 수 있습니다. ID는 Shadow tree 내에서만 고유해야 합니다.&lt;/li&gt;
&lt;li&gt;Shadow&amp;nbsp;DOM에는&amp;nbsp;자체&amp;nbsp;스타일시트가&amp;nbsp;있습니다.&amp;nbsp;외부&amp;nbsp;DOM의&amp;nbsp;스타일&amp;nbsp;규칙은&amp;nbsp;적용되지&amp;nbsp;않습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;예를 들어&lt;/p&gt;
&lt;pre id=&quot;code_1670561747011&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;style&amp;gt;
  /* 문서 스타일은 #elem(1) 내부의 shadow tree에 적용되지 않습니다. */
  p { color: red; }
&amp;lt;/style&amp;gt;

&amp;lt;div id=&quot;elem&quot;&amp;gt;&amp;lt;/div&amp;gt;

&amp;lt;script&amp;gt;
  elem.attachShadow({mode: 'open'});
    // shadow tree 는 고유 스타일이 있습니다. (2)
  elem.shadowRoot.innerHTML = `
    &amp;lt;style&amp;gt; p { font-weight: bold; } &amp;lt;/style&amp;gt;
    &amp;lt;p&amp;gt;Hello, John!&amp;lt;/p&amp;gt;
  `;

  // &amp;lt;p&amp;gt; 는 shadow tree 내부의 쿼리에서만 볼 수 있습니다. (3)
  alert(document.querySelectorAll('p').length); // 0
  alert(elem.shadowRoot.querySelectorAll('p').length); // 1
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;문서의 스타일은 그림자 트리에 영향을 주지 않습니다.&lt;/li&gt;
&lt;li&gt;하지만 내부 스타일이 작동합니다.&lt;/li&gt;
&lt;li&gt;섀도우&amp;nbsp;트리의&amp;nbsp;요소를&amp;nbsp;가져오려면&amp;nbsp;트리&amp;nbsp;내부에서&amp;nbsp;쿼리해야&amp;nbsp;합니다.&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>DOM/HTML5</category>
      <author>AGAL</author>
      <guid isPermaLink="true">https://agal.tistory.com/234</guid>
      <comments>https://agal.tistory.com/234#entry234comment</comments>
      <pubDate>Fri, 9 Dec 2022 13:57:57 +0900</pubDate>
    </item>
    <item>
      <title>대체 텍스트 가이드</title>
      <link>https://agal.tistory.com/233</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;구체적이고 간결하다&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;가능한 한 적은 수의 단어를 사용하십시오.&amp;nbsp;개체의 색상이 관련이 있습니까?&amp;nbsp;배경의 날씨가 관련이 있습니까?&amp;nbsp;사람의 머리색이 중요합니까?&amp;nbsp;콘텐츠 작성자는 이 정보가 메시지에 추가되거나 삭제되는지 여부를 판단해야 합니다. *문자 제한은 100-150입니다. (권장 125자)&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;미학이 아닌 정보를 기술하라&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&quot;밝은 파랑새의 그래픽&quot;과 같이 그림이 어떻게 보이는지 설명하지 마십시오.&amp;nbsp;&quot;트위터 아이콘&quot;과 같이 이미지 콘텐츠가 무엇이며 어떤 역할을 하는지 설명합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;이미지의 기능에 대해 생각하기&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;콘텐츠 작성자는 이유가 있어 웹 페이지에 이미지를 추가합니다.&amp;nbsp;내가 왜 이것을 포함하고 있는지 자문해 보십시오.&amp;nbsp;그것을 포함함으로써 내가 전달하려는 메시지는 무엇입니까?&amp;nbsp;이 설명을 포함하지 않으면 어떤 추가 정보와 의미를 놓칠 수 있습니까? 팁: 전화로 누군가에게 이미지를 설명한다고 상상해 보십시오.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;일반 구두점 사용&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;쉼표 및 마침표와 같은 일반적인 구두점을 사용하면 화면 판독기(및 최종 사용자)가 텍스트를 더 쉽게 이해할 수 있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;장식 이미지의 경우 대체 텍스트를 비워 둡니다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;인터넷은 긴 텍스트 페이지를 나누거나 콘텐츠의 느낌을 향상시키는 데 사용되는 장식적인 이미지로 가득 차 있습니다.&amp;nbsp;이는 콘텐츠를 게시하는 기술, 과학 또는 기업 사이트에서 일반적입니다.스크린 리더 사용자는 일반적으로 웹 페이지의 분위기, 느낌 및 미학이 관련이 없다는 데 동의합니다.&amp;nbsp;중요한 콘텐츠의 접근성을 방해해서는 안 됩니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;저작권 정보 또는 사진 크레딧을 포함하지 마십시오.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;사진 작가의 이름, 크리에이티브 커먼즈 라이선스 또는 추가 저작권 정보를 대체 텍스트에 포함할 필요가 없습니다.&amp;nbsp;이미지 아래 캡션에 더 적합한 귀중한 단어를 낭비합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&quot;~의 사진&quot; 또는 &quot;~의 이미지&quot;로 시작하지 마십시오.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;매일 스크린 리더를 사용하는 사람들은 img 요소의 의미 때문에 이미지에 도달했다는 것을 알게 될 것입니다.&amp;nbsp;이 정보는 불필요하고 귀중한 설명 단어를 낭비합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;복잡한 이미지의 경우 다른 곳에서 추가 설명 제공&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;특정 상황에서는 125자가 이미지로 전달되는 모든 정보를 전달하기에 충분하지 않을 수 있습니다.&amp;nbsp;수학 방정식, 인포그래픽, 순서도와 같은 이미지가 좋은 예입니다.&amp;nbsp;화면 판독기 사용자를 페이지나 웹사이트의 다른 위치에 있는 텍스트 기반 설명으로 안내하는 대체 텍스트를 포함해야 할 수도 있습니다. &lt;a href=&quot;https://accessibility.psu.edu/images/&quot;&gt;복잡한 이미지를 위한 대체 텍스트 작성에 대한 Penn State University의 지침 읽기&lt;/a&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;대체 텍스트가 필요하지 않은 경우&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;이미지가 장식적일 때, 즉 페이지에 표시되는 나머지 정보에 더 이상의 맥락이나 의미를 추가하지 않습니다. 다른 예는 다음과 같습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;링크에 이미지를 사용하지만 링크의 목적을 이해하기 위해 이미지가 필요하지 않은 경우&lt;/li&gt;
&lt;li&gt;이미 텍스트 레이블이 있는 아이콘&lt;/li&gt;
&lt;li&gt;중요한 정보가 이미 본문에 효과적으로 전달된 다이어그램 또는 차트&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;대체 텍스트 테스트 절차&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;1. &lt;b&gt;의미 있는 이미지&lt;/b&gt; (텍스트 이미지, 행동을 시작하거나 의미를 전달하거나 응답을 촉구하는 데 사용 되는 기능적 이미지, 이미지 지도 등)&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;alt=&quot;&quot; 아닌지 확인 (텍스트 문자열이 비어 있지 않은지 확인)&lt;/li&gt;
&lt;li&gt;aria-role=&quot;presentation&quot; 이 아닌지 확인&lt;/li&gt;
&lt;li&gt;aria-role=&quot;none&quot; 이 아닌지 확인&lt;/li&gt;
&lt;li&gt;aria-hidden이 &quot;true&quot; 로 설정되어 있지 않은지 확인&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;2. &lt;b&gt;장식 이미지&lt;/b&gt; (순수한 장식이거나 시각적 서식 지정에만 사용)&lt;br /&gt;&amp;nbsp; *다음 절차중 하나 이상 참인지 체크&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;aria-role=&quot;presentation&quot;&lt;/li&gt;
&lt;li&gt;aria-role=&quot;none&quot;&lt;/li&gt;
&lt;li&gt;aria-hidden=&quot;true&quot;&lt;/li&gt;
&lt;li&gt;alt=&quot;&quot;&lt;/li&gt;
&lt;li&gt;css(background)를 통해 이미지 삽입&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;3. &lt;b&gt;보안 문자&lt;/b&gt; &lt;br /&gt;&amp;nbsp; *다음 절차중 하나라도 수행 못할 시 실패&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;텍스트 문자열이 비어 있지 않은지 확인&lt;/li&gt;
&lt;li&gt;텍스트 문자열이 CAPTCHA의 목적을 식별하고 설명하는지 확인&lt;/li&gt;
&lt;li&gt;시각이 없는 사용자와 청각이 없는 사용자를 위해 최소한 대체 형식의 CAPTCHA가 제공되는지 확인&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;4. &lt;b&gt;텍스트 이미지&lt;/b&gt; (로고 또는 브랜드 이름의 일부인 로고 유형 또는 텍스트)&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;텍스트를 사용하면 텍스트 이미지와 동일한 시각적 표현 및 효과를 얻을 수 없는지 확인&lt;/li&gt;
&lt;li&gt;텍스트 이미지를 사용자의 요구 사항에 맞게 시각적으로 사용자 지정할 수 있는지 확인 (웹 콘텐츠를 통해 사용자는 글꼴, 크기, 색상 및 배경 설정을 지정할 수 있으며 이러한 설정에 따라 텍스트의 모든 이미지가 제공)&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Reference&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;a href=&quot;https://bighack.org/how-to-write-better-alt-text-descriptions-for-accessibility/&quot;&gt;https://bighack.org/how-to-write-better-alt-text-descriptions-for-accessibility/&lt;/a&gt; &lt;a href=&quot;https://ictbaseline.access-board.gov/06Images/#accessibility-requirements&quot;&gt;https://ictbaseline.access-board.gov/06Images/#accessibility-requirements&lt;/a&gt; &lt;a href=&quot;https://ictbaseline.access-board.gov/06Images/#62-test-procedure-for-decorative-images&quot;&gt;https://ictbaseline.access-board.gov/06Images/#62-test-procedure-for-decorative-images&lt;/a&gt;&lt;/p&gt;</description>
      <category>DOM/HTML5</category>
      <author>AGAL</author>
      <guid isPermaLink="true">https://agal.tistory.com/233</guid>
      <comments>https://agal.tistory.com/233#entry233comment</comments>
      <pubDate>Wed, 5 Oct 2022 21:24:32 +0900</pubDate>
    </item>
    <item>
      <title>대용량 이미지 분기 처리</title>
      <link>https://agal.tistory.com/232</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;사용 배경&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;페이지 로드시 바로 보여지는 화면인 경우 대용량 로드로 인해 흰 화면 노출로 성능 이슈 야기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모니터 해상도 증가 및 retina 디스플레이 등 1920을 훨씬 상회하는 이미지로 인해 PC는 1920, 2560, 3840 각각 해상도에 맞게 지원 필요&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;사용 범위&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;메인 이미지나 Stories 등에 배경처럼 전체사이즈로 들어가는 이미지&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;적용 사항&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;webP를 활용하여 이미지 용량 개선 (통상적으로 jpg, png 보다 가벼우나 추출 설정상 jpg가 더 가벼운 경우에는 jpg 사용 - DP 팀과 협의) (iOS11 이상 지원이므로 iOS10 이하 브라우저 지원할 지 여부 체크 - DP 팀과 협의)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웹/모바일 디바이스에 따른 반응형 이미지 동적 로드가 가능한 &amp;lt;picture&amp;gt; 태그 사용 (웹/모바일간 비율이 상이하며 나타나는 레이아웃 문제는 css로 제어)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;384&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qwvLU/btrNeE4mHX9/s3TOgBk5n8cwBi0YNbEHw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qwvLU/btrNeE4mHX9/s3TOgBk5n8cwBi0YNbEHw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qwvLU/btrNeE4mHX9/s3TOgBk5n8cwBi0YNbEHw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqwvLU%2FbtrNeE4mHX9%2Fs3TOgBk5n8cwBi0YNbEHw1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1600&quot; height=&quot;384&quot; data-origin-width=&quot;1600&quot; data-origin-height=&quot;384&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;picture&amp;gt;
	&amp;lt;source media=&quot;(max-width: 1024px)&quot; srcset=&quot;모바일_이미지_src&quot;&amp;gt;
	&amp;lt;source media=&quot;(min-width: 1024px)&quot; srcset=&quot;
			 웹_1920_이미지_src 1920w,
			 웹_2560_이미지_src 2560w,
			 웹_3840_이미지_src 3840w&quot;&amp;gt;
	&amp;lt;img src=&quot;웹_1920_이미지_src&quot; alt=&quot;&quot;&amp;gt;
&amp;lt;/picture&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/25907930/chrome-not-respecting-video-source-inline-media-queries&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;*&amp;lt;video&amp;gt;태그 지원하지 않음 &lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</description>
      <category>DOM/HTML5</category>
      <author>AGAL</author>
      <guid isPermaLink="true">https://agal.tistory.com/232</guid>
      <comments>https://agal.tistory.com/232#entry232comment</comments>
      <pubDate>Fri, 30 Sep 2022 20:34:37 +0900</pubDate>
    </item>
    <item>
      <title>Axios</title>
      <link>https://agal.tistory.com/230</link>
      <description>&lt;h1&gt;Axios&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서드파티 라이브러리로 CDN 혹은 npm 이나 yarn과 같은 패키지 매니저를 통해 설치하여 프로젝트에 추가할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Axios는 브라우저 혹은 node.js 환경에서 실행할 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;설치하기&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;NPM을 사용하여 설치&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;cmake&quot;&gt;&lt;code&gt;npm install axios
&lt;/code&gt;&lt;/pre&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Yarn을 사용하여 설치&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;yarn add axios
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 프로젝트에서 import 해야 합니다.&lt;/p&gt;
&lt;pre class=&quot;capnproto&quot;&gt;&lt;code&gt;import axios from &quot;axios&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 브라우저에서 Axios를 사용한다면 아래와 같이 CDN을 사용할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;&quot;&gt;&lt;code&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;문법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fetch와 문법은 비슷하나, 다양한 방법으로 요청할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;axios(url, {
  // 설정 옵션
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 메서드를 붙일 수도 있습니다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;axios.get(url, {
  // 설정 옵션
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fetch 메서드처럼 HTTP 메서드 없이 요청할 경우 기본적으로 GET 요청을 생성합니다.&lt;/p&gt;
&lt;pre class=&quot;lisp&quot;&gt;&lt;code&gt;axios(url);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또, 두 번째 인자를 사용해서 커스텀 설정하는 것도 가능합니다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;axios(url, {
  method: &quot;get&quot;, // 다른 옵션도 가능합니다 (post, put, delete, etc.)
  headers: {},
  data: {},
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래처럼 작성할 수도 있습니다.&lt;/p&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;axios({
  method: &quot;get&quot;,
  url: url,
  headers: {},
  data: {},
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;JSON 데이터 처리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 예제에서는 JSONPlaceholder라는 REST API에 GET 요청을 통해 투두 리스트의 아이템을 가져옵니다.&lt;/p&gt;
&lt;pre class=&quot;vbscript&quot;&gt;&lt;code&gt;const url = &quot;&amp;lt;https://jsonplaceholder.typicode.com/todos&amp;gt;&quot;;

axios
	.get(url)
	.then((response) =&amp;gt; console.log(response.data));
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Axios를 사용하면 응답 데이터를 기본적으로 JSON 타입으로 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;응답 데이터는 언제나 응답 객체의&amp;nbsp;data 프로퍼티에서 사용할 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;자동 문자열 변환(stringify)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제&amp;nbsp;JSONPlaceholder&amp;nbsp;API를 사용해서 데이터를 전송해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 위해서는 데이터를 JSON 문자열로 직렬화 해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;POST&amp;nbsp;메서드로 JavaScript 객체를 API로 전송하면 Axios가 자동으로 데이터를 문자열로 변환해줍니다.&lt;/p&gt;
&lt;pre class=&quot;qml&quot;&gt;&lt;code&gt;const url = &quot;&amp;lt;https://jsonplaceholder.typicode.com/todos&amp;gt;&quot;;

const todo = {
  title: &quot;A new todo&quot;,
  completed: false,
};

axios
  .post(url, {
    headers: {
      &quot;Content-Type&quot;: &quot;application/json&quot;,
    },
    data: todo,
  })
  .then(console.log);
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Axios로&amp;nbsp;post 요청을 할 때 요청 본문(request body)으로 보내고자 하는&amp;nbsp;data는 data 프로퍼티에 할당합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컨텐츠 유형 헤더도 설정할 수 있습니다. 기본적으로 axios는&amp;nbsp;Content-Type을&amp;nbsp;application/json으로 설정합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;에러 처리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Promise가 거부(reject)되면&amp;nbsp;.catch()를 사용하여 에러를 처리할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;.catch()를 사용한 일반적인 에러 처리는 다음과 같습니다.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;const url = &quot;&amp;lt;https://jsonplaceholder.typicode.com/todos&amp;gt;&quot;;

axios
  .get(url)
  .then((response) =&amp;gt; console.log(response.data))
  .catch((err) =&amp;gt; {
    console.log(err.message);
  });
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Axios의 promise는 상태 코드가 2xx의 범위를 넘어가면 거부(reject)합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 객체에 응답(response) 또는 요청(request) 프로퍼티가 포함되어 있는지 확인하여 에러에 대한 자세한 정보를 확인할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;.catch((err) =&amp;gt; {
	// 에러 처리
	if (err.response) {
		// 요청이 이루어졌고 서버가 응답했을 경우
	  const { status, config } = err.response;

    if (status === 404) {
      console.log(`${config.url} not found`);
    }
    if (status === 500) {
      console.log(&quot;Server error&quot;);
    }

  } else if (err.request) {
    // 요청이 이루어졌으나 서버에서 응답이 없었을 경우
    console.log(&quot;Error&quot;, err.message);
  } else {
    // 그 외 다른 에러
    console.log(&quot;Error&quot;, err.message);
  }
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 객체의&amp;nbsp;response&amp;nbsp;프로퍼티는 클라이언트가 2xx 범위를 벗어나는 상태 코드를 가진 에러 응답을 받았음을 나타냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 객체의&amp;nbsp;request&amp;nbsp;프로퍼티는 요청이 수행되었지만 클라이언트가 응답을 받지 못했음을 나타냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;요청 또는 응답 속성이 모두 없는 경우는 네트워크 요청을 설정하는 동안 오류가 발생한 경우입니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;응답 시간 초과 / 요청 취소&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 클라이언트에서 HTTP 요청이 시간 초과될 경우,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Axios에서는&amp;nbsp;timeout 속성을 설정 객체에 추가하여 요청이 종료될 때까지의 시간을 밀리초로 지정할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 예제에서는 만약 요청이 4초 이상 걸릴 경우에 종료하고 console창에 error를 로깅하고 있습니다.&lt;/p&gt;
&lt;pre class=&quot;coffeescript&quot;&gt;&lt;code&gt;const url = &quot;&amp;lt;https://jsonplaceholder.typicode.com/todos&amp;gt;&quot;;

axios
  .get(url, {
    timeout: 4000, // 기본 설정은 '0'입니다 (타임아웃 없음)
  })
  .then((response) =&amp;gt; console.log(response.data))
  .catch((err) =&amp;gt; {
    console.log(err.message);
  });
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;취소 토큰을 통한 요청 취소&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이&amp;nbsp;CancelToken.source팩토리를 사용하여 취소 토큰을 만들 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;mel&quot;&gt;&lt;code&gt;const CancelToken = axios.CancelToken;
const source = CancelToken.source();

axios.get('/user/12345', {
  cancelToken: source.token
}).catch(function (thrown) {
  if (axios.isCancel(thrown)) {
    console.log('Request canceled', thrown.message);
  } else {
    // 에러 핸들링
  }
});

axios.post('/user/12345', {
  name: 'new name'
}, {
  cancelToken: source.token
})

// 요청 취소하기 (메시지 파라미터는 옵션입니다)
source.cancel('Operation canceled by the user.');
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행자 함수를 CancelToken 생성자에 전달하여, 취소 토큰을 만들수도 있습니다.&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;const CancelToken = axios.CancelToken;
let cancel;

axios.get('/user/12345', {
  cancelToken: new CancelToken(function executor(c) {
    // 실행자 함수는 취소 함수를 파라미터로 받습니다.
    cancel = c;
  })
});

// 요청 취소하기
cancel();
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Reference&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://meticulous.ai/blog/fetch-vs-axios/&quot;&gt;https://meticulous.ai/blog/fetch-vs-axios/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://axios-http.com/kr/docs/cancellation&quot;&gt;https://axios-http.com/kr/docs/cancellation&lt;/a&gt;&lt;/p&gt;</description>
      <category>Javascript/ECMAScript 2015 (ES6)</category>
      <author>AGAL</author>
      <guid isPermaLink="true">https://agal.tistory.com/230</guid>
      <comments>https://agal.tistory.com/230#entry230comment</comments>
      <pubDate>Wed, 28 Sep 2022 20:02:36 +0900</pubDate>
    </item>
    <item>
      <title>Cross-site Scripting(XSS)</title>
      <link>https://agal.tistory.com/231</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;정의&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTML 삽입(HTML Injection) 취약점이 발생하는 지점은&amp;nbsp;&lt;b&gt;웹 브라우저에서 전달되는 값이 HTML 내에 출력되는 곳&lt;/b&gt;이다. HTML삽입이 가능하면 대부분의 공격은 자바스크립트(Javascript)를 이용한다. 이 때문에 다른 곳에서(cross-site) 전달되는 스크립트를 실행(scripting)한다고 하여 일반적으로는&amp;nbsp;&lt;b&gt;크로스 사이트 스크립트&lt;/b&gt;(Cross-site Script, Cross-site Scripting)라고 많이 알려져 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;XSS 종류와 공격 방법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;XSS 종류&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. Reflected XSS&lt;br /&gt;이름 그대로 반사하는 형태의 공격이다. DB에 저장하여 공격하는 게 아닌 1회용 공격으로 볼 수 있다. 이유는 클라이언트가 직접 누르도록 유도하기 때문이다.기본적으로 URL을 통해 스크립트 공격을 진행한다. 블랙 해커는 웹 페이지를 통해 클라이언트에게 악의적인 스크립트를 포함한 URL을 클라이언트에게 보낸다. 예를 들면 이메일, 쪽지 등 어떠한 방법이라도 가능하다. 해당 주소로 유도만 하면 되기 때문이다. 이후 클라이언트가 해당 주소를 클릭하게 되면 악의적인 스크립트가 실행된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;505&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/br6n8g/btrNcBZwzfe/9d8lr7tKQ6IoPEUslgJVO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/br6n8g/btrNcBZwzfe/9d8lr7tKQ6IoPEUslgJVO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/br6n8g/btrNcBZwzfe/9d8lr7tKQ6IoPEUslgJVO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbr6n8g%2FbtrNcBZwzfe%2F9d8lr7tKQ6IoPEUslgJVO1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;674&quot; height=&quot;505&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;505&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.Stored XSS&lt;br /&gt;저장된 XSS 공격, Reflected XSS와 달리 지속적으로 활용할 수 있다. 주로 게시판, 쪽지함 등과 같은 저장형 형태의 게시글에서 많이 이용된다.게시판 게시글은 웹서버 및 데이터베이스와 연동하여 저장되고 출력된다. 블랙 해커는 게시글을 작성할 때 악성 스크립트를 포함시켜서 올린다. XSS 공격에 주의 깊게 봐야 할 기법은 Drive by download이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;663&quot; data-origin-height=&quot;625&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bDOtiE/btrNb9Cq1I9/cgEuw8xGkrAlpvkBRZMcrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDOtiE/btrNb9Cq1I9/cgEuw8xGkrAlpvkBRZMcrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDOtiE/btrNb9Cq1I9/cgEuw8xGkrAlpvkBRZMcrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDOtiE%2FbtrNb9Cq1I9%2FcgEuw8xGkrAlpvkBRZMcrK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;663&quot; height=&quot;625&quot; data-origin-width=&quot;663&quot; data-origin-height=&quot;625&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. DOM based XSS&lt;br /&gt;DOM은 기반 XSS 공격. 일반적으로 DOM 기반 XSS 취약점이 있는 브라우저를 대상으로 진행한다.피해자의 브라우저가 HTML 페이지를 구문 분석할 때마다 공격 스크립트가 DOM 생성의 일부로 실행되면서 공격한다. 페이지 자체는 변하지 않으나, 페이지에 포함되어 있는 브라우저 측 코드가 DOM 환경에서 악성코드로 실행된다. *DOM 기반 XSS는 서버와 관계없이 브라우저에서 발생하는 것이 차이점이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;349&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brkXmg/btrNcmByYFX/DGAvGiBlUW37ydvRZG21I0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brkXmg/btrNcmByYFX/DGAvGiBlUW37ydvRZG21I0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brkXmg/btrNcmByYFX/DGAvGiBlUW37ydvRZG21I0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrkXmg%2FbtrNcmByYFX%2FDGAvGiBlUW37ydvRZG21I0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;698&quot; height=&quot;349&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;349&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;XSS 공격 대응 방법&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Content Security Policy (CSP) 실행&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;CSP :&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP&quot;&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;**innerHTML&amp;nbsp;대신&amp;nbsp;textContent&amp;nbsp;사용**&lt;/li&gt;
&lt;li&gt;// Bad latestReview.innerHTML = 'Pizza is &amp;lt;img src=&quot;wrongLocation&quot; onError='alert(&quot;You're hacked&quot;)'&amp;gt; delicious!!' // Good latestReview.textContent = 'Pizza is &amp;lt;img src=&quot;wrongLocation&quot; onError='alert(&quot;You're hacked&quot;)'&amp;gt; delicious!!'&lt;/li&gt;
&lt;li&gt;&lt;b&gt;입력 값 검증 (입력 값 제한)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력 데이터의 길이 제한하기&lt;/li&gt;
&lt;li&gt;지정된 문자 또는 형식으로 입력되었는지 확인&lt;/li&gt;
&lt;li&gt;정해진 규칙을 벗어난 입력 값들은 무효화 시키기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;출력 값 검증 (입력 값 치환)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;스크립트로 해석될 여지가 있는 특수 문자들을 인코딩해서 보여줘야 한다.변경 전 변경 후 변경 전 변경 후
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;amp;&lt;/td&gt;
&lt;td&gt;&amp;amp;&lt;/td&gt;
&lt;td&gt;&quot;&lt;/td&gt;
&lt;td&gt;&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt;&lt;/td&gt;
&lt;td&gt;&amp;lt;&lt;/td&gt;
&lt;td&gt;'&lt;/td&gt;
&lt;td&gt;'&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;gt;&lt;/td&gt;
&lt;td&gt;&amp;gt;&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;td&gt;/&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(&lt;/td&gt;
&lt;td&gt;(&lt;/td&gt;
&lt;td&gt;)&lt;/td&gt;
&lt;td&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Modern Framework 사용&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;프론트엔드를 위한 모던 프레임워크는 (React, Angular 등) 또한 웹사이트를 악의적인 공격으로부터&amp;nbsp;다양한 보안 방식을 제공&lt;/li&gt;
&lt;li&gt;스크립트 영역에 출력 자제 이벤트 핸들러 영역에 스크립트가 삽입되는 경우 보호 기법들을 우회할 수 있기 때문에 사용자의 입력을 출력하는 것을 최대한 자제, 필요한 경우 대응 방안과 함께 사용해야 한다.&lt;/li&gt;
&lt;li&gt;// 예시 코드 &amp;lt;script&amp;gt; var user_name='0oooo'; alert(user_name); &amp;lt;/script&amp;gt; // 공격 코드 0oooo'; alert(document.cookie); // &amp;lt;script&amp;gt; var user_name='0oooo'; alert(document.cookie); //'; alert(user_name); &amp;lt;/script&amp;gt;&lt;/li&gt;
&lt;li&gt;보안 라이브러리 사용
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;MS에서 개발한 AntiXSS 라이브러리, OWASP&lt;/li&gt;
&lt;li&gt;네이버에서 개발한 Lucy-Xss-Servlet-Filter 라이브러리&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;XSS 공격 벡터&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;body&amp;gt; 태그 이벤트 속성은 &quot;body&quot; 태그를 통해 제공되는 경우 스크립트의 소스가 될 수도 있다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.1395%;&quot;&gt;&amp;lt;div&amp;gt;태그&lt;/td&gt;
&lt;td style=&quot;width: 86.7442%;&quot;&gt;이 태그는 배경 참조도 포함하여 &amp;lt;table&amp;gt;과 같은 방식으로 스크립트를 참조하는데 사용할 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.1395%;&quot;&gt;&amp;lt;table&amp;gt; 태그&lt;/td&gt;
&lt;td style=&quot;width: 86.7442%;&quot;&gt;background 속성이 일반적으로 이미지를 참조하는 경우 문제가 되는 스크립트를 참조하도록 손상될 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.1395%;&quot;&gt;&amp;lt;object&amp;gt; 태그&lt;/td&gt;
&lt;td style=&quot;width: 86.7442%;&quot;&gt;이 태그를 사용하여 외부 사이트의 스크립트를 포함할 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.1395%;&quot;&gt;&amp;lt;iframe&amp;gt; 태그&lt;/td&gt;
&lt;td style=&quot;width: 86.7442%;&quot;&gt;피싱 공격에 효과적인 이 벡터를 XSS 공격이 현재 페이지에 다른 HTML 페이지를 삽입할 수 있도록 한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.1395%;&quot;&gt;&amp;lt;input&amp;gt; 태그&lt;/td&gt;
&lt;td style=&quot;width: 86.7442%;&quot;&gt;일부 브라우저는 이 벡터를 통한 조작이 허용된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.1395%;&quot;&gt;&amp;lt;img&amp;gt; 태그&lt;/td&gt;
&lt;td style=&quot;width: 86.7442%;&quot;&gt;사용중인 브라우저에 따라 이 속성은 유용할 수 있따.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.1395%;&quot;&gt;&amp;lt;link&amp;gt; 태그&lt;/td&gt;
&lt;td style=&quot;width: 86.7442%;&quot;&gt;이 태그는 외부 스타일 시트에 연결하는 일반 사용 대신 스크립트를 포함할 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.1395%;&quot;&gt;&amp;lt;script&amp;gt; 태그&lt;/td&gt;
&lt;td style=&quot;width: 86.7442%;&quot;&gt;스크립트 태그는 외부 Java script 코드를 참조하는데 사용할 수 있으므로 가장 간단한 XSS 태그이다. 공격자는 스크립트 태그 내에 악성코드를 삽입할 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 13.1395%;&quot;&gt;JS 이벤트&lt;/td&gt;
&lt;td style=&quot;width: 86.7442%;&quot;&gt;공격자가 사용하는 또 다른 태그인 이벤트 속성은 다양한 태그에 적용된다. &quot;onerror&quot; 및 &quot;onload&quot;와 같은 속성이 예이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;*공격 벡터 : 해커가 컴퓨터나 네트워크에 접근하기 위해 사용하는 경로나 방법&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Reference&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://tofusand-dev.tistory.com/92&quot;&gt;https://tofusand-dev.tistory.com/92&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://gogomalibu.tistory.com/163&quot;&gt;https://gogomalibu.tistory.com/163&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&amp;amp;blogId=lstarrlodyl&amp;amp;logNo=221941738753&quot;&gt;https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&amp;amp;blogId=lstarrlodyl&amp;amp;logNo=221941738753&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://myungjjju.tistory.com/38&quot;&gt;https://myungjjju.tistory.com/38&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>INFO/WEB</category>
      <author>AGAL</author>
      <guid isPermaLink="true">https://agal.tistory.com/231</guid>
      <comments>https://agal.tistory.com/231#entry231comment</comments>
      <pubDate>Tue, 27 Sep 2022 20:50:15 +0900</pubDate>
    </item>
    <item>
      <title>도메인 (domain) - 인터넷 기본 도메인 , 호스트, 포워딩 알아보기 | 생활코딩</title>
      <link>https://agal.tistory.com/226</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;도메인&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;IP란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;인터넷에 연결되어 있는 장치(컴퓨터, 스마트폰, 타블릿, 서버 등등)들은 각각의 장치를 식별할 수 있는 주소. 예) 115.68.24.88&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;도메인이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;IP를 이해하고 기억하기 쉽게 각 IP에 이름을 부여한 것&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;443&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cLl2mJ/btrwgj8GugV/u5r7opxeAVKq80A0AKIjY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cLl2mJ/btrwgj8GugV/u5r7opxeAVKq80A0AKIjY1/img.png&quot; data-alt=&quot;출처 :&amp;amp;amp;nbsp;https://opentutorials.org/course/228/1450&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cLl2mJ/btrwgj8GugV/u5r7opxeAVKq80A0AKIjY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcLl2mJ%2Fbtrwgj8GugV%2Fu5r7opxeAVKq80A0AKIjY1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;661&quot; height=&quot;443&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;443&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 :&amp;amp;nbsp;https://opentutorials.org/course/228/1450&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;도메인의 구성요소&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;컴퓨터의 이름과 최상위 도메인으로 구성되어 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;opentutorials.org&lt;br /&gt;- opentutorials : 컴퓨터의 이름&lt;br /&gt;- org : 최상위 도메인 - 비영리단체&lt;/li&gt;
&lt;li&gt;daum.co.kr&lt;br /&gt;- daum : 컴퓨터의 이름&lt;br /&gt;- co : 국가 형태의 최상위 도메인을 의미&lt;br /&gt;- kr : 대한민국의 NIC에서 관리하는 도메인을 의미&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;URL의 이해&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도메인은 장치를 식별하기 위한 주소&lt;/li&gt;
&lt;li&gt;URL은 서버가 가지고 있는 다양한 컨텐츠를 식별하기 위한 주소 (URL = 도메인 + 경로)&lt;/li&gt;
&lt;li&gt;예를 들어서 https://s3.ap-northeast-2.amazonaws.com/opentutorials-user-file/module/121/298.png가 있을 때&lt;br /&gt;- 도메인 : opentutorials.org&lt;br /&gt;- URL : https://s3.ap-northeast-2.amazonaws.com/opentutorials-user-file/module/121/298.png&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;도메인 검색 및 구입&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;도메인 선정의 고려사항&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;선호하는 최상위 도메인을 선택한다. com&lt;/li&gt;
&lt;li&gt;쓰임에 맞는 최상위 도메인을 선택한다. 비영리 서비스인 생활코딩의 홈페이지는 .org&lt;/li&gt;
&lt;li&gt;도메인 이름에 최상위 도메인을 포함시킨다. 예를들면, flickr.com 는 flic.kr, delicious.com은 del.icio.us&lt;/li&gt;
&lt;li&gt;짧을수록 좋다.&lt;/li&gt;
&lt;li&gt;키보드 자판상에서 좌우 대칭이 입력하기에 편리하다.&lt;/li&gt;
&lt;li&gt;악의적인 선점에 대비해서 예비 도메인을 구입하는 것이 유리&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;호스트 설정&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;호스트란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;네트워크에 연결되어 있는 컴퓨터들을 호스트라고 한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;호스트 설정이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;도메인을 호스트의 IP에 연결하는 행위&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;도메인과 호스트의 관계도&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;298.png&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;443&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMmGBr/btrwm9NwVyH/m6ReDKcaI9L4Ajk2o3ohO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMmGBr/btrwm9NwVyH/m6ReDKcaI9L4Ajk2o3ohO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMmGBr/btrwm9NwVyH/m6ReDKcaI9L4Ajk2o3ohO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMmGBr%2Fbtrwm9NwVyH%2Fm6ReDKcaI9L4Ajk2o3ohO0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;661&quot; height=&quot;443&quot; data-filename=&quot;298.png&quot; data-origin-width=&quot;661&quot; data-origin-height=&quot;443&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;하나의 도메인으로 여러 개의 호스트에 연결하기&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;784.png&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;174&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JLQmm/btrwIhJMydi/J6s0I5ZPtDEmpHcpFl7dTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JLQmm/btrwIhJMydi/J6s0I5ZPtDEmpHcpFl7dTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JLQmm/btrwIhJMydi/J6s0I5ZPtDEmpHcpFl7dTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJLQmm%2FbtrwIhJMydi%2FJ6s0I5ZPtDEmpHcpFl7dTK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;532&quot; height=&quot;174&quot; data-filename=&quot;784.png&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;174&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;포워딩 설정&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;포워딩이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;도메인으로 접근한 사용자를 다른 도메인으로 보내는 행위 예를 들어 ooo2.org로 사용자가 접근하면 opentutorials.org로 보낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;보통 호스트를 설정할 수 없을 때 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;유동 포워딩 : 브라우저 URL이 포워딩된 URL로 변경&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;고정 포워딩 : 브라우저 URL이 현재 URL로 고정&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;호스트 설정과 포워딩의 차이점&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;호스트 설정은 도메인과 IP를 연결시키는 것.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;span style=&quot;color: #666666;&quot;&gt;포워딩은 다른 도메인으로 보내는 것이기 때문에 포워딩한 사용자의 URL이 변경된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;네임서버&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;네임서버란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;도메인에 해당하는 IP를 알려주는 서비스&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;네임서버의 역할과 동작&lt;/h3&gt;
&lt;p&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/2ZUxoi7YNgs&quot; width=&quot;560&quot; height=&quot;315&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;hosts 파일&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;브라우저가 도메인에 해당하는 IP를 찾는 순서&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;local cache를 검색한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;hosts 파일을 검색한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;도메인 네임서버을 검색한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;hosts 파일의 위치&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Unix&quot;&gt;Unix&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Unix-like&quot;&gt;Unix-like&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://opentutorials.org/wiki/POSIX&quot;&gt;POSIX&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;/etc/hosts&lt;a href=&quot;https://opentutorials.org/course/228/1457#cite_note-1&quot;&gt;[2]&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&quot;3&quot;&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Microsoft_Windows&quot;&gt;Microsoft Windows&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Windows_3.1x&quot;&gt;3.1&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;%Windir%HOSTS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Windows_95&quot;&gt;95&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Windows_98&quot;&gt;98/98SE&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Windows_Me&quot;&gt;Me&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;%WinDir%hosts&lt;a href=&quot;https://opentutorials.org/course/228/1457#cite_note-2&quot;&gt;[3]&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Windows_NT&quot;&gt;NT&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Windows_2000&quot;&gt;2000&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Windows_XP&quot;&gt;XP&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(&lt;a href=&quot;https://opentutorials.org/wiki/X86&quot;&gt;x86&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;amp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://opentutorials.org/wiki/X64&quot;&gt;x64&lt;/a&gt;),&lt;a href=&quot;https://opentutorials.org/course/228/1457#cite_note-3&quot;&gt;[4]&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Windows_Server_2003&quot;&gt;2003&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Windows_Vista&quot;&gt;Vista&lt;/a&gt;,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Windows_7&quot;&gt;7&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Environment_variable#System_path_variables&quot;&gt;%SystemRoot%&lt;/a&gt;system32driversetchosts&lt;a href=&quot;https://opentutorials.org/course/228/1457#cite_note-hostReset-4&quot;&gt;[5]&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Windows_Mobile&quot;&gt;Windows Mobile&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;Registry key underHKEY_LOCAL_MACHINECommTcpipHosts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&quot;3&quot;&gt;Apple&lt;a href=&quot;https://opentutorials.org/wiki/Macintosh&quot;&gt;Macintosh&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;9 and earlier&lt;/td&gt;
&lt;td&gt;System Folder: Preferences or System folder&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Mac_OS_X&quot;&gt;Mac OS X&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;10.0 &amp;ndash; 10.1.5&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://opentutorials.org/course/228/1457#cite_note-macosx-5&quot;&gt;[6]&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;(Added through NetInfo or niload)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Mac_OS_X&quot;&gt;Mac OS X&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;10.2 and newer&lt;/td&gt;
&lt;td&gt;/private/etc/hosts&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://opentutorials.org/course/228/1457#cite_note-macosx-5&quot;&gt;[6]&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(or&lt;span&gt;&amp;nbsp;&lt;/span&gt;/etc/hosts, since&lt;span&gt;&amp;nbsp;&lt;/span&gt;/etc&lt;span&gt;&amp;nbsp;&lt;/span&gt;is a&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Symbolic_link&quot;&gt;symbolic link&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;to&lt;span&gt;&amp;nbsp;&lt;/span&gt;/private/etc)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Novell_NetWare&quot;&gt;Novell NetWare&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;SYS:etchosts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://opentutorials.org/wiki/OS/2&quot;&gt;OS/2&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;amp;&lt;a href=&quot;https://opentutorials.org/wiki/EComStation&quot;&gt;eComStation&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&quot;bootdrive&quot;:mptnetc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td rowspan=&quot;2&quot;&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Symbian_OS&quot;&gt;Symbian&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Symbian OS 6.1&amp;ndash;9.0&lt;/td&gt;
&lt;td&gt;C:systemdatahosts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Symbian OS&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Symbian_OS#Symbian_OS_9.1&quot;&gt;9.1+&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;C:private10000882hosts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://opentutorials.org/wiki/MorphOS&quot;&gt;MorphOS&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;NetStack&lt;/td&gt;
&lt;td&gt;ENVARC:sys/net/hosts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://opentutorials.org/wiki/AmigaOS&quot;&gt;AmigaOS&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;DEVS:Internet/hosts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Android_(operating_system)&quot;&gt;Android&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;/system/etc/hosts&lt;span&gt;&amp;nbsp;&lt;/span&gt;(or&lt;span&gt;&amp;nbsp;&lt;/span&gt;/etc/hosts, since&lt;span&gt;&amp;nbsp;&lt;/span&gt;/etc&lt;span&gt;&amp;nbsp;&lt;/span&gt;is a&lt;a href=&quot;https://opentutorials.org/wiki/Symbolic_link&quot;&gt;symbolic link&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;to&lt;span&gt;&amp;nbsp;&lt;/span&gt;/system/etc)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://opentutorials.org/wiki/IOS_(Apple)&quot;&gt;iOS&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;iOS 2.0 and newer&lt;/td&gt;
&lt;td&gt;/private/etc/hosts&lt;span&gt;&amp;nbsp;&lt;/span&gt;(or&lt;span&gt;&amp;nbsp;&lt;/span&gt;/etc/hosts, since&lt;span&gt;&amp;nbsp;&lt;/span&gt;/etc&lt;span&gt;&amp;nbsp;&lt;/span&gt;is a&lt;a href=&quot;https://opentutorials.org/wiki/Symbolic_link&quot;&gt;symbolic link&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;to&lt;span&gt;&amp;nbsp;&lt;/span&gt;/private/etc)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://opentutorials.org/wiki/TOPS-20&quot;&gt;TOPS-20&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;&amp;lt;SYSTEM&amp;gt;HOSTS.TXT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href=&quot;https://opentutorials.org/wiki/Plan_9_from_Bell_Labs&quot;&gt;Plan 9&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;&amp;nbsp;&lt;/td&gt;
&lt;td&gt;/lib/ndb/hosts&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;host 파일을 수정하는 이유&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;특정 도메인의 환경을 테스트를 해야 하는데 해당 도메인의 소유권이 없거나 해당 도메인이 다른 상황에서 사용되고 있을 때 도메인을 직접 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>INFO/WEB</category>
      <author>AGAL</author>
      <guid isPermaLink="true">https://agal.tistory.com/226</guid>
      <comments>https://agal.tistory.com/226#entry226comment</comments>
      <pubDate>Thu, 17 Mar 2022 14:12:33 +0900</pubDate>
    </item>
    <item>
      <title>정규표현식 패턴 - 정규표현식 | 생활코딩</title>
      <link>https://agal.tistory.com/225</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;※ 예제 설명&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;정규표현식 === 소스&lt;span style=&quot;color: #000000;&quot;&gt; &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;첫 매치&lt;/b&gt; 모두 매치&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;위치&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;^&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;: 캐럿 뒤에 나오는 패턴이 소스 상에서 시작 위치에 있을 때만 매치&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;^who === &lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;who&lt;/b&gt;&lt;/span&gt; &lt;/span&gt;is who&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&amp;amp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;: 달러 앞에 나오는 패턴이 소스 상에서 끝 위치에 있을 때만 매치&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;who$ === who is &lt;span style=&quot;color: #000000;&quot;&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;b&gt;who&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;이스케이핑&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;\&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;: 백슬래시 뒤에 나오는 문자를 정규표현식에서 의미가 있는 문법적 요소(^, $, 등)가 아닌 일반 문자로 변환&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;^\$ === &lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;&lt;b&gt;$&lt;/b&gt;&lt;/span&gt;12-$13&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;*escape(이스케이프) : 코드 상에서 어떤 역할로부터 탈출(해제) 시켜 준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;모든 문자&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;.&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;: 모든 문자(≒character)를 매치&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;.... === &lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;&lt;b&gt;test&lt;/b&gt; of poin&lt;/span&gt;t&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;특정 문자&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;[]&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;: 스퀘어 브라켓(대괄호) 안에 있는 문자 중 일치하는 문자 하나를 매치&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;[oyu] === H&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;o&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;w d&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;o&lt;/span&gt;&lt;/span&gt; &lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;you&lt;/span&gt; d&lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;o&lt;/span&gt;?&lt;br /&gt;[dH]. === &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;Ho&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;w &lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;do&lt;/span&gt; you &lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;do&lt;/span&gt;?&lt;br /&gt;[owy][yow] === H&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;ow&lt;/span&gt;&lt;/b&gt;&lt;/span&gt; do &lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;yo&lt;/span&gt;u do?&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;-&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;: 대시 앞에 나오는 문자부터 대쉬 뒤에 나오는 문자까지의 범위&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;[C-F] === AB&lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;&lt;b&gt;C&lt;/b&gt;DEF&lt;/span&gt;GH&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;^&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;: 스퀘어 브라켓 안에서의 캐럿은 부정의 의미&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;[^C-F] === &lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;AB&lt;/span&gt;CDEF&lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;GH&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;서브 패턴&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;()&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;: 퍼렌씨시스(소괄호) 안에 파이프(수직선)로 분리한 문자 중 일치하는 문자를 매치&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;(on|ues|rida) === M&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;on&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;day T&lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;ues&lt;/span&gt;day F&lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;rida&lt;/span&gt;y&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;수량자&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;*&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;: 아스테리스크(별표) 앞에 나오는 패턴이 있을 수도 있고 없을 수도 있는 것을 의미 (0개 ~ 여러개) ≒ {0,}&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;a*b === &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;aab&lt;/span&gt;&lt;/b&gt;&lt;/span&gt; &lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;ab&lt;/span&gt;c &lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;b&lt;/span&gt;c&lt;br /&gt;[-@]* === &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;-@-&lt;/span&gt;&lt;/b&gt;&lt;/span&gt; *** &lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;--&lt;/span&gt; *** &lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;-@-&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;+&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;: 플러스(더하기) 앞에 나오는 패턴이 하나 이상 있음을 의미 (1개 ~ 여러개) ≒ {1,}&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;a+b === &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;aab&lt;/span&gt;&lt;/b&gt;&lt;/span&gt; &lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;ab&lt;/span&gt;c bc&lt;br /&gt;[^ ] === &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;-@-&lt;/span&gt;&lt;/b&gt;&lt;/span&gt; &lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;***&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;-- ***&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;-@-&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;: 퀘션(물음표) 앞에 나오는 패턴이 없거나 하나인 경우를 의미 (0개 ~ 1개) ≒ {0,1}&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;a?b === a&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;ab&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;ab&lt;/span&gt;c &lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;b&lt;/span&gt;c&lt;br /&gt;-@?@?@?- === X&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;--&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;X&lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;-@-&lt;/span&gt;XX-@@@@-XX&lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;-@@-&lt;/span&gt;XX&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;{}&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;: 브레이스(중괄호) 안에 있는 숫자만큼 브레이스 앞에 있는 패턴을 매치&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;[els]{5} === th&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;e&lt;/span&gt;&lt;/b&gt;&lt;/span&gt; darkn&lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;ess&lt;/span&gt; bind th&lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;e&lt;/span&gt;m&lt;br /&gt;[els]{2,3} === them a&lt;b&gt;&lt;span style=&quot;color: #000000; background-color: #c0d1e7;&quot;&gt;ll&lt;/span&gt;&lt;/b&gt; darkn&lt;span style=&quot;color: #000000; background-color: #c0d1e7;&quot;&gt;ess&lt;/span&gt;&amp;nbsp;&lt;br /&gt;[a-z]{3,} === One &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;ring&lt;/span&gt;&lt;/b&gt;&lt;/span&gt; to &lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;bring&lt;/span&gt;&amp;nbsp; &amp;nbsp; // {3,} 은 3개 이상 매치&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;* 콤마(쉼표)로 매칭되는 개수의 범위를 정한다. 예를 들어 {1, 3} 은 1개에서 3개까지 매치&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;※ 수량자(*, +, ?) 뒤에 ?가 있을 경우 해당 수량자의 최소값으로 매치&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;r.*? === One &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;r&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;ing to b&lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;r&lt;/span&gt;ing&amp;nbsp; &amp;nbsp; &amp;nbsp;// 0개 매치&lt;br /&gt;r.+? === One &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;ri&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;ng to b&lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;ri&lt;/span&gt;ng&amp;nbsp; &amp;nbsp; // 1개&amp;nbsp;매치&lt;br /&gt;r.?? === One&amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;r&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;ing to b&lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;r&lt;/span&gt;ing&amp;nbsp; &amp;nbsp; &amp;nbsp;// 0개&amp;nbsp;매치&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;※&amp;nbsp;탐욕적 vs 게으른 수량자&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&amp;lt;div&amp;gt;.+&amp;lt;\/div&amp;gt; === &lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&amp;lt;div&amp;gt;text&amp;lt;/div&amp;gt; &amp;lt;div&amp;gt;text2&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; // &lt;u&gt;.+&lt;/u&gt; 는 탐욕적 선택자&lt;br /&gt;&amp;lt;div&amp;gt;.+?&amp;lt;\/div&amp;gt; === &lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;&amp;lt;div&amp;gt;text&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/b&gt; &lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;&amp;lt;div&amp;gt;text2&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp; // &lt;u&gt;.+?&lt;/u&gt; 는 게으른 선택자&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;경계&lt;/h2&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;\w&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;: word(단어) 를 매체&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;[a-z]\w* === A1 B2 &lt;span style=&quot;color: #000000; background-color: #c0d1e7;&quot;&gt;&lt;b&gt;c3&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000; background-color: #c0d1e7;&quot;&gt;d_4&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;color: #000000; background-color: #c0d1e7;&quot;&gt;e&lt;/span&gt;:5 &lt;span style=&quot;background-color: #c0d1e7; color: #000000;&quot;&gt;ffGG77&lt;/span&gt;--__--&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>INFO/WEB</category>
      <author>AGAL</author>
      <guid isPermaLink="true">https://agal.tistory.com/225</guid>
      <comments>https://agal.tistory.com/225#entry225comment</comments>
      <pubDate>Fri, 8 Oct 2021 18:12:30 +0900</pubDate>
    </item>
    <item>
      <title>2. 모듈패턴으로 기존 코드 개선하기 - 견고한 JS 소프트웨어 만들기 | 김정환</title>
      <link>https://agal.tistory.com/222</link>
      <description>&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;클릭 카운터 모듈 (ClickCounter)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;: 카운터 데이터를 다루는 모듈 (전역 공간에 있는 counter 변수를 ClickCounter 안에서 관리하자)&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;첫번째 스펙&amp;nbsp;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&quot;ClickCounter 모듈의 getValue() 는 카운터 값을 반환한다.&quot;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&amp;gt; git&amp;nbsp;checkout&amp;nbsp;--force&amp;nbsp;ClickCounter-spec-1&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;두번째 스펙&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&quot;ClickCounter 모듈의 increase() 는 카운터 값을 1만큼 증가한다.&quot;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&amp;gt; git checkout --force ClickCounter-spec-2&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;beforEach는 it 함수 호출 직전에 실행되는 자스민 함수.&lt;/p&gt;
&lt;pre id=&quot;code_1630546422409&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;describe(() =&amp;gt; {
  beforeEach(() =&amp;gt; {})	// 1
  afterEach(() =&amp;gt; {})	// 3
  it(() =&amp;gt; {})		// 2
})&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;중복 코드를 beforeEach로 옮기자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;※ 중복 코드를 제거한 코드를 DRY(&lt;span style=&quot;color: #202124;&quot;&gt;Don't&lt;/span&gt; Repeat Yourself) 하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;클릭 카운트 뷰 모듈 (ClickCounte View)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;카운터 데이터는 돔(DOM)에 반영되어야 한다. 데이터를 출력하고 이벤트 핸들러를 바인딩하는 일을 담당할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;첫번째 스펙&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&quot;ClickCounterView 모듈의 updateView()는 카운트 값을 출력한다.&quot;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&amp;gt; git checkout --force ClickCountView-spec-1&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;Q) 데이터를 조회할 ClickCounter를 어떻게 얻을까? 데이터를 출력할 돔 엘리먼트는 어떻게 테스트 할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;A) 주입하자&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;- ClickCounter는 객체를 만들어 파라미터로 전달 받자&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;- 데이터를 출력할 돔 엘리먼트를 만들어 전달 받자&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;TDD&amp;nbsp; 방식으로 사고하다 보면 이런 식으로 필요한 &lt;span style=&quot;color: #ee2323;&quot;&gt;모듈을 주입&lt;/span&gt;받아 사용하는 경향이 생김&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;하나의 기능 단위로 모듈을 분리할 수 있기 때문에 &lt;span style=&quot;color: #ee2323;&quot;&gt;단일 책임 원칙&lt;/span&gt;을 지킬 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;Q) ClickCountView에 의존성 주입이 되었는지는 어떻게 체크할까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;A) 의존성 주입을 테스트하는 코드를 작성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;두번째 스펙&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&quot;ClickCounterView 모듈의 increaseAndUpdateView()는 카운트 값을 증가하고 그 값을 출력한다.&quot;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&amp;gt; git checkout --force ClickCountView-spec-2&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;# 테스트 더블&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;단위 테스트 패턴으로, 테스트하기 곤란한 컴포넌트를 대체하여 테스트하는 것. 특정한 동작을 흉내만 낼뿐이지만 테스트 하기에는 적합하다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;더미(dummy): 인자를 채우기 위해 사용&lt;/li&gt;
&lt;li&gt;스텁(sturb): 더미를 개선하여 실제 동작하게끔 만든 것. 리턴값을 하드코딩한다.&lt;/li&gt;
&lt;li&gt;스파이(spy): 스텁과 유사, 내부적으로 기록을 남기는 추가 기능&lt;/li&gt;
&lt;li&gt;페이크(fake): 스텁에서 발전한 실제 코드.&lt;/li&gt;
&lt;li&gt;목(mock): 더미, 스텁, 스파이를 혼합한 형태&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;자스민에서는 테스트 더블을 스파이스(spies)라고 부른다. spyOn(), createSpy() 함수를 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;세번째 스펙&lt;/h4&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&quot;클릭 이벤트가 발생하면 increaseAndUpdateView()를 실행한다.&quot;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style3&quot;&gt;&amp;gt; git checkout --force ClickCountView-spec-3&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;클릭 이벤트 핸들러(increseAndUpdateView)를 바인딩할 돔 엘리먼트(triggerEl)를 주입 받자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Javascript/프로그래밍 기법</category>
      <author>AGAL</author>
      <guid isPermaLink="true">https://agal.tistory.com/222</guid>
      <comments>https://agal.tistory.com/222#entry222comment</comments>
      <pubDate>Thu, 2 Sep 2021 17:43:09 +0900</pubDate>
    </item>
  </channel>
</rss>