JavaScript에서 배열을 복제하는 가장 빠른 방법-슬라이스 대 'for'루프


634

JavaScript에서 배열을 복제하려면 다음 중 사용하는 것이 더 빠릅니까?

슬라이스 방법

var dup_array = original_array.slice();

For 고리

for(var i = 0, len = original_array.length; i < len; ++i)
   dup_array[i] = original_array[i];

나는 두 가지 방법으로 만 할 알고 얕은 복사 : original_array 개체에 대한 참조를 포함하는 경우, 객체는 복제되지 않지만 참조 만이 복사됩니다, 따라서 두 배열은 같은 객체에 대한 참조를해야합니다. 그러나 이것은이 질문의 요점이 아닙니다.

나는 단지 속도에 대해서만 묻고있다.


3
jsben.ch/#/wQ9RU <= 어레이를 복제하는 가장 일반적인 방법에 대한 벤치 마크
— EscapeNetscape

답변:


776

배열을 복제하는 방법 은 적어도 5 가지 (!) 있습니다.

  • 고리
  • 일부분
  • Array.from ()
  • 연결하다
  • 스프레드 연산자 (FASTEST)

huuuge BENCHMARKS 스레드 가 있으며 다음 정보를 제공합니다.

  • 대한 깜박임 브라우저 slice(), 가장 빠른 방법입니다 concat()조금 느린이며, while loop2.4 배는 느립니다.

  • 다른 브라우저의 while loop경우 가장 빠른 방법입니다. 해당 브라우저에는 slice및에 대한 내부 최적화가 없기 때문 concat입니다.

2016 년 7 월에도 마찬가지입니다.

다음은 브라우저의 콘솔에 복사하여 붙여넣고 여러 번 실행하여 그림을 볼 수있는 간단한 스크립트입니다. 그들은 밀리 초를 출력하며 낮을수록 좋습니다.

while 루프

n = 1000*1000;
start = + new Date();
a = Array(n); 
b = Array(n); 
i = a.length;
while(i--) b[i] = a[i];
console.log(new Date() - start);

일부분

n = 1000*1000;
start = + new Date();
a = Array(n); 
b = a.slice();
console.log(new Date() - start);

이러한 메소드는 Array 객체 자체를 복제하지만 배열 내용은 참조로 복사되며 딥 복제되지는 않습니다.

origAr == clonedArr //returns false
origAr[0] == clonedArr[0] //returns true

48
@ cept0 감정 없음, 벤치마킹 jsperf.com/new-array-vs-splice-vs-slice/31
— Dan

2
@ 댄 그래서 무엇? 테스트 결과 : 매일 밤 Firefox 30이 Chrome보다 ~ 230 % 더 빠릅니다. V8의 소스 코드를 확인하면 splice놀랄 것입니다. (...)
— mate64

4
슬프게도 짧은 배열의 경우 그 대답은 크게 다릅니다 . 예를 들어, 각 리스너를 호출하기 전에 리스너의 배열을 복제합니다. 이러한 배열은 대개 작으며 대개 1 개의 요소입니다.
— gman

6
이 방법을 놓쳤다 :A.map(function(e){return e;});
— wcochran

13
깜박임 브라우저 에 대해 쓰고 있습니다. 주로 HTML 렌더링에 영향을 미쳐 중요하지 않은 레이아웃 엔진 만 깜박 이지 않습니까? V8, Spidermonkey 및 친구들에 대해 이야기하고 싶다고 생각했습니다. 나를 혼란스럽게 한 것. 내가 틀렸다면 나를 깨우 치십시오.
— Neonit

241

기술적 slice 으로 가장 빠른 방법입니다. 그러나0 시작 색인 을 추가하면 더 빠릅니다 .

myArray.slice(0);

보다 빠르다

myArray.slice();

http://jsperf.com/cloning-arrays/3


그리고 myArray.slice(0,myArray.length-1);보다 빠르다 myArray.slice(0);?
— jave.web

1
@ jave.web you; 방금 배열의 마지막 요소를 삭제했습니다. 전체 사본은 array.slice (0) 또는 array.slice (0, array.length)입니다.
— Marek Marczak

137

es6 방법은 어떻습니까?

arr2 = [...arr1];

23
babel로 변환하는 경우 :[].concat(_slice.call(arguments))
— CHAN

1
어디에서 오는지 확실하지 않습니다 arguments... 귀하의 babel 출력이 몇 가지 다른 기능을 혼란스럽게 생각합니다. 더 가능성이 높습니다 arr2 = [].concat(arr1).
— Sterling Archer

3
@SterlingArcher arr2 = [].conact(arr1)와는 다릅니다 arr2 = [...arr1]. [...arr1]구문은 hole을로 변환합니다 undefined. 예를 들면 다음과 같습니다 arr1 = Array(1); arr2 = [...arr1]; arr3 = [].concat(arr1); 0 in arr2 !== 0 in arr3.
— tsh

1
위의 Dan 대답에 대해 내 브라우저 (Chrome 59.0.3071.115)에서 이것을 테스트했습니다. .slice ()보다 10 배 이상 느 렸습니다. n = 1000*1000; start = + new Date(); a = Array(n); b = [...a]; console.log(new Date() - start); // 168
— Harry Stevens

1
여전히 다음과 같은 것을 복제하지 않습니다 [{a: 'a', b: {c: 'c'}}]. 경우 c의 값은 "중복"배열에 변경 그냥 참조 사본이 아닌 클론이기 때문에, 그것은 원래의 배열로 변경됩니다.
— 신경 전달 물질

44

배열 또는 객체를 딥 복제하는 가장 쉬운 방법 :

var dup_array = JSON.parse(JSON.stringify(original_array))

56
초보자를위한 중요 사항 : JSON에 따라 다르므로 제한 사항도 상속합니다. 무엇보다도 배열은 undefined또는을 포함 할 수 없습니다 function. 그 과정에서 둘 다 null당신 을 위해 변환됩니다 JSON.stringify. (['cool','array']).slice()변경 과 같은 다른 전략 은 물론 배열 내에서 개체를 딥 복제하지 않습니다. 따라서 절충안이 있습니다.
— 세스 할러데이

27
성능이 매우 좋지 않으며 DOM, 날짜, 정규 표현식, 함수 ... 또는 프로토 타입 객체와 같은 특수 객체에서는 작동하지 않습니다. 순환 참조를 지원하지 않습니다. 딥 클론에는 JSON을 사용해서는 안됩니다.
— Yukulélé

17
최악의 방법! 일부 문제의 경우 다른 모든 문제가 해결되지 않는 경우에만 사용하십시오. 속도가 느리고 리소스가 많이 사용되며 주석에 언급 된 모든 JSON 제한이 있습니다. 25 개의 투표권을 얻는 방법을 상상할 수 없습니다.
— 루카스 리에 시스

2
프리미티브로 배열을 복사하고 속성은 추가 프리미티브 / 배열이있는 배열입니다. 이를 위해 괜찮습니다.
— Drenai

4
위의 Dan 대답에 대해 내 브라우저 (Chrome 59.0.3071.115)에서 이것을 테스트했습니다. .slice ()보다 거의 20 배 느 렸습니다. n = 1000*1000; start = + new Date(); a = Array(n); var b = JSON.parse(JSON.stringify(a)) console.log(new Date() - start); // 221
— Harry Stevens

29
var cloned_array = [].concat(target_array);

3
이것이 무엇을하는지 설명하십시오.
— Jed Fox

8
이 코드 스 니펫은 질문에 대답 할 수 있지만 방법과 이유를 설명하는 컨텍스트를 제공하지는 않습니다. 답을 설명하기 위해 한두 문장을 추가하십시오.
— brandonscript

32
나는 이런 종류의 의견을 싫어한다. 그것이하는 일이 분명하다!
— EscapeNetscape

6
간단한 질문에 대한 간단한 답변, 읽을만한 큰 이야기가 없습니다. 나는 대답 이런 종류의 일처럼
— 아킴

15
"속도에 대해서만 묻습니다"-이 답변은 속도에 대한 정보를 제공하지 않습니다. 이것이 주요 질문입니다. brandonscript는 좋은 지적이 있습니다. 이 답변을 고려하려면 추가 정보가 필요합니다. 그러나 더 간단한 질문이라면 훌륭한 답변이 될 것입니다.
— TamusJRoyce

26

빠른 데모를 만들었습니다 : http://jsbin.com/agugo3/edit

Internet Explorer 8의 결과는 156, 782 및 750이며이 slice경우 훨씬 빠릅니다.


이 작업을 매우 빠르게 수행해야하는 경우 가비지 수집기의 추가 비용을 잊지 마십시오. 슬라이스를 사용하여 셀룰러 오토마타의 각 셀에 대해 각 이웃 배열을 복사하고 있었고 이전 배열을 재사용하고 값을 복사하는 것보다 훨씬 느 렸습니다. Chrome은 총 시간의 약 40 %가 가비지 수집에 소비되었음을 나타냅니다.
— drake7707

21

a.map(e => e)이 작업의 또 다른 대안입니다. 현재로서는 Firefox에서는 .map()매우 빠르지 만 (거의 .slice(0)) Chrome에서는 그렇지 않습니다.

반면에 배열이 다차원 인 경우 배열은 객체이고 객체는 참조 유형이므로 슬라이스 또는 연결 방법 중 어느 것도 치료법이 될 수 없습니다. 따라서 배열을 복제하는 적절한 방법 중 하나 Array.prototype.clone()는 다음과 같습니다.

Array.prototype.clone = function(){
  return this.map(e => Array.isArray(e) ? e.clone() : e);
};

var arr = [ 1, 2, 3, 4, [ 1, 2, [ 1, 2, 3 ], 4 , 5], 6 ],
    brr = arr.clone();
brr[4][2][1] = "two";
console.log(JSON.stringify(arr));
console.log(JSON.stringify(brr));


나쁘지는 않지만 불행히도 배열에 Object가있는 경우 작동하지 않습니다 : \ JSON.parse (JSON.stringify (myArray))이 경우 더 잘 작동합니다.
— GBMan

17

🏁 어레이를 복제하는 가장 빠른 방법

어레이를 복제하는 데 걸리는 시간을 테스트하기 위해 매우 일반적인 유틸리티 기능을 만들었습니다. 100 % 신뢰할 수는 없지만 기존 어레이를 복제하는 데 걸리는 시간에 대한 정보를 얻을 수 있습니다.

function clone(fn) {
    const arr = [...Array(1000000)];
    console.time('timer');
    fn(arr);
    console.timeEnd('timer');
}

그리고 다른 접근법을 테스트했습니다.

1)   5.79ms -> clone(arr => Object.values(arr));
2)   7.23ms -> clone(arr => [].concat(arr));
3)   9.13ms -> clone(arr => arr.slice());
4)  24.04ms -> clone(arr => { const a = []; for (let val of arr) { a.push(val); } return a; });
5)  30.02ms -> clone(arr => [...arr]);
6)  39.72ms -> clone(arr => JSON.parse(JSON.stringify(arr)));
7)  99.80ms -> clone(arr => arr.map(i => i));
8) 259.29ms -> clone(arr => Object.assign([], arr));
9) Maximum call stack size exceeded -> clone(arr => Array.of(...arr));

업데이트 :
참고 : 그중에서도 배열을 딥 복제하는 유일한 방법은을 사용하는 것 JSON.parse(JSON.stringify(arr))입니다.

즉, 배열에 반환 할 함수가 포함되어 있으면 위의 내용을 사용하지 마십시오 null.
이 업데이트에 대해 @GilEpshtain에게 감사합니다 .


2
귀하의 답변을 벤치마킹하려고 시도한 결과 매우 다른 결과를 얻었습니다. jsben.ch/o5nLG
— mesqueeb

@mesqueeb, 물론 기계에 따라 테스트가 변경 될 수 있습니다. 그러나 테스트 결과로 답변을 업데이트하십시오. 잘 했어!
— Lior Elrom

나는 당신의 대답을 많이 좋아하지만 테스트를 시도하고 그것이 arr => arr.slice()가장 빠릅니다.
— Gil Epshtain

1
@LiorElrom, 메소드를 직렬화 할 수 없기 때문에 업데이트가 올바르지 않습니다. 예를 들어 JSON.parse(JSON.stringify([function(){}]))출력됩니다[null]
— 길 Epshtain

1
좋은 벤치 마크. 나는이 브라우저 내 Mac에서이 테스트 한 크롬 버전 81.0.4044.113 사파리 버전 13.1 (15609.1.20.111.8) 빠른 확산 작업은 다음 [...arr]과 4.653076171875ms크롬과 8.565ms사파리입니다. 크롬에서 두 번째로 빠른 슬라이스 기능이다 arr.slice()와 6.162109375ms사파리에서 두 번째 [].concat(arr)로 13.018ms.
— edufinn

7

링크를 살펴보십시오 . 속도가 아니라 편안함입니다. 보시 다시피 기본 유형 에서만 slice (0) 을 사용할 수 있습니다 .

참조의 복사본이 아닌 배열의 독립 복사본을 만들려면 배열 슬라이스 방법을 사용할 수 있습니다.

예:

참조의 복사본이 아닌 배열의 독립 복사본을 만들려면 배열 슬라이스 방법을 사용할 수 있습니다.

var oldArray = ["mip", "map", "mop"];
var newArray = oldArray.slice();

객체를 복사하거나 복제하려면

function cloneObject(source) {
    for (i in source) {
        if (typeof source[i] == 'source') {
            this[i] = new cloneObject(source[i]);
        }
        else{
            this[i] = source[i];
  }
    }
}

var obj1= {bla:'blabla',foo:'foofoo',etc:'etc'};
var obj2= new cloneObject(obj1);

출처 : 링크


1
기본 유형의 코멘트는 적용 for뿐만 아니라 해당 루프.
— user113716

4
객체 배열을 복사하는 경우 새 배열이 객체를 복제하는 대신 동일한 객체를 참조 할 것으로 기대합니다.
— lincolnk

7

@Dan으로 "이 대답은 빠르게 구식이된다 사용. 말했다 벤치 마크 실제 상황을 확인하기 위해"자체에 대한 대답이 없었습니다 jsperf에서 하나 개의 특정 응답이 : 상태 :

var i = a.length;
while(i--) { b[i] = a[i]; }

578,129 ops / sec ( a.concat()60 %)의 런너 업으로 960,589 ops / sec를 기록했습니다.

이것은 최신 Firefox (40) 64 비트입니다.


@aleclarson은 새롭고보다 안정적인 벤치 마크를 만들었습니다.


1
jsperf를 실제로 연결해야합니다. 'while loop'테스트를 제외하고 모든 테스트 케이스에 새 배열이 생성되므로 생각중인 것이 깨졌습니다.
— aleclarson

1
더 정확한 새 jsperf를 만들었습니다 : jsperf.com/clone-array-3
— aleclarson

60 % 무엇? 60 % 더 빠릅니까?
— Peter Mortensen

1
@PeterMortensen : 587192는 960589의 ~ 60 % (61.1 ...)입니다.
— serv-inc

7

Spread운영자 와 ECMAScript 2015 방법 :

기본 예 :

var copyOfOldArray = [...oldArray]
var twoArraysBecomeOne = [...firstArray, ..seccondArray]

브라우저 콘솔에서 시도하십시오 :

var oldArray = [1, 2, 3]
var copyOfOldArray = [...oldArray]
console.log(oldArray)
console.log(copyOfOldArray)

var firstArray = [5, 6, 7]
var seccondArray = ["a", "b", "c"]
var twoArraysBecomOne = [...firstArray, ...seccondArray]
console.log(twoArraysBecomOne);

참고 문헌


아마도 스프레드가 빠른 유일한 것은 입력하는 것입니다. 다른 방법보다 성능이 떨어집니다.
— XT_Nova

3
논증에 대한 링크를 제공하십시오.
— Marian07

6

브라우저에 따라 다릅니다. 블로그 게시물 Array.prototype.slice vs manual array creation 을 보면 각각의 성능에 대한 대략적인 지침이 있습니다.

여기에 이미지 설명을 입력하십시오

결과 :

여기에 이미지 설명을 입력하십시오


1
arguments적절한 배열이 아니며 컬렉션에서 call강제 slice로 실행하는 데 사용하고 있습니다. 결과가 잘못 될 수 있습니다.
— lincolnk

Yeh는 내 게시물에서 이러한 통계가 브로 더가 향상됨에 따라 지금은 변경 될 것이라고 언급했지만 일반적인 아이디어를 제공합니다.
— kyndigs

2
@diugalde 나는 그림으로 코드를 게시하는 것이 허용되는 유일한 상황은 코드가 잠재적으로 위험하고 복사 붙여 넣기를해서는 안되는 경우라고 생각합니다. 그러나이 경우에는 꽤 어리 석습니다.
— Florian Wendelborn 2016 년

6

훨씬 더 깨끗한 해결책이 있습니다.

var srcArray = [1, 2, 3];
var clonedArray = srcArray.length === 1 ? [srcArray[0]] : Array.apply(this, srcArray);

Array생성자가 정확히 하나의 인수로 호출 될 때 생성자가 다르게 동작 하므로 길이 검사가 필요합니다 .


2
그러나 가장 빠릅니까?
— Chris Wesseling

14
splice()아마도 보다 의미 론적 입니다. 하지만 실제로는, 적용 하고 이 모든하지만 직관적이다.
— Michael Piefel

쇼에 가장 느린 성능 크롬 - jsperf.com/new-array-vs-splice-vs-slice/113
— chrismarx

3
Array.of길이를 사용 하고 무시할 수 있습니다 .Array.of.apply(Array, array)
— Oriol

6

.slice ()는 2 차원 배열에서는 작동하지 않습니다. 다음과 같은 기능이 필요합니다.

function copy(array) {
  return array.map(function(arr) {
    return arr.slice();
  });
}

3
자바 스크립트에는 2 차원 배열이 없습니다. 배열을 포함하는 배열이 있습니다. 당신이하려는 것은 질문에 필요하지 않은 깊은 사본 입니다.
— Aloso

5

배열의 길이에 따라 다릅니다. 배열 길이가 <= 1,000,000 인 경우 slice및 concat메소드는 거의 같은 시간이 걸립니다. 그러나 더 넓은 범위를 제공하면 concat방법이 승리합니다.

예를 들어 다음 코드를 사용해보십시오.

var original_array = [];
for(var i = 0; i < 10000000; i ++) {
    original_array.push( Math.floor(Math.random() * 1000000 + 1));
}

function a1() {
    var dup = [];
    var start = Date.now();
    dup = original_array.slice();
    var end = Date.now();
    console.log('slice method takes ' + (end - start) + ' ms');
}

function a2() {
    var dup = [];
    var start = Date.now();
    dup = original_array.concat([]);
    var end = Date.now();
    console.log('concat method takes ' + (end - start) + ' ms');
}

function a3() {
    var dup = [];
    var start = Date.now();
    for(var i = 0; i < original_array.length; i ++) {
        dup.push(original_array[i]);
    }
    var end = Date.now();
    console.log('for loop with push method takes ' + (end - start) + ' ms');
}

function a4() {
    var dup = [];
    var start = Date.now();
    for(var i = 0; i < original_array.length; i ++) {
        dup[i] = original_array[i];
    }
    var end = Date.now();
    console.log('for loop with = method takes ' + (end - start) + ' ms');
}

function a5() {
    var dup = new Array(original_array.length)
    var start = Date.now();
    for(var i = 0; i < original_array.length; i ++) {
        dup.push(original_array[i]);
    }
    var end = Date.now();
    console.log('for loop with = method and array constructor takes ' + (end - start) + ' ms');
}

a1();
a2();
a3();
a4();
a5();

original_array의 길이를 1,000,000으로 설정하면 slice메서드와 concat메서드가 거의 같은 시간 (임의의 숫자에 따라 3 ~ 4ms)이 걸립니다.

original_array의 길이를 10,000,000으로 설정하면 slice60ms를 초과하고 concat20ms를 초과합니다.


dup.push에서 잘못 사용되었습니다 a5. 대신 dup[i] = 사용해야합니다
— 4esn0k


2
        const arr = ['1', '2', '3'];

         // Old way
        const cloneArr = arr.slice();

        // ES6 way
        const cloneArrES6 = [...arr];

// But problem with 3rd approach is that if you are using muti-dimensional 
 // array, then only first level is copied

        const nums = [
              [1, 2], 
              [10],
         ];

        const cloneNums = [...nums];

// Let's change the first item in the first nested item in our cloned array.

        cloneNums[0][0] = '8';

        console.log(cloneNums);
           // [ [ '8', 2 ], [ 10 ], [ 300 ] ]

        // NOOooo, the original is also affected
        console.log(nums);
          // [ [ '8', 2 ], [ 10 ], [ 300 ] ]

따라서 이러한 시나리오가 발생하지 않도록하려면

        const arr = ['1', '2', '3'];

        const cloneArr = Array.from(arr);

cloneNums[0][0]예제의 변경 사항이 변경 사항을 어떻게 전파 했는지에 대해 지적하는 것은 타당합니다. nums[0][0]그러나 nums[0][0]실제로는 cloneNums스프레드 연산자 에 의해 참조가 복사되는 객체 이기 때문 입니다. 즉,이 동작은 값 (int, string 등 리터럴)으로 복사하는 코드에는 영향을 미치지 않습니다.
— Aditya MP

1

벤치 마크 시간!

function log(data) {
  document.getElementById("log").textContent += data + "\n";
}

benchmark = (() => {
  time_function = function(ms, f, num) {
    var z = 0;
    var t = new Date().getTime();
    for (z = 0;
      ((new Date().getTime() - t) < ms); z++)
      f(num);
    return (z)
  }

  function clone1(arr) {
    return arr.slice(0);
  }

  function clone2(arr) {
    return [...arr]
  }

  function clone3(arr) {
    return [].concat(arr);
  }

  Array.prototype.clone = function() {
    return this.map(e => Array.isArray(e) ? e.clone() : e);
  };

  function clone4(arr) {
    return arr.clone();
  }


  function benchmark() {
    function compare(a, b) {
      if (a[1] > b[1]) {
        return -1;
      }
      if (a[1] < b[1]) {
        return 1;
      }
      return 0;
    }

    funcs = [clone1, clone2, clone3, clone4];
    results = [];
    funcs.forEach((ff) => {
      console.log("Benchmarking: " + ff.name);
      var s = time_function(2500, ff, Array(1024));
      results.push([ff, s]);
      console.log("Score: " + s);

    })
    return results.sort(compare);
  }
  return benchmark;
})()
log("Starting benchmark...\n");
res = benchmark();

console.log("Winner: " + res[0][0].name + " !!!");
count = 1;
res.forEach((r) => {
  log((count++) + ". " + r[0].name + " score: " + Math.floor(10000 * r[1] / res[0][1]) / 100 + ((count == 2) ? "% *winner*" : "% speed of winner.") + " (" + Math.round(r[1] * 100) / 100 + ")");
});
log("\nWinner code:\n");
log(res[0][0].toString());
<textarea rows="50" cols="80" style="font-size: 16; resize:none; border: none;" id="log"></textarea>

버튼을 클릭 한 후 10 초 동안 벤치 마크가 실행됩니다.

내 결과 :

크롬 (V8 엔진) :

1. clone1 score: 100% *winner* (4110764)
2. clone3 score: 74.32% speed of winner. (3055225)
3. clone2 score: 30.75% speed of winner. (1264182)
4. clone4 score: 21.96% speed of winner. (902929)

Firefox (SpiderMonkey Engine) :

1. clone1 score: 100% *winner* (8448353)
2. clone3 score: 16.44% speed of winner. (1389241)
3. clone4 score: 5.69% speed of winner. (481162)
4. clone2 score: 2.27% speed of winner. (192433)

우승자 코드 :

function clone1(arr) {
    return arr.slice(0);
}

승자 엔진 :

스파이더 몽키 (Mozilla / Firefox)


1

JavaScript에서 배열을 순서대로 복제하는 빠른 방법 :

#1: array1copy = [...array1];

#2: array1copy = array1.slice(0);

#3: array1copy = array1.slice();

배열 객체에 직렬화 할 수없는 JSON 콘텐츠 (함수, Number.POSITIVE_INFINITY 등)가 더 나은 경우

array1copy = JSON.parse(JSON.stringify(array1))


0

이 코드를 따를 수 있습니다. 불변의 방법 배열 복제. 이것은 복제를 배열하는 완벽한 방법입니다


const array = [1, 2, 3, 4]

const newArray = [...array]
newArray.push(6)
console.log(array)
console.log(newArray)

0

ES6에서는 간단히 스프레드 구문을 활용할 수 있습니다 .

예:

let arr = ['a', 'b', 'c'];
let arr2 = [...arr];

스프레드 연산자는 완전히 새로운 배열을 생성하므로 하나를 수정해도 다른 배열에는 영향을 미치지 않습니다.

예:

arr2.push('d') // becomes ['a', 'b', 'c', 'd']
console.log(arr) // while arr retains its values ['a', 'b', 'c']
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.