
문자열로 구성된 리스트 strings와, 정수 n이 주어졌을 때, 각 문자열의 인덱스 n번째 글자를 기준으로 오름차순 정렬하려 합니다. 예를 들어 strings가 ["sun", "bed", "car"]이고 n이 1이면 각 단어의 인덱스 1의 문자 "u", "e", "a"로 strings를 정렬합니다.

string.slice(n,n+1)
위의 내용이 처음에 생각한 내용이었다.
function solution(string, n) {
let strpart = (string.map(str => str.slice(n,n+1))).sort()
console.log(strpart)
}
콘솔을 확인해보면, 나오기는 했지만, n번지의 값만 가져와서 정렬을 했다. 문자열 전체가 온 것이 아니다. 즉 문제는 이해했지만 코드를 잘못 작성했다.

let string = ["abce", "abcd", "cdx"];
let n = 1
function solution(string, n) {
let arr = []
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "a"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "b"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "c"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "d"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "e"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "f"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "g"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "h"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "i"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "j"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "k"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "l"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "m"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "n"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "o"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "p"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "q"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "r"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "s"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "t"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "u"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "v"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "w"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "x"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "y"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "z"){arr.push(string[i])}}
console.log(arr
)}
solution(string, n)
slice(n,n+1)의 값이 만약 a 일 때부터 z 일 때까지 순차적으로 진행하면서, 해당되는 조건의 값을 순차적으로 기록하도록 하였다.string[0] 부터 string[string.length -1]까지 먼저 a 를 가지고 있으면 배열에 추가하고 아니면 다음 함수로 넘어간다.string[0] 부터 string[string.length -1]까지 먼저 b 를 가지고 있으면 배열에 추가하고 아니면 다음 함수로 넘어간다.string[0] 부터 string[string.length -1]까지 먼저 c 를 가지고 있으면 배열에 추가하고 아니면 다음 함수로 넘어간다...d부터 y까지를 위와 같이 실행하고,string[0] 부터 string[string.length -1]까지 먼저 z 를 가지고 있으면 배열에 추가하고 아니면 다음 함수로 넘어간다.결과는 n번지의 값으로만 비교했을 뿐이고, [0-(n+1)]번지까지의 내용은 비교하기 않았다는 것이다. 예를 들어서 아래를 보자.

여기서 결과로 산출된 값을 정렬해주려고 하니까. 접근이 되지 않았다.

단순하게, 산출된 값에 다시 sort()를 주었더니, 위의 코드를 실행할 이유가 없게 되었다. 즉 n번지의 값을 비교한 것이 의미없이, 그냥 0번지의 값으로 출력된 것이다.
sort() 의 위치를 변경시키져 적용시켰다.
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "a"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "b"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string[i].slice(n,n+1) == "c"){arr.push(string[i])}}
for(let i=0;i<string.length; i++)
...
for(let i=0;i<string.length; i++) {if(string.sort()[i].slice(n,n+1) == "a"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string.sort()[i].slice(n,n+1) == "b"){arr.push(string[i])}}
for(let i=0;i<string.length; i++) {if(string.sort()[i].slice(n,n+1) == "c"){arr.push(string[i])}}
...
결과는 성공이다.

function solution(strings, n) {
let answer = strings.sort((a,b) => {
if (a[n] < b[n]) return -1
if (a[n] > b[n]) return 1
if (a[n] === b[n]) {
if (a > b) return 1
if (a < b) return -1
return 0
}
})
return answer;
}
sort() 메소드를 위와 같이 세련되게 작성할 수 있구나라는 부분에 놀랐다.

sort((a,b) => a-b) 메소드의 진행과정 따라기
첫째, 배열에 있는 [0]번지와 [1]번지를 먼저 비교한다.
1) a = 1, b =5
2) 1 - 5 = -4(음수) a보다 b가 4칸 뒤에 있다.
3) 반환된 결과는 [ 1, 5 ]
둘째, 배열에 있는 [1]번지와 [2]번지를 다음으로 비교한다.
1) a = 5, b =4
2) 5 - 4 = 1 (양수면 앞으로 n칸) a가 b보다 1칸 앞에 있다.
3) 반환된 결과는 [ 4, 5 ]
4) 이전 값까지 포함된 결과 [1 , 4, 5]
셋째, 배열에 있는 [2]번지와 [3]번지를 다음으로 비교한다.
1) a = 4, b =6
2) 4 - 6 = -2 (음수면 뒤로 n칸)
3) 반환된 결과는 [ 4 → 뒤로 2칸→ 6 ]
4) 이전 값까지 포함된 결과 [ 1, 4, 5, 6]
넷째, 배열에 있는 [3]번지와 [4]번지를 다음으로 비교한다.
1) a = 6, b = 2
2) 6 - 2 = 4 (양수면 앞으로 n칸)
3) 반환된 결과는 [ 2 ← 앞으로 4칸 ← 6 ]
4) 이전 값까지 포함된 결과 [ 1, 2, 4, 5, 6]

sort((a,b) => a-b) 메소드의 진행과정 따라기
첫째, 배열에 있는 [0]번지와 [1]번지를 먼저 비교한다.
1) a = 1, b =5
2) 1 - 5 = -4(음수) a보다 b가 4칸 뒤에 있다.
3) 반환된 결과는 [ 1, 5 ]
둘째, 배열에 있는 [1]번지와 [2]번지를 다음으로 비교한다.
1) a = 5, b =4
2) 5 - 4 = 1 (양수면 앞으로 n칸) a가 b보다 1칸 앞에 있다.
3) 반환된 결과는 [ 4, 5 ]
4) 이전 값까지 포함된 결과 [1 , 4, 5]
셋째, 배열에 있는 [2]번지와 [3]번지를 다음으로 비교한다.
1) a = 4, b =6
2) 4 - 6 = -2 (음수면 뒤로 n칸)
3) 반환된 결과는 [ 4 → 뒤로 2칸→ 6 ]
4) 이전 값까지 포함된 결과 [ 1, 4, 5, 6]
넷째, 배열에 있는 [3]번지와 [4]번지를 다음으로 비교한다.
1) a = 6, b = 2
2) 6 - 2 = 4 (양수면 앞으로 n칸)
3) 반환된 결과는 [ 2 ← 앞으로 4칸 ← 6 ]
4) 이전 값까지 포함된 결과 [ 1, 2, 4, 5, 6]
함수은 가능한 간결하고 명확해야 한다. 함수가 어떤 동작을 하는지 설명할 수 있어야 한다. 코드로 기록된 내용을 보면 해당 함수가 어떤 기능인지 힌드를 얻을 수 있어야 한다.
showMessage(..) // 메시지를 보여줌getAge(..) // 나이를 나타내는 값을 얻고 그 값을 반환함calcSum(..) // 합계를 계산하고 그 결과를 반환함createForm(..) // form을 생성하고 만들어진 form을 반환함checkPermission(..) // 승인 여부를 확인하고 true나 false를 반환함또한 함수는 동작 하나만을 담당하도록 해야 한다. 즉 독립적인 두 개의 동작은 독립된 함수 두 개에서 나눠서 수행할 수 있게 해야 한다. 현업에서 선언되는 함수명에 대한 경고가 있어서 아래에 기록해 놓고자 한다.
개발자들이 빈번히 하는 실수를 소개해 보겠습니다.
- getAge 함수는 나이를 얻어오는 동작만 수행해야 합니다. alert 창에 나이를 출력해 주는 동작은 이 함수에 들어가지 않는 것이 좋습니다.
- createForm 함수는 form을 만들고 이를 반환하는 동작만 해야 합니다. form을 문서에 추가하는 동작이 해당 함수에 들어가 있으면 좋지 않습니다.
- checkPermission 함수는 승인 여부를 확인하고 그 결과를 반환하는 동작만 해야 합니다. 승인 여부를 보여주는 메시지를 띄우는 동작이 들어가 있으면 좋지 않습니다.
- 위 예시들은 접두어의 의미가 합의되었다고 가정하고 만들었습니다. 본인이나 본인이 속한 팀에서 접두어의 의미를 재합의하여 함수를 만들 수도 있긴 하지만, 아마도 위 예시에서 사용한 접두어 의미와 크게 차이가 나진 않을 겁니다. 어찌 되었든 접두어를 사용하여 함수 이름을 지을 땐, 해당 접두어에 어떤 의미가 있는지 잘 이해하고 있어야 합니다.
function showMessage() {
alert( '안녕하세요!' );
}
함수를 선언하고 그 안에 기록한 let과 const는 지역변수가 되며, 함수밖으로는 나가지 못한다. 이것이 스코프에 대한 이해이다. 반면에 함수 밖에 선언된 변수는 함수 안으로 가져올 수 있는데 이는 전역변수로 let과 const가 그 스코프에 따라서 내용을 가져올 수 있기 때문이다.
해당 내용은 아는 내용은 넘어가고, 만약 인자가 주어지지 않으면, 매개변수는 undefinded 데이터를 생성한다. 즉 내용이 없다는 것이다. 먼저 복수의 매개변수를 기록하는 것을 먼저 소개하고 이야기 해보도록 하겠다.
function 함수이름(복수의, 매개변수는, 콤마로, 구분합니다) {
/* 함수 본문 */
}
이번에는 매개변수에 해당되는 값에 인자를 주지 말아보자.
function showMessage(from, text = "no text given") {
alert( from + ": " + text );
}
showMessage("Ann");
인자("Ann")이 함수호출에서 기록되어 담겨가면, function showMessage(from, text = "no text given") 함수는 담겨진 인자를 매개변수from("Ann")에 담는다. 그러나 매개변수text에 대한 값은 담겨오지 않았다. 이럴 때 매개변수text에 해당되는 초기값을 위와 같이 지정해 주면 아래와 같이 기록된다.

구 자바스크립트에서는 아래와 같이 기록했다. 그런데 구 자바스크립트? 아마도 ECMAScript 5(ES5)이전버전의 자바스크립트를 의미하는 것 같다.
## 기록방법01
function showMessage(from, text) {
if (text === undefined) {
text = 'no text given';}
alert( from + ": " + text );}
## 기록방법02
function showMessage(from, text) {
// text의 값이 falsy면 기본값이 할당됨
// 이 방식은 text == ""일 경우, text에 값이 전달되지 않은것과 같다고 간주합니다..
text = text || 'no text given';}
기록방법02는 현재 자바스크립트에서도 사용할 수 있다. 이외에 모던 자바스크립트 엔진이 지원된다면, 아래의 방법도 있다고 한다.

let age = prompt("나이를 입력하세요.")
function showMovie(age) {
if ( !age || age < 20 ) {
return;}
else {
alert( "19영화 관람가능" );}
}
showMovie(age)
위와 같이 함수호출에 나이의 값이 입력되지 않으면, 매개변수가 undefined 이면 return 아래의 결과는 실행되지 않을 것이다.
함수선언식과 다르게 변수 또는 객체 내에 함수를 다루려고 할 때는 부르는 용어가 달라진다. 아래의 예시를 보자.
let hey = function() {alert( "Hello" );}
콘솔에 hey() 를 입력하면 아래와 같이 기록이다.

부모함수 내부에서 실행하는 함수를 자녀함수라고 볼 때, 콜백함수는 자녀함수를 지칭하는 말로 이해하면 될 것 같다. 강의안에는 이 부분에 대한 설명도 언급도 없기에, 내용을 살펴보고 나의 말로 정리한 내용이다.
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();}
function showOk() {
alert( "동의하셨습니다." );}
function showCancel() {
alert( "취소 버튼을 누르셨습니다." );}
ask("동의하십니까?", showOk, showCancel);
먼저, 최종적으로 기록된 ask()를 통해서 함수가 전언되었다.
question : "동의하십니까?"가 인자가 들어오고,yes : showOk 인자로 들어오고,no : showCancel 인자로 들어온다. 매개변수yes로 들어온 showOk 은 함수 내에서 yes() 를 통해서 함수로 작동하며, 동의하셨습니까를 실행시키고, 매개변수no 로 들어온 showCancel 은 함수 내에서 no() 를 통해서 함수로 작동하며, 취소 버튼을 누르셨습니다를 실행시킨다.
위의 있는 코드는 아래와 같이 기록할 수도 있다.
function ask(question, yes, no) {
if (confirm(question)) yes()
else no();
}
ask(
"동의하십니까?",
function() { alert("동의하셨습니다."); },
function() { alert("취소 버튼을 누르셨습니다."); }
);
이때 함수호출 시, 인자로 전달한 함수를 익명함수라고 부른다.
지금까지 살펴보았던 함수표현식 아래와 같다. 익명함수로 보통 아래와 같이 기록된다.
let student = function() {
return ...
}
이를 더 간결하게 기록할 수 있는데, 그것이 화살표 함수이다.
위의 함수는 아래와 같이 기록할 수 있다.
let student = () => return ...
스파르타코딩강의안에는 특별한 설명이 없지만, return이 복잡할 때는 {중괄호}를 생략하면 안된다. 또한 매개 변수가 없다면, (소괄호)도 생략할 수 없다. 만약 소괄호에 담긴 매개변수가 하나면 (소괄호)도 생략이 가능하다.
let hey = () => alert("안녕하세요!");
hey();
또한, 화살표 함수는 조건부 삼항 연산자 도 사용이 가능하다.
조건부 삼항 연산자 조건 ? 결과1 : 결과2
let age = prompt("나이를 알려주세요.", 18);
let welcome = (age < 18) ?
() => alert('청소년이네요') :
() => alert("성인이시네요");
welcome();
복잡하게 기록하면 이렇게도 설정할 수 있다.
let ask = (question, yes, no) => (confirm(question)) ? yes() : no();
ask("동의하십니까?", () => alert("동의하셨습니다."), () => alert("취소 버튼을 누르셨습니다."))
두 줄이지만, 쉽지 않다. 질문에 대한 사용자의 선택에 따라서 값니 true와 false가 될 것이다. true이면 yes()를 false이면 no()가 실행될 것인데, 내용을 보면 yes()는 동의하셨습니다를, no()는 취소 버튼을 누르셨습니다를 출력할 것이다.
JS 자료형은 크게 8가지로 정리할 수 있다. 그러나 이 자료형은 두 개로 다시 구분되는데 다음과 같다.
그러나 객체형은 다양한 데이터를 담을 수 있는데, property(key:value) 로 구성된 자료를 가지고 있다. 키에는 문자형, 값에는 모든 자료형이 허용된다. 함수까지도 말이다.
## 객체 생성자 문법
let user = new Object(); // '객체 생성자' 문법
## 객체 리터럴
let user = {};
(기존에 없던 key:value 를 선언함으로 가능)
만약 기존에 있는 property에 입력하면, 내용이 변경된다. 표기법은 점표기법과 [대괄호] 표기법으로 나눠진다.
let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple");
let bag = {};
bag[fruit] = 5;
bag에 속한 객체를 보면, 보이는 [fruit]가 바로 계산된 프로퍼티이다. bag.apple 을 실행하면, [fruit]에 있는 "apple"이 입력된 내용과 같이 prompt에 기록되어 산출될 것이다. 그리고 입력된 내용에 따라서, 기존 {[fruit]: 5}에는 apple이 기록될 것이다.
let fruit = 'apple';
let bag = {
[fruit + 'Computers']: 5 };
또한 입력받은 값으로 key 이름을 적용시킬 수도 있다. 다시 위에서 이야기 한 부분을 언급하자면, 함수를 통해서 새로운 객체를 생성하는 것도 가능하다.
function makeUser(name, age) {
return {
name: name,
age: age,
};
}
let user = makeUser("John", 30);
makeUser 로 선언된 user변수 객체를 만들 수 있다. 또한 예약어를 만들수도 있다.
let obj = {
for: 1,
let: 2,
return: 3
};
alert( obj.for + obj.let + obj.return );
결과는 6이 산출될 것이다.
let user = { name: "John", age: 30 };
alert( "age" in user );
alert( "blabla" in user );
age(key)는 있기 때문에 true가, blable(key)은 존재하지 않기 때문에 false가 나올 것이다.
for (key in object) {}
해당 내용을 통해서 object객에 있는 내용을 반복하여 출력할 수 있다. 객체는 자동으로 정렬된다. 아래를 보자. 그러나 해당 방법도 key가 정수일 때만 가능하다. 정수 이외에는 기록된 순서대로 출력된다.
let codes = {
"49": "독일",
"41": "스위스",
"44": "영국",
"1": "미국"};
for (let code in codes) {alert(code);}
const user = {
name: "John"};
## 사례1
user.name = "Pete";
## 사례2
user = 123;
const로 선언된 변수는 내용이 변경되지 않는 상수라고 배웠다. 그러나 객체에 대해서는 접근이 다른데, 사례1과 같이 property의 value를 변경한다고 하자. 변경이 된다. 그러나 사례2는 되지 않는데, 이는 user가 객체 데이터인데, 객체에 숫자형 데이터를 입력했기 때문이다. 형 자체의 변형은 const는 허용하지 않는다. 그러나 객체의 내용(value)을 변경하는 것은 허용한다.
let salaries = {
John: 100,
Ann: 160,
Pete: 130
}
function sum(num) {
let nums = 0;
for (key in num)
{nums = nums+ num[key]}
console.log(nums)
}
sum(salaries)
let menu = {
width: 200,
height: 300,
title: "My menu"
};
function multiplyNumeric(obj) {
for (let key in obj) {
if (typeof obj[key] == 'number') {
obj[key] *= 2;
}
}
}
multiplyNumeric(menu);
console.log(menu)
핵심은 if (typeof obj[key] == 'number') 들어온 value가 숫자형 자료인지 검색하는 것이다.
원시형 자료형의 복사는 단순했다. 아래와 같이 독립된 두개의 변수를 만들 수 있었다. 그러나 객체를 복사할 때는 방법이 다르다.
let message = "Hello!";
let phrase = message;
객체를 다음과 같이 선언하면, 예를 들어 하나의 통장에서 두개의 체크카드를 만든 것으로 이해하는 것과 동일하다. 하나의 창구를 같이 사용하는 것 뿐이다. 이를 참조에 의한 객체 복사라고 부른다.
let user = { name: "John" };
let admin = user;
일치연산자를 통해서 확인해 보면, true가 나오는 것을 볼 수 있다.
let a = {};
let b = a; // 참조에 의한 복사
alert( a == b ); // true, 두 변수는 같은 객체를 참조합니다.
alert( a === b ); // true
객체의 복사는 다음과 같이 진행된다.
let user = {
name: "John",
age: 30};
let clone = {}; // 새로운 빈 객체
for (let key in user) {
clone[key] = user[key];}
clone.name = "Pete";
반복문을 통해서 아래와 같이 새로운 빈객체에 입력해준다고 하자. 결과를 보면 clone만 수정되고 user는 변경되지 않는 것을 볼 수 있다.
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
Object.assign(user, permissions1, permissions2);
console.log(user)
Object.assign을 사용하면 가능하다. 가장 첫번째 객체에 나머지 값이 취합된다. 만약 기존의 값이 존재한다면, 내용이 수정변경된다.
이 방법을 활용하면, 객체를 복사하는 것도 가능하다.
let user = {
name: "John",
age: 30
};
let clone = Object.assign({}, user);
clone에는 Object.assign을 통해서 새로운 객체가 형성되었을 것이다. 그러나 이렇게 생성된 객체는 서로 동일하다. 하나의 통장, 두 개의 체크카드인 것이다. 하나의 값을 바꾸면 함께 변경된다. 즉 복사를 한 것이지 복제를 한 것이 아닌 것임을 기억하자.
객체에는 함수형 자료를 담을 수도 있다. 아래와 같이 말이다.
let user = {
name: "John",
age: 30
};
user.sayHi = function() {
alert("안녕하세요!");
};
없던 내용에 sayHi 함수표현식을 추가해주었다. user.sayHi();를 선언하면 안녕하세요가 alert 될 것이다.
간략하게, 객체를 사용하여 개체를 표현하는 방식을 OOP라고 부른다. 올바른 개체를 선택하는 방법, 개체 사이의 상호작용을 나타내는 방법 등에 관한 의사결정이 이러한 설계를 기반으로 생성된다.
user.sayHi = function() {
alert("안녕하세요!");
};
user.sayHi() {
alert("안녕하세요!");
};
let user = {
name: "John",
age: 30
};
user.sayHi = function() {
alert(this.name);
};
user.sayHi()
위의 코드를 실행하면, user객체의 name의 값이 출력된다. 여기서 this는 자기자신의 최상단 user를 가리키기 때문이다. 그러나 this는 화살표형 자료에서는 사용할 수 없다.
let calculator = {
sum() {
return this.a + this.b;
},
mul() {
return this.a * this.b;
},
read() {
this.a = +prompt('첫 번째 값:', 0);
this.b = +prompt('두 번째 값:', 0);
}
};
calculator.read();
alert( calculator.sum() );
alert( calculator.mul() );
calculator.read();를 실행되는 발생되는 내용에 대한 부분이다. 객체메서드가 호출되면, prompt를 통해서 값이 불려와지게 된다. 해당 값이, 해당 객체 내에서 활용될 것인데, alert을 통해 호출된 객체 메소드에 따라서 sum과 mul이 산출되는 방식인 것이다.
let ladder = {
step: 0,
up() {
this.step++;
},
down() {
this.step--;
},
showStep: function() {
alert( this.step );
}
};
ladder.up();
ladder.up();
ladder.down();
ladder.showStep();
ladder.up() 객체 메서드를 실행하면, step: 0이 올라가고, ladder.down() 객체 메서드를 실행하면, step: 0 이 내려오는 방식이다.
이런방식으로 객체 메서드 내에서 this는 활용될 수 있다.
생성자 함수란 함수를 사용해서 새로운 객체를 생성하는 것을 말한다. 만약에 반복되어 객체를 생산해야 되는 문제가 주어진다면, 이것으로 해결이 가능한 것이다.
function User(name) {
this.name = name;
this.isAdmin = false;
}
let user = new User("보라");
alert(user.name);
alert(user.isAdmin);
생성자 함수와 new 연산자를 통해서 함수에 담겨질 인자를 설정한 값에 따라서, user.name은 "보라"가 될 것이다. 그러나 유의할 것이 있다. 생성자 함수에의 return 사용이다.
function BigUser() {
this.name = "원숭이";
return { name: "고릴라" };}
function SmallUser() {
this.name = "원숭이";
return;}
alert( new BigUser().name );
alert( new SmallUser().name );
왜 그럴까? 고릴라의 사례는 return에 내용이 존재하기 때문이다. 반면에 원숭이는 return의 내용이 없어서 객체에서 내용을 산출한다. 우선순위가 return에 있다.
function Accumulator(startingValue) {
this.value = startingValue;
this.read = function() {
this.value += +prompt('더할 값을 입력해주세요.', 0);
};
}
let accumulator = new Accumulator(1);
accumulator.read();
accumulator.read();
alert(accumulator.value);
와... 이걸 어떻게 풀었지?
나머지 매개변수란 간단하다. 매개변수로 설정된 값보다, 인자의 값이 많은 경우이다. 즉 여분의 인자가 발생되었다는 것이다. 역시나 교재가 조금 설명이 부족하다.
Edwin벨로그
이때 매개변수에서 해당 인자를 전부 사용하고 싶을 때는 어떻게 해야 할까. 바로 스프레드 문법으로 사용이 가능하다.
function sumAll(...args) {
let sum = 0;
for (let arg of args) sum += arg;
return sum;
}
alert( sumAll(1, 2, 3) );

또한 사용하고 싶은 매개변수1, 매개변수2, 나머지 매개변수를 기록하는 것도 가능하다. 그러나 나머지 매개변수의 위치는 항상 마지막 이어야 한다.
function showName(firstN, lastN, ...etc) {
console.log(firstN, lastN);
console.log(...etc)
}
showName("edwin", "park", 0, 1234, 4567)

function showName() {
console.log( arguments.length );
console.log( arguments[0] );
console.log( arguments[1] );
}
showName("Bora", "Lee");
showName("Bora");

그러나 기억하자, 설정에 따라서 매개변수가 부족하면, ()에는 없지만, 코드를 함수 내에서 실행할 때 없는번지[1]의 매개변수 요청하면 해당 값은 undefinded이 된다. 그러나 위에서 실행된 부분은 조금독특하다. 그렇지 않은가? 이는 나머지 매개변수라는 개념이 등장하기 전에 사용되었던 arguments 객체를 사용하여, 복수의 인자를 받아서 활용하는 예제이다. 그러나 기억하자. 요구하는 값이 없으면 undefinded이 된다. 뿐만 아니다. arguments 객체는 연속되는 매소드를 사용할 수 없다.
반면에 나머지 매개변수는 연속되는 매소드를 사용할 수 있는데, 아래와 같다.
function showName(name,...num) {
let pointlist = [...num.map((pointplus) => pointplus+10)]
console.log(name)
console.log(pointlist.reduce((current,points) => current+points))
}
showName("Edwin", 1234,5678,9012);
gh
showName("Edwin", 1234,5678,9012) 과 같은 값이 주어진다고 하자. 맨 앞에 있는 것은 매개변수 name에 사용할 부분이고, 뒤에 이어지는 숫자는 과거에 쌓인 포인트들이다. 해당 포인트들에 +10을 해주고, 총합을 계산해보자는 내용이 문제로 주어진다고 하자. 그럴 때 위에서 배운 나머지 매개변수를 사용할 수 있을 것인데? 문제는, arquments로는 해당 내용을 접근할 수 없다는 것이다.

매개변수의 활용은 참으로 다양하다. 혹시 누적된 포인트 가운데 최고 포인트가 몇점인지 살펴볼 수 있을까? 위의 코드에 아래의 내용을 추가해보자.
console.log(Math.max(...num))
결론은 9012가 산출되는 것을 볼 수 있을 것이다. 스프레드 문법은 이렇게 활용이 가능하다. 또한 여로 곳으로 나눠진 배열을 하나의 배열로 취합하는 것도 가능하다.
let numlist1 = [1,2,3,4,5,6,7,8,9]
let numlist2 = [1,2,3,4,5,6,7,8,9]
let numlist3 = [1,2,3,4,5,6,7,8,9]
console.log(...numlist1, ...numlist2, ...numlist3)

그런데 유의할 점이 있다. 하나의 "문자열"을 스프레드 문법으로 기록하면, 하나씩 나뉘어진 배열로 입력된다는 것을 기억하자.
let numlist1 = [1,2,3,4,5,6,7,8,9]
let numlist2 = [1,2,3,4,5,6,7,8,9]
let numlist3 = "Edwin"

또한 스프레트 문법을 사용하여, 이전의 배열을 복사하는 것도 가능하다.
let arr = [1, 2, 3];
let arrCopy = [...arr];
arr.push(4);
console.log(arr)
console.log(arrCopy);

변수arr와 변수arrCopy는 분명 다르다. 그리고 이러한 스프레드는 객체를 복사하는 것도 같다. 복사된 객체에는 원본의 객체에 내용이 추가된다 하더라도, 추가되지 않는 별개의 객체로 형성되어 관리할 수 있다는 말이다.