
컴파일러가 필요 없다!
한 줄 씩 바이트코드로 변환된 후 실행된다.
컴파일러 언어에 비해 속도가 느리고 실행파일을 별도로 생성하지 않는다.


간단하게 말하면, 키워드는 예약어의 소집합이다!
const, goto..
js 시스템에서 먼저 사용하는 단어
int ,class
의미에 따른 룰이 있는 예약어
변수 선언은 런타임 이전 단계에서 실행된다. 이를 호이스팅이라고 표현한다.
🤠 var 선언
선언과 초기화 단계가 암묵적으로 함께 일어난다..
👉 80과 undefined는 가비지 콜렉터에 의해 정리된다. (언제 정리될지는 예측x)
js 엔진이 소스코드를 실행하기 위해 필요한 환경을 제공하고 실행 결과를 관리하는 영역
식별자와 스코프가 이곳에서 관리된다
값 할당은 런타임 시점에 발생한다.
애플리케이션이 할당한 메모리 공간을 주기적으로 검사하여 더 이상 사용되지 않는 메모리를 해제, 메모리 누수를 방지하는 기능
🧐 매니지드 언어와 언매니지드 언어
개발자가 메모리 직접 제어로 할당과 해제가 가능하면 언매니지드 언어, 불가능하면 매니지드 언어라고 한다.
JS는 직접적인 메모리 제어를 허용하지 않는 매니지드 언어다.
사람이 이해할 수 있는 문자 또는 기호를 사용해 값을 생성하는 표기법
코드 블록 등은 세미콜론을 붙이지 않아도 문의 종료를 의미하는 자체 종결성을 가진다.
Number, String, Boolean, undefined, null, symbol
let string_1 = "string";
let string_2 = "string";
string_1===string_2; //true. 둘은 같은 메모리 주소를 가리킨다.
😬 템플릿 리터럴
백틱(``)을 이용한 string 표현법
😏 null과 indefined의 차이
undefined는 "아직 정의되지 않은 값"
null은 "의도적인 부재. 빈 값으로 정의된 값"
겹치지 않는 값을 만들기 위해 사용 (출력x 변환x)
Symbol(‘인자’): 인자는 해당 symbol의 설명description. symbol 영향x
Symbol.for(‘키값’): 레지스트리에서 해당 키값인 심볼 가져옴
Symbol.keyFor(‘심볼명’): 레지스트리에서 해당 심볼의 키값 가져옴
객체, 함수, 배열 등
7장 생략. 쓸 게 없다..
각 case문에서 break가 없어 해당 case를 거친 후 재할당되는 현상
식별자가 붙은 문. break를 사용 가능
foo: {
console.log("foo");
break foo;
}
기존 변수 값의 재할당 ❌
표현식을 에러 없이 평가하기 위해 암묵적 타입 변환 값을 만들어서 한번만 쓰고 버림 ⭕
어떠한 값 + "" = 모두 string으로 변환
let foo=null;
console.log(foo.value) //error
console.log(foo && foo.value) //null로 정상작동
let foo=null;
console.log(foo && foo?.value) //undefined로 정상작동
let foo=null; //or undefined
console.log(foo ?? "foo는 null이므로 대신 이쪽을 출력한다");
원시 타입 값은 변경 불가능하지만. 객체 타입 값은 변경이 가능하다
객체 리터럴에서의 대괄호는 코드 블록이 아니므로 세미콜론을 생략할 수 없다.
const 객체 = {0개 이상의 속성};
delete person.name;
값이 수정될 때마다 해당 메모리를 수정하는 것이 아닌, 새로운 메모리에 할당된다!
상태 변경을 추적하기 쉬움
데이터 신뢰성 보장
let test="test";
test[0]="T";
console.log(test) //test

function add(x,y){ return x+y; } //단독 사용시 함수 선언문
(function add(x,y){return x+y;}) //피연산자로 사용시 함수 리터럴 👉 함수 식별자 없음
🤨 함수 이름과 함수 식별자의 차이
const 함수 식별자 = function 함수 이름() {}; 함수식별자(); //⭕ 함수이름(); //❌
😕 함수 호이스팅을 피해라
함수 호이스팅은 함수를 호출하기 전에 반드시 함수를 선언해야 한다는 규칙을 무시한다.
함수 선언문 대신 함수 표현식을 사용하자!
const add = function(x,y){return x+y;};
const add=new Function('x','y','return x+y');
const add=(x,y)=>{return x+y;};
모든 화살표 함수는 익명 함수이다 (식별자O 이름X)
기존 함수와 달리 객체가 생성될 때 this를 재정의해준다
*prototype 프로퍼티가 없다
자바스크립트의 모든 객체는 일급객체!
값을 가지고 있는 객체!
남은 매개변수는 undefined 처리된다
남은 인수는 함수의 arguments 객체에 프로퍼티로 보관된다.
console.log(arguments)를 하면 볼 수 있다.
암묵적으로 undefined가 return된다
Immediately invoked function expression
(function() {...}());
다른 함수의 인자로써 넘겨진 후 특정 이벤트에 의해 호출되는 함수.
콜백함수를 파라미터로 받아 사용하는 함수.
함수를 인자로 전달받거나 함수를 결과로 반환한다.
👉 고차함수는 콜백함수를 자신의 일부분으로 합성한다.
😀 어디에 사용하나요?
원래 있는 함수를 수정할 때 기존에 사용하던 함수를 곧바로 수정하는 것은 위험!
따라서 콜백함수를 별도로 만들어 인자로 넘기는 방식을 채택한다.eventListener에서 onClick에 함수를 넣어주는 것도 고차함수의 일종이다!
이외에도 배열 고차 함수(filter, map..) 등에서도 사용된다!
let cnt=0;
function 순수함수(cnt){ return cnt+1; } //어떤 상황에서도 cnt+1을 return.
function 비순수함수(){ return cnt+1;} //cnt의 상태에 따라 다른 값을 return.
중첩된 스코프 내에서 같은 이름의 식별자가 있을 때,
둘 중 어떤 것을 사용할 지 JS엔진이 고르는 행위를 말한다.
JS는 정적 스코프!
동적(dynamic) 스코프는 함수가 호출된 곳을 기준으로 결정된다.
정적(lexical) 스코프는 함수가 정의된 곳을 기준으로 결정된다.
var x=1;
function foo(){
var x=10;
boo(); //함수호출 x=10
}
function boo(){ //함수 정의 x=1
console.log(x);
}
foo();
// 동적 스코프에서는 호출된 곳의 로컬스코프를 우선하므로 x=10.
// 정적 스코프에서는 정의된 곳의 로컬스코프를 우선 찾으므로 x=1.
JS는 함수 레벨 스코프!
블록 레벨 스코프는 같은 블록인 것이 중요하고, 👉 let, const
함수 레벨 스코프는 같은 함수인 것이 중요하다. 👉 var
var global="전역";
if(global=="전역"){
var global="지역"
console.log(global); //지역
}
console.log(global);
//블록 레벨 스코프에서는 지역 블록이 끝났으므로 "전역"
//함수 레벨 스코프에서는 아직 같은 함수 내므로 "지역"
🤭 Lexical environment
코드가 어디에서 실행되고 주위에 어떤 코드가 있는가 👉 코드 문맥을 구성하는 환경
🤗 execution context(실행 컨텍스트)
lexical environment를 구현한 것
실행 컨텍스트의 랙시컬 환경을 단방향으로 연결한 것
변수를 찾을 때 로컬 스코프에서 찾을 수 없다면 한 단계 상위 스코프로 올라가 찾는다.
function scope1(){
var x=1;
function scope2(){
var x=10; //찾았으므로 더이상 체인을 타고 위로 올라가지 않는다.
function scope3(){
console.log(x);
}
}
}
var x = 'global'; //외부 var 할당
function foo(){
console.log(x); // undefined 👉 내부 var 호이스팅
var x = 'local'; // 내부 var 할당
}
foo();
console.log(x); //global 👉 외부 var 호이스팅
모든 코드가 전역 변수를 참조하고 변경할 수 있는 상태
var x=1;
var x=2; //가능. 에러 없음!
함수 외부에서 선언한 변수는 코드 블록 내에서 선언시 모두 전역 변수가 된다.
var x=1;
if(1){var x=10;}
console.log(x); //10
var은 변수 선언(메모리 할당)과 초기화(undefined)가 동시에 발생하기 때문에,
변수 호이스팅에 의해 var이 값 할당 전에 함수의 최상단으로 끌어올려진다.
console.log(x); //undefined
var x=1;
var x=1;
console.log(window.x); //1
let x=1;
let x=2; //불가능. 에러발생!
let x=1;
if(1){let x=10;}
console.log(x); //1
let은 선언(메모리 할당)과 초기화(undefined)가 동시에 일어나지 않는다.
따라서 선언(메모리 할당)만 된 시점에서는 호이스팅되어도 변수 사용이 불가능하다.
👉 호이스팅이 안 되는 것처럼 동작!
console.log(x); //에러발생
let x=1;
😐 템퍼럴 데드 존(TDZ)
let a=1; //첫번째 a 호이스팅 if(1){ //템퍼럴 데드 존: 두번째 a 호이스팅 but 값 미정 = 변수사용x 구간 console.log(a); let a=100; //두번째 a 호이스팅 }
let x=1;
console.log(window.x); //undefined

js 엔진 내부 로직이므로 직접 접근이 불가능하다.
모든 객체는 해당 내부 슬롯을 가진다.
._ _ proto __ 를 통해 접근 가능하다.
JS 엔진은 프로퍼티를 생성할 때 프로퍼티의 상태를 나타내는 프로퍼티 어트리뷰트를 기본값으로 자동 정의한다!
const person={
//데이터 프로퍼티
firstName: '홍',
lastName: '길동',
//접근자 프로퍼티
get fullName(){ return firstName+lastName; }
set fullName(name){ [this.firstName, this.lastName]=name.split(' '); }
}
일반 객체의 _ _proto__
키와 값으로 구성된 일반적인 프로퍼티.
Object.defineProperty(객체타입, 프로퍼티명, {프로퍼티 목록})으로 정의 가능하다.
함수 객체의 prototype
자체적으로 값을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 호출되는 접근자 함수로 구성된 프로퍼티
😮 프로토타입
어떤 객체의 부모 객체로 하위 객체에게 자신의 프로퍼티와 메서드를 상속한다!
😍 프로토타입 체인
프로토타입이 단방향 링크드리스트형태로 연결된 상속 구조.
현재 객체에 찾는 프로퍼티나 메소드가 없다면, 프로토타입 체인을 따라 올라가며 프로퍼티나 메서드를 찾는다~
JS에서 제공하는 객체 변경 방지 메서드 목록
객체 확장 금지(프로퍼티 추가 금지) 메서드
프로퍼티 추가, 삭제, 재정의 금지
👉 객체 읽기, 쓰기만 가능!
객체 동결
👉 객체 읽기만 가능!
👉 단, 중첩된 객체에서 내부 객체까지 동결되진 않는다!