커링은 하나 이상의 매개변수를 받는 함수를 하나의 매개변수만 받는 함수로 바꿔가는 과정이다. 커링을 이용하면 재사용성이 높으면서 보다 명확하고 간결한 코드를 작성할 수 있다.
function sum (n, m) {
return n + m;
};
console.log(sum(1, 2))
// 3
커링 적용
function curryedSum (n) {
return function (m) {
return n + m;
}
};
const result = curryedSum(1)
console.log(result(2))
// 3
const prefixCreator = function (longNumber, num) {
return longNumber.slice(0, num);
};
const prefix = prefixCreator('1234567890', 2);
console.log(prefix);
// '12'
커링 적용
const curryedPrefixCreator = function (longNumber) {
return function (num) {
return longNumber.slice(0, num);
}
};
const prefix = curryedPrefixCreator('1234567890');
const prefixes = [prefix(2), prefix(3), prefix(4)];
console.log(prefixes);
// ["12", "123", "1234"]
function htmlTagMaker (tag) {
let startTag = '<' + tag + '>';
let endTag = '<' + tag + '>';
return function (content) {
return startTag + content + endTag;
}
}
const divMaker = htmlTagMaker('div');
const h1Maker = htmlTagMaker('h1');
console.log(divMaker('hey'));
// <div>hey</div>
console.log(h1Maker('Hello'));
// <h1>Hello</h1>
[ Deeply Understand Currying in 7 Minutes | Yazeed Bzadough ]
[ A Beginner’s Guide to Currying in Functional JavaScript | M. David Green ]
this
는 모든 함수 scope 내에서 자동으로 생성되는 식별자로, 실행중인 코드가 속해있는 객체다. 함수가 실행되는 동안 - 메소드 호출 시에 해당 메소드를 갖고 있는 객체에 접근할 수 있다. 동적으로 객체를 생성하는 경우(예를 들면 생성자를 사용하는 경우)에 유용하다.
this
: 전역 객체console.log(this);
// Window
this
: 전역 객체let fn = function () {
console.log(this);
}
fn();
// Window
엄격 모드에서는 위와 같이 this
를 사용했을 때, 전역 객체 대신 undefined
를 반환한다.
this
: 메소드 실행 시 this
가 위치한 객체const pen = {
ink: 10,
usePen: function() {
this.ink = this.ink - 1;
}
};
console.log(pen.ink);
// 10
pen.usePen();
// 이 때 this는 pen
console.log(pen.ink);
// 9
const marker = {
ink: 200,
useMarker: pen.usePen // pen에 정의된 메소드를 가져옴
}
console.log(marker.ink);
// 200
marker.useMarker();
// 이 때 this는 pen이 아닌 marker
console.log(marker.ink);
// 199
어떤 객체의 속성으로 접근해서 사용하는 함수를 메소드(method)라고 부른다. function
키워드를 통해 정의된 함수 내부의 this
키워드가 실제로 무엇을 가리킬 것인가는, 메소드가 어떻게 정의되는가에 의해 결정되는 것이 아니라 메소드가 어떻게 사용되는가에 의해 결정된다.
this
: new 로 생성된 객체function Cat(name){
this.name = name;
}
const tuxedo = new Cat('tux');
console.log(tuxedo.name);
// tux
const ginger = new Cat('pepe');
console.log(ginger.name)
// pepe
.bind()
Invocation this
: 메소드의 인수로 넘긴 값function greet() {
console.log(this.name + ', 오늘도 좋은 하루 보내!');
}
const whiteCat = {name: '만두'};
const greetForDumpling = greet.bind(whiteCat);
greetForDumpling();
// 만두, 오늘도 좋은 하루 보내!
.call()
or .apply()
Invocation this
: 첫번째 전달인자function greet() {
console.log(this.name + ', 오늘도 좋은 하루 보내!');
}
const grayCat = {name: '먼지'};
const whiteCat = {name: '만두'};
greet.call(grayCat);
// 먼지, 오늘도 좋은 하루 보내!
greet.apply(whiteCat);
// 만두, 오늘도 좋은 하루 보내!
재귀함수는 '스스로를 호출하는' 함수로, 세 가지 요소로 구성된다.
1. A Termination Condition
만약 '이 일이 일어난다면' 함수를 동작시키지 않을 조건. 원하지 않는 매개변수를 거르는 역할이다.
2. A Base Case
Termination Condition과 비슷하게 함수를 멈추게 한다. 하지만 Base Case는 재귀 함수의 종착지이다. 여기에서 리턴된 값을 시작으로 Call Stack에 쌓인 명령들이 실행된다. Base Case는 동시에 Termination Condition 이 되기도 한다.
3. The Recursion
함수 스스로를 다시 호출한다. 여기서 매개변수를 변경할 수도 있다.
function factorial(num) {
// A Termination Condition : Factorial 은 음수로 계산할 수 없기에, 매개변수가 음수일 경우 함수를 동작시키지 않는다.
if (num < 0) {
return;
}
// A Base Case : 함수를 반복 실행해서 num이 1이 되면 그로부터 출발하여 call stack에 쌓인 순서대로 일이 처리된다.
if (num === 1){
return 1;
}
// The Recursion : 함수 스스로를 다시 호출한다.
return num * factorial(num - 1);
}
아래와 같은 결과가 나오도록 재귀 함수를 작성하라.
console.log(replicate(3, 5)) // [5, 5, 5]
console.log(replicate(1, 69)) // [69]
console.log(replicate(-2, 6)) // []
function replicate(repeat, num, arr = []) {
if (repeat <= 0) {
return arr;
}
arr.push(num);
return replicate(repeat - 1, num, arr);
}
객체가 특정 프로퍼티를 가지고 있는지를 나타내는 불리언 값을 반환한다. 모든 객체는 hasOwnProperty()를 상속하는 Object의 자식이다. 이 메소드는 객체가 특정 프로퍼티를 자기만의 직접적인 프로퍼티로서 소유하고 있는지를 판단하는데 사용된다.
[ Object.prototype.hasOwnProperty() | MDN ]
let obj = {
prop: 'exists'
};
function changeObj() {
delete obj.prop;
}
obj.hasOwnProperty('prop'); // returns true
changeObj();
obj.hasOwnProperty('prop'); // returns false
hasOwnProperty()를 이용해 객체가 비었는지 확인하는 법
for(var prop in obj) {
if(!obj.hasOwnProperty(prop)) //
// ...
}
개체 고유 속성의 이름을 배열로 반환한다. 배열 순서는 일반 반복문을 사용할 때와 같다. Object.keys()는 object에서 직접 검색된 열거형 속성들에 대응하는 문자열을 요소로 갖는 배열을 반환한다. 반환된 요소는 객체의 요소 전체를 수동으로 반복(loop)하며 주어지는 순서와 동일하다.
오래된 버전의 브라우저에서는 동작하지 않으므로 확인이 필요하다.
[ Object.keys() | MDN ]
const object1 = {
a: 'somestring',
b: 42,
c: false
};
console.log(Object.keys(object1));
// expected output: Array ["a", "b", "c"]
keys()를 이용해 객체가 비었는지 확인하는 법
if(Object.keys(obj).length === 0) // obj is empty
새로 공부한 개념과 방법을 기존에 작성한 코드에 적용하며 여러 번 다시 짜 보았다. 그 과정을 정리했다.
코드를 작성한 목적 :
일정한 범위의 숫자들을 문자열로 바꾼 후 배열 안에 넣어 사용할 수 있도록 준비
const obj = {
numbers: (function () {
let result = ['1', '2', '3'];
for (let prefix = 10; prefix <= 13; prefix++) {
result.push(String(prefix));
}
for (let prefix = 30; prefix <= 33; prefix++) {
result.push(String(prefix));
}
return result;
})()
};
console.log(obj.numbers); // 최종적으로 만들어내고자 하는 결과
// ["1", "2", "3", "10", "11", "12", "13", "30", "31", "32", "33"]
function plusNumbers (startNum, endNum) {
let result = [String(startNum)];
while (startNum !== endNum) {
startNum = startNum + 1;
result.push(String(startNum));
}
return result;
};
function plusNumbers (startNum, endNum, result = []) {
if(startNum >= endNum + 1) {
return result;
}
result.push(String(startNum));
return plusNumbers(startNum + 1, endNum, result);
};
const obj = {
numbers: [plusNumbers(1, 5), plusNumbers(10, 15), plusNumbers(30, 35)]
.reduce(function (acc, val) {
return acc.concat(val)
})
};
console.log(obj.numbers); // 최종적으로 만들어내고자 하는 결과
// ["1", "2", "3", "10", "11", "12", "13", "30", "31", "32", "33"]