es6이전 함수는 구분 없이 다양한 목적으로 사용됨.
각각 명확히 구분되지 않았다. 또한 모두 construct
를 가지고있었음.
=> 실수가 나올 수 있음. 또한 construct
를가지면 prototype
도 생성됨. 비효율적.
ES6부터는 명확히 구분하여 사용한다.
constructor, prototype, arguments
super, arguments
ES6이전 메서드는 그냥 함수를 프로퍼티에 바인딩 한 것.
따라서 위의 문제가 그대로 존재함. 함수로써 호출할수 있고, 생성자가 됨.
ES6이후 메서드는 메서드 축약표현으로 정의한 함수만 메서드라 불림.
const obj ={
x:1,
foo() {return this.x // 메서드축약표현
bar: function(){...} //일반 함수
}
당연히 축약표현 메서드는 인스턴스 생성 불가 그리고 [[HomeObject]]
내부 슬롯을 갖는다(super
키워드 전용)
=> 따라서 축약표현 메서드가 아닌 일반함수는 super
호출 불가.
선언문으로 정의할 수 없고 표현식으로만 가능하다.
const arrow1 = x => x; //매개변수 하나면 괄호생략 가능
const arrow2 = (x,y) => x * y;
const arrow3 = (x,y) => {return x*y} //중괄호로 감싸면 명시적으로 return해주어야만 한다.
const arrow4 = (x,y) => ({x,y}) //...{x,y}. 객체리터럴 반환시 소괄호로 감싸야함.
const IIFEarrow = (name => ({
sayHi(return name);
}))("kim")
IIFEarrow.sayHi() // kim
화살표함수도 일급객체기에 고차함수에 인수로 전달할 수 있다. 일반 함수보다 훨씬 가독성이 좋다.
[1, 2, 3].map(v => v *2); // [2, 4, 6]
일반함수와의 차이점은 위에서도 설명했지만 이렇다.
this, arguments, super, new.target
바인딩 갖지 않음.일반함수와 구분되는(모양 말고) 가장 큰 특징이 this
다.
this
는 함수가 어떻게 호출되었는지에 따라 바인딩된다.
=> 콜백함수로 전달된 함수는 일반함수로서 호출하기에 전역 객체를 가리킨다.
이는 this
처리를 위한 갖가지 방법을 고안해냈다. 이전this파트에서 설명함.
화살표함수는 이를 단박에 해결해줌.
상위 스코프(컨텍스트)의 this를 그대로 참조함. 이를lexical this라고 함.
마치 렉시컬 스코프처럼 화살표 함수가 정의된 위치에 의해 결정된다는 걸 의미함.
참고로 화살표 함수가 중첩되어있어도 계속해서 스코프를 타고 this를 찾는다.
이 부분은 살짝 헷갈렸다.
const counter = {
num: 1,
increase:() => ++this.num
}
counter.increase() // NaN (this가 전역객체를 가리킴)
상위 스코프의 this
를 참조한다면, 객체의 this
를 참조하게될줄 알았는데
객체는 스코프가 아니다.
이 부분을 헷갈리지 말자!
class Person{
name = "lee";
sayHi = () => console.log(`hi ${this.name}`);
}
const person = new Person();
person.sayHi() // hi lee
위와 어떻게 다른 것일까?
객체에 메서드로 추가한 것과 어떻게 다른 것일까???
=> 클래스 필드는 인스턴스의 프로퍼티다. 따라서 this
는 생성될 인스턴스다.
다만 이렇게 하면 인스턴스만의 메서드가 되기에 주의하자.
super
바인딩이 없으니 이또한 상위에서 가져온다.
class Rabbit extends Animal {
stop() {
setTimeout(() => super.stop(), 1000); // 1초 후에 부모 stop을 호출합니다.
}
}
// Unexpected super
setTimeout(function() { super.stop() }, 1000);
1번은 stop()
메서드의 super
를 가져와서 사용하지만
2번은 일반함수로서 호출되었기에 super
가 없다!
=> 콜백함수에서 super
를 사용하려면 화살표 함수가 필요하군
이 또한 상위스코프의 arguments
를 참조...알겠지?
(function(){
const foo = () => console.log(arguments); //1,2만 들어온다
foo(3,4);
}(1,2))
function foo (...rest){
console.log(rest); //[1,2,3,4,5] 배열로 받는다.
}
foo(1,2,3,4,5)
매개변수의 개수를 확정할 수 없는 가변인자 함수를 만들때 유용하다.
이전에 한번 설명했던 것 같은데...? 맨마지막 부분을 보면 있다.
내가 애용하는 문법이다. 값이 안들어왔을때 예외처리 해줄수있어서 편하다.
const sum = (x,y) => x+y;
sum(1) //NaN. 전달되지 않은 매개변수는 undefined다
const sum = (x = 0, y = 0) => x+y;
sum(1) // 1
배열이란 여러개값을 순차적으로 나열한 자료구조다. 객체와 더불어 사용빈도가 매우높으니 잘 배워보자.
const arr = ["kim", "apple", "banana"];
kim, apple, banana
는 모두 요소고, 인덱스를 0부터가진다.
또한 길이를 가지기에 for문으로 순차적 순회가 가능하다.
참고로 배열은 객체다.
본래의 자료구조에서 말하는 배열은 동일한 크기의 메모리 공간이 빈틈없이 연속적으로 나열되어있는 자료구조다.
이러한 배열을 밀집 배열이라 한다.
크기가 동일하고 빈틈이 없다면 임의의 요소에 접근할때 이렇게 할 수 있을 것이다
검색 대상의 메모리 주소 = 배열 시작 메모리 주소 + 인덱스 * 요소 바이트 수
=> 마치 offset
과 같다.
하지만 js의 배열은 요소로 함수, 객체, 문자열..등 다양한 값을 가진다. 또한 크기도 다르다.
이러한 배열을 희소 배열이라 한다.
이처럼 js의 배열은 일반적인 배열이 아니다. 배열의 동작을 흉내낸 특수한 객체다
실제로getOwnPropertyDescriptors
로 열어보면 인덱스를 키로 가지며length
를 프로퍼티로 갖는 특수객체란 걸 알 수 있다.
모든 값은 객체의 프로퍼티가 될 수 있기에, 배열의 요소에도 모든 값이 올 수 있다.
참고로 인덱스기반 검색할땐 배열이 객체보다 약 2배정도 빠르다.
명시적으로 길이를 할당할 수 있다.
const arr = [1,2,3]
arr.length = 1 //[1]
arr.length = 3 //[1, empty x 2]. 실제로 길이는 늘어나지 않는다.
이처럼 중간에 구멍나는 배열이 희소배열이지만..이렇게 쓰는건 권장하지 않는다.
같은 타입 요소를 최대한 연속적으로 넣는 게 핵심이다.
화살표함수에 대해서 진득히 알아갈 수 있었다.
특히 상위 스코프의 this를 참조한다는 사실을 명확히 알 수 있었고 super도 마찬가지!
희소배열과 밀집배열의 차이도 알 수 있었다.