프로토타입 체인은 프로토타입이 단방향 링크드 리스트 형태로 연결되어 있는 상속 구조를 말한다. 객체의 프로퍼티나 메서드에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티 또는 메서드가 없다면 프로토타입 체인을 따라 프로토타입의 프로퍼티나 메서드를 차례대로 검색한다.
(프로토타입은 유전자다. 부모에 있는 요소를 가져다가 자식도 사용할 수 있다.)
function Machine() {
this.q = 'hello'
}
Machine.prototype.name = 'kim'
var ets = new Machine()
ets.name ===> 'kim'
}
ets가 name을 가지고 있지 않다면 ets 부모인 Machine의 유전자에서 찾아본다.
object에서 자료를 뽑을 때 일어나는 일이다.
- 직접 자료를 가지고 있으면 그것을 출력
- 없으면 부모 유전자까지 찾아본다.
- 또 없으면 부모의 부모 유전자까지 찾아본다.
=> 계속해서 찾아나감
var arr = [4,1,5]
arr.sort() ===> [1,4,5]
var arr2 = new Array(4,2,1);
왜 arr에 sort()를 붙일 수 있는가??
부모 유전자인 Array에 기록되어 있기 때문에
Array.prototype.sort()
Array.prototype.myFunction = function(){}
arr.myFunction()
attribute는 html 문서에서 elements에 추가적인 정보를 넣을 때 사용되는 요소이고 property는 자바스크립트 스크립트 객체에 저장되는 데이터이다. 데이터 프로퍼티 또는 접근자 프로퍼티의 프로퍼티 어트리뷰트와의 차이는 전자는 키와 값으로 구성된 일반적인 객체의 데이터 라고 볼 수 있고 프로퍼티 어트리뷰트는 해당 데이터의 상태를 나타내는 속성이다..
Object.defineProperty() 메서드를 사용하면 개별적인 프로퍼티에 대한 어트리뷰트를 정의할 수 있다. 해당 메서드의 매개변수로는 객체, 프로퍼티 이름, 프로퍼티 어트리뷰트 객체가 들어간다. 설정할 수 있는 속성으로는 데이터 프로퍼티의 경우 value, enumerable, writable, configurable이 있다. 접근자 프로퍼티의 경우 get과 set 그리고 enumerable과 configurable 속성을 설정할 수 있는데 만약 생략할 경우 기본값으로 undefined나 false가 들어간다.
먼저 javascript의 내부슬롯에 대해서 알아보아야 한다. 내부슬롯이란 자바스크립트 엔진의 구현 알고리즘을 설명하기 위해 ECMAScript 사양에서 사용하는 의사 프로퍼티 (pseudo property)와 의사 메서드 (pseudo method)이다. ECMAScript 사양에 등장하는 이중 대괄호로 감싼 이름들이 내부슬롯과 내부 메서드이다. 즉 내부슬롯과 내부 메서드는 자바스크립트 엔진의 내부 로직이므로 원칙적으로 자바스크립트 내부 슬롯과 내부 메서드에 집적적으로 접근하거나 호출할 수 있는 방법을 제공하지 않지만 일부의 경우에 한하여 간접적으로 접근할 수 있는 수단을 제공한다. 예를들어 [[prototype]]에 접근하려면 __proto__를 통해 간접적으로 접근할 수 있다.
상속 구조를 변경하는 것이 성능에 미치는 영향은 미묘하고 광범위하며, obj.proto = ... 문에 소요된 시간에 국한되지 않고 [[Prototype]]이 변경된 객체에 접근할 수 있는 모든 코드로 확장될 수 있다. (Shapes and Inline Caches)
대신 Object.create()를 사용하여 원하는 [[Prototype]]으로 새 객체를 만들어야 한다. 또는 ES6를 지원할 경우 setPrototypeOf를 사용해서 객체의 프로토타입을 정의해야 한다. 만약 접근을 한다면 getPrototypeOf를 사용할 수 있다.
new 연산자는 사용자 정의 객체 타입 또는 내장 객체 타입의 인스턴스를 생성한다. 사용자 정의 객체를 생성하기 위해서는 두 단계가 필요하다. 함수를 작성하여 객체 타입을 정의하고 new 연산자로 객체의 인스턴스를 생성하는 것이다. (객체가 메모리에 할당되어 실제 사용될 때 인스턴스라고 함) 생성자 함수에 의해 리턴된 객체는 전체 new 호출 결과과 된다. 즉 new 연산자와 함께 호출하면 해당 함수는 생성자 함수로서 동작하기 때문이다. 만약 new 연산자와 함께 생성자 함수를 호출하지 않으면 생성자 함수가 아니라 일반 함수로 동작한다.
생성자 함수는 인스턴스를 생성하고 초기화하고 반환한다. 처음으로 암묵적으로 빈 객체를 생성한 후 this에 바인딩한다. (바인딩이란 식별자와 값을 연결하는 과정을 의미한다) 이후 this에 바인딩 되어있는 인스턴스를 초기화한다. 모든 처리가 끝나면 완성된 인스턴스와 바인딩된 this가 암묵적으로 반환된다. (일반적으로 생성자 함수 내부에서 returnㅁ누을 반드시 생략해야한다. this가 아닌 값을 반환할 수 있기 때문이다)
this는 객체 자신의 프로퍼티나 메서드를 참조하기 위한 자기참조변수이다. this가 가리키는 값, 즉 this 바인딩은 함수 호출 방식에 따라 동적으로 결정되는데 생성자 함수로서의 this 호출은 생성자 함수가 생성할 인스턴스를 가리킨다.
바인딩 : 식별자와 값을 연결하는 과정을 의미
먼저 상황에 따라 생성자 함수에 의한 방식을 사용할 수 있다. 복잡한 객체를 생성할때, 프로퍼티 구조가 동일한 개체 여러 개를 생성해야할 때 사용할 수 있다. 허나 성능 면에서는 객체의 솏어과 메서드를 직접 지정할 수 있는 객체리터럴이 더 빠르기 때문에 상황에 알맞게 객체를 생성하는 방법을 도입해야 한다.
new.target은 생성자 함수가 new 연산자 없이 호출되는 것을 방지하기 위해 사용한다. new 연산자로 인스턴스화된 생성자 및 함수에서 new.target은 생성자 또는 함수 참조를 반환하고 일반 함수 호출에서는 undefined를 반환한다. 여기서 new는 예약어이다.
입려과 출력에만 상관하는 작은 함수들을 엮어서 프로그램을 만드는 기법. 즉 읽기가 더 쉽고 함수가 무슨 역할을 하는 지 더 이해하기 편한것
함수형 프로그래밍(functional programming)은 함수를 자료형으로 취급하고, 함수의 조합을 통해 프로그램을 작성하는 프로그래밍 패러다임이다. 함수형 프로그래밍은 순수 함수(pure function)를 기반으로 하기 때문에, 상태 변경이나 부작용이 발생하지 않는다. 따라서 함수형 프로그래밍은 모듈성이 높고, 테스트하기 쉽고, 재사용하기 쉽다.
함수를 객체와 동일하게 사용할 수 있기 때문인데 그 이유는 객체의 내부 슬롯과 내부 메서드를 포함하고 있기 때문이다. 이로인해 함수의 매개변수에 전달할 수 있으며, 함수의 반환값으로도 사용될 수 도 있기 대문에 일급 객체이다.
일급 객체는 변수에 할당할 수 있고, 다른 함수의 인자로 전달할 수 있고 반환값으로도 사용될 수 있는 객체로 함수 뿐만 아니라 객체, 배열, 문자열도 포함한다. 일급 함수는 함수의 이름을 변수에 할당할 수 있고 다른 함수의 인자로 전달할 수 있고 반환값으로 사용될 수 있는 함수이다. 고차함수는 다른 함수를 인자로 전달하거나 반환값으로 사용할 수 있는 함수이다.
일급 객체는 변수에 할당할 수 있고, 다른 함수의 인자로 전달할 수 있고 반환값으로도 사용될 수 있는 객체로 함수 뿐만 아니라 객체, 배열, 문자열도 포함한다.
함수의 arguments 객체는 매개변수 개수를 확정할 수 없는 가변 인자 함수를 구현할 때 사용된다. arguments 객체는 배열 형태로 인자 정보를 담고 있지만 실제 배열이 아닌 유사 배열 객체이므로 Function.prototype.call이나 Function.prototype.apply를 사용해서 간접 호출해야 한다.
call() 메소드는 주어진 this 값 및 각각 전달된 인수와 함께 함수를 호출합니다.
call()은 이미 할당되어있는 다른 객체의 함수/메소드를 호출하는 해당 객체에 재할당할때 사용됩니다. this는 현재 객체(호출하는 객체)를 참조합니다.
apply() 메서드는 주어진 this 값과 배열 (또는 유사 배열 객체) 로 제공되는 arguments 로 함수를 호출합니다.
this 객체를 할당할 수 있습니다. this 는 현재 객체, 호출하는 객체를 참조합니다. apply 를 사용해, 새로운 객체마다 메소드를 재작성할 필요없이 한 번만 작성해 다른 객체에 상속시킬 수 있습니다.
call()은 인수 목록을, 반면에 apply()는 인수 배열 하나를 받는다는 점이 중요한 차이점입니다.
func.call(thisArg[, arg1[, arg2[, ...]]])
func.apply(thisArg, [argsArray]);