나를 위한 정리
https://poiemaweb.com/ 이 사이트를 이용해 궁금한 것이 생길 때 마다 찾아서 읽어보긴 했지만 자바스크립트를 주언어로 사용하는 사람이 책 한권도 제대로 읽어보지 않은건 말이 안된다고 생각했다. 그래서 책 하나를 지정해서 완독하고 시간이 날 때 마다 회독하기로 결심했다.
인터넷에서 복붙한거 아니고 내가 직접 읽고 직접 정리했다. ^.^!
1바이트는 8개의 비트로 구성되어 있다.
비트는 메모리 조각이다.
숫자형 데이터는 64비트의 공간을 확보한다.
반면 문자열은 특별히 정해진 규격이 없음 (영어는 1바이트, 한글은 2바이트 등...)
궁금증 : 왜 문자열로 전환했댜 다시 json객체로 바꾸면 깊은복사가 되는걸까? 무슨 원리로 ?
문자열로 전환 후 다시 JSON 객체로 바꾸는 것이 깊은 복사를 수행하는 이유는 JSON.stringify()와 JSON.parse() 함수의 동작 원리 때문입니다.
JSON.stringify() 함수는 JavaScript 객체를 JSON 형식의 문자열로 변환합니다. 이때, 객체의 모든 속성과 값을 문자열로 변환하여 새로운 문자열을 생성합니다. 즉, 원본 객체와는 별개로 새로운 문자열을 생성하므로 깊은 복사가 이루어집니다.
JSON.parse() 함수는 JSON 형식의 문자열을 JavaScript 객체로 변환합니다. 이때, JSON 형식의 문자열을 분석하여 새로운 객체를 생성합니다. 따라서, 새로운 객체가 원본 객체와는 메모리 위치가 다르므로 깊은 복사가 이루어집니다.
문자열은 특별히 정해진 데이터 규격이 없다.
만약 미리 미리 확보된 공간 내에서만 데이터 변환을 할 수 있다면 변환한 데이터를 다시 저장하기 위해서는 확보된 공간을 변환된 데이터 크기에 맞게 늘리는 작업이 선행되어야 한다.
만약 해당 공간이 메모리 중간에 있는 상황이라면 ?
=> 해당 공간보다 뒤에 저장된 데이터들을 전부 뒤로 옮기고 이동시킨 주소를 각 식별자에 다시 연결하는 작업을 해야한다.
결국 효율적으로 문자열 데이터의 변환을 처리하려면 변수와 데이터를 별도에 공간에 나누어 저장해야 하는 것이다.
let a = 'abc'
a = a + 'def'
let b = 5 //5가 있으면 주소를 찾아 할당, 없으면 데이터 공간을 만들어 저장
let c = 5 //주소가 있으면 만들어진 주소를 찾아 할당
b = 7
변수 a 에 문자열 'abc'를 할당했다가 뒤에 다른 문자열을 추가하면 기존 abc가 다른 문자열로 바뀌는 것이 아니다. 새로운 문자열 완성본을 만들어 그 주소를 a에 새로 저장한다.
undefined는 사용자가 명시적으로 지정할 수도 있지만 값이 존재하지 않을 때 자바스크립트 엔진이 자동으로 부여하는 경우도 있다.
'비어있는 요소' 와 'undefined를 할당한 요소' 는 출력 결과부터 다르다.
비어있는 요소는 순회와 관련된 많은 배열 메서드들의 순회 대상에 제외된다.
사용자가 지정한 undefined는 비록 비어있음을 의미하긴 하지만 하나의 값으로 동작한다.
이때의 프로퍼티나 배열의 요소는 고유의 키값이 실존하게 되고, 따라서 순회 대상이 될 수 있다.
한편 사용자가 아무것도 하지 않은 채로 접근했을 때 자바스크립트 엔진이 하는 수 없이 반환해주는 undefined는 해당 프로퍼티 내지 배열의 키값 자체가 존재하지 않음을 의미한다.
결론 : 존재하지 않는 경우에는 명시적으로 null 을 쓰자.
실행할 코드에 제공할 환경 정보들을 모아놓은 객체
실행컨텍스트를 생성할 때는 V.E와 L.E , ThisBiding 세 가지 정보를 수집한다.
var a = 1
function outer (){
funcion inner (){
console.log(a)
var a = 3
}
inner()
console.log(a)
}
outer ()
console.log(a)
이렇게 실행컨텍스트가 활성될 때 자바스크립트 엔진은 해당 컨텍스트에 관련된 코드들을 실행하는 데 필요한 환경 정보들을 수집해서 실행 컨텍스트 객체에 저장한다.
여기에 담기는 정보들은
이다.
현재 컨텍스트와 관련된 코드의 식별자 정보들이 저장된다.
컨텍스트를 구성하는 함수에 지정된 매개변수 식별자, 선언한 함수, 등이 저장된다.
어떤 식별자들만 있는지 관심이 있고 어떤 값이 할당될 것인지는 관심이 없다.
스코프란 식별자에 대한 유효범위 이다.
=> 유효범위라고 하니 말이 어려워 보이는데, 그냥 {} 라고 생각하면 될듯!
ES5는 전역 공간을 제외하면 오직 함수에서만 스코프가 생성된다. [함수레벨]
현재 호출된 함수가 선언될 당시의 L.E를 참조한다. 과거 시점인 '선언될 당시'에 주목.
예를 들어 A함수 내부에서 B함수를 선언하고 다시 B함수 내부에서 C를 선언한 경우,
함수 C의 outerEnvirementReference는 함수 B의 L.E를 참조한다.
B는 A의 L.E를 참조하고.. 이처럼 연결리스트의 형태를 띈다.
이런 구조적 특서상 여러 스코프에서 동일한 식별자를 선언한 경우,
무조건 스코프 체인 상에서 가장 먼저 발견된 식별자에만 접근이 가능하다.
+) 중간에 여담이지만, 제가 글을 작성하면서 느낀 것은 그 어떤 블로그글 보다 책의 설명이 훨-씬!! 더 좋다는 것입니다. 실행컨텍스트는 제게 너무 어려운 개념이었고 블로그 글과 문서를 정말 많이 찾아봤는데 코어 자바스크립트 만큼 쉬운 말로 풀어서 설명해주는 블로그가 없더라구요.
그래서 혹시 정보 검색 목적으로 타고와서 이 글을 보시는 분들은 꼭 코어 자바스크립트 책을 회독하시는 것을 추천드립니다.
자바스크립트에서 this는 기본적으로 실행 컨텍스트가 생성될 때 함께 결정된다.
실행 컨텍스트는 함수다 호출될 때 생성된다. => this는 호출될 때 결정된다.
함수는 그 자체로 독립적인 기능을 수행하는 반면 메소드는 자신이 호출한 대상 객체에 관한 동작을 수행한다.
a.
let testFunction(){
console.log('test')
}
testFunction() //함수 호출
let obj ={
method : testFunction
}
obj.method() //메소드로서 호출
이 경우 this는 지정되지 않는다. this는 호출한 주체에 대한 정보가 담긴다. 그래서 함수로서 호출 하는 것은 호출 주체를 명시하지 않고 개발자가 코드에 직접 관여해 실행한 것 이기 때문에 호출 주체 정보를 할 수 없다.
실행컨텍스트 활성화 당시 this가 지정되지 않은 경우 this는 전역컨텍스트를 바라보기 때문에 자동으로 전역컨텍스트가 설정된다.
ES6 에서 화살표 함수는 실행컨텍스트를 생성할 때 this 바인딩 과정 자체가 빠지게 되어 상위 스코프의 this를 그대로 활용할 수 있게 됐다.
클로저란 어떤 함수 A에서 선언한 변수a를 참조하는 내부함수 B를 외부로 전달할 경우 A의 실행 컨텍스트가 종료된 이후에도 변수 a가 사라지지 않는 현상을 말합니다.
■ 함수를 선언할 때 만들어지는 유효범위가 사라진 후에도 호출할 수 있는 함수 — 존 레식, 《자바스크립트 닌자 비급》, 인사이트(p116)
■ 이미 생명 주기가 끝난 외부 함수의 변수를 참조하는 함수 — 송형주 고현준, 《인사이드 자바스크립트》, 한빛미디어(p157)
■ 자신이 생성될 때의 스코프에서 알 수 있었던 변수들 중 언젠가 자신이 실행될 때 사용할 변수들만을 기억하여 유지시키는 함수 — 유인동, 《함수형 자바스크립트 프로그래밍》, 인사이트(p31)
자바스크립트는 함수에 자동으로 객체인 prototype 프로퍼티를 생성해 놓는데, 해당 함수를 생성자 함수로서 사용할 경우 (new 연산자로 호출할 경우) 그로부터 생성된 인스턴스에는 숨겨진 프로퍼티인 proto가 자동으로 생성된다.
이 프로퍼티는 생성자 함수의 prototype를 참조한다.
생성자 함수 prototype 에 어떤 메서드나 프로퍼티가 있다면 인스턴스에서도 마치 자신의 것처럼 해당 메서드나 프로퍼티에 접근할 수 있게 된다.
const Person = function(name){
this._name = name
}
const instance = new Person('seorim')
Person.prototype.getName = function(){
return this._name
}
instance.__proto__.getName() //undefined
//이렇게 호출하게 되면 this의 binding 대상이 잘못되었다는 것을 알 수 있다.
어떤 함수를 메소드로서 호출할 때는 메소드명 바로 앞의 객체가 곧 this가 된다.
그러니까 이 함수 내부에서의 this는 Person이 아닌, person.proto라는 객체가 된다.