자바스크립트 기초 1

공부는 혼자하는 거·2021년 5월 1일
0

프론트엔드 쪽으로 가기로 마음을 먹었으니 JavaScript를 확실히 파보려 한다. 복습하는 겸 다시 차근차근 살펴보기로 하자.

인터프리터 언어

자바스크립트는 인터프리터 언어이다. 한줄한줄씩 읽고 바로 실행시켜나가며 진행해나간다. 자바스크립트를 위에서 작성하면 순서대로 읽기 때문에 브라우저가 자바스크립트에서 손댄 html 태그 중 나중에 나온 html 태그를 찾지 못해서 버그를 일으키는 경우가 있다. function은 그런 경우를 방지하지만 안전상 <script>는 항상 밑에! document.ready()도 이러한 경우를 방지하기 위해, html 랜더링 다 된 후에 실행시키는 메서드다.

타입

자바스크립트는 원시타입과 참조타입이 있다. 원시타입은 숫자(Number), 문자열(String), 논리형(Boolean), Null, Undefined이고, 참조타입은 함수(Fucntion), 배열(Array), 객체(Object)이다.

원시타입은 해당 값을 복사하여 서로 독립된 값을 가지며(불변성), 참조타입은 해당 주소를 참조하여 메모리에 저장된 것을 갖고와 참조한 값이 바뀌면 자동으로 바뀐다. 이 둘의 차이점은 확실히 알아야 된다.

메모리 모델

자바스크립트를 처음 살펴보다 보면 JAVA와 가장 눈에 띄게 차이나는 점은 변수에 특정한 Type를 정하는 예약어가 없이 var, let, const로 퉁 친다는 것이다. (typescript는 javascript의 확장판으로 데이터 타입이 있다.) 그래서 처음 보면 이게 변수의 byte가 어떻게 배정되는지 감도 안 잡힌다. 4byte인지 8byte인지..

자바스크립트의 느슨한 타입을 설명하자면 대략 이렇다.
https://developer.mozilla.org/ko/docs/Web/JavaScript/Data_structures
https://m.blog.naver.com/bkcaller/221662231924

자바스크립트는 Number 형일 경우 무적권 8byte씩 데이터 영역을 잡아넣는다. 그래서 long => int 처럼 C나 자바 같이 엄격한 타입을 요구하는 언어와 달리 형변환 데이터 손실 이딴 거 신경쓰지 않아도 된다. 하지만 이러면 메모리 낭비가 너무 심하지 않을까? 자바스크립트는 아래와 같은 메모리 구조를 통해, 이러한 낭비를 최소화시켰다.

let a = 'abc'; 

자바와 달리 원시타입변수도 바로 저장되는 것이 아닌 참조값 저장영역과 실제 value 저장영역이 분리되어있다. 자바스크립트는 Number 형일 경우 8byte씩 데이터 영역을 집어넣지만, 문자열 경우는 정해진 규격이 없다. 문자열의 byte는 가변적일 수 있기 때문이다. 만약 문자열 abc에 ed가 추가된다면, 자바스크립트는 abcde라는 새로운 문자열을 만들어서 별도의 데이터 영역에 저장하고 그 데이터 영역을 변수영역의 참조주소로 연결한다. 기존 5004 영역은 쓰는 애가 없으면 가비지 컬렉터가 알아서 처리할 것이다.

cpu -> ram -> hdd or sdd

조금 더 알아보자. 자바스크립트 언어는 무적권 4 바이트씩 변수의 주소를 배정하며, 작동원리는 대략 이렇다. ram의 남는 공간을 힙(heap / CPU가 엄격하게 관리하지 않는 컴퓨터 메모리 영역)이라 설정하고, 변수와 데이터를 선언하면, OS가 힙의 공간 랜덤한 데에 데이터(value)를 할당하고, ram은 무적권 4바이트 공간에다 그 힙 주소지를 저장한다. (래퍼런스를 넘겨준다) 데이터의 크기는 runtime 시 동적으로 결정된다. 사실 이 부분은 나도 자세히 기억이 안 나서 한 번 더 공부해봐야겠다. 암튼 크기가 정해져있지 않고 모든 변수가 참조로 기억된다.

ram(4byte) -> heap (5000번지) *5000 <-

이 방식의 장점은 3이라는 숫자가 담긴 변수를 500개를 선언한다고 생각해보자. 500개를 선언했을 때 변수가 선언된 메모리 영역에 값을 할당하는 경우 500개를 모두 메모리에 상주 시켜야한다. (500*8) = 4000byte

하지만 데이터 영역을 분리하여 주소 값만 변수 영역의 값에 할당을 한다면 데이터 3 숫자 하나만 선언하고 변수 500개의 값 주소에 참조만 하면된다.

이러면 (500*4)+8 =2008 byte이다. 요런 식으로 메모리 낭비를 최소화시킨다. 그러다 변수 하나의 값을 4로 변경시키면 그 변수만 새로 주소지를 만들어서 복제하면 된다. 왜냐 원시타입 데이터는 불변성이라서 값이 바뀌면, 새로운 메모리 주소를 배정 2020 byte(8+4).

물론 그래도 C나 C++에 비해 메모리 낭비가 더 될 수 밖에 없는 구조인 건 맞다. 당연히 메모리 구조에 민감한, 한정된 자원을 가지고 승부하는 게임이라든지 임베디드 쪽에서는 선호하지 않는 언어이고, 대신 컴퓨팅 능력이 예전과 비교할 수 없을 정도로 늘어난 현재에서 이렇게 느슨한 타입으로, 동적바인딩하는 것은 또 나름의 장점을 가지고 있다 ㅎㅎ

불변성

https://blog.naver.com/alsrb9434/222140981155 자바스크립트 데이터타입

변수를 선언할 때는 왠만하면 const로 해주자. 그 이유는 아래 링크를 보면 알 수 있다. 리액트 할 때, 불변함수를 쓰는 이유와 일맥상통한 부분이 있는데 이건 나중에 한 번 다뤄보겠다.
https://junwoo45.github.io/2019-11-04-memory_model/

‘배열은 변경할 수 있는 경우에만 유용한데, const는 이를 허용하지않으니..그렇다면 왜 const를 사용하는거야?'

사실 이 부분은 React를 다루면서 다시 한 번 적어볼려 했는데, const myArray = [] 로 선언하고, 여기에 push로 값을 밀어넣어도 const로 선언한 배열에 전혀 지장이 없는 이유는

보시다시피 데이터영역에 저장된 것은 배열의 참조값이고, push나 pop은 실제 바뀌는 겂은 또 다른 heap 영역이기 때문이다. 이래서 리액트 시 불변함수를 쓰라는 것이다. 리액트는 상태변수일 경우 불변성을 유지하는 게 중요한데, 이런 push나 pop 같은 얕은 복사 함수를 쓰면, const로 선언한다 해도 실제로 불변성이 유지가 안 되기 때문에, push나 pop 같은 거 빼고 아래 같은 경우는 버그가 생긴다.

//error 발생
myArray = 3  
myArray = ["a"]

대략적인 차이점

const nicoInfo = { //object 만들기
            name: "Nico ",
            age: 33,
            gender: "male",
            isHansome: true,
            facMovies: ["Along the Gods", "LoTr"],
            favFood: [
                { name: "kimchi", fatty: false },
                { name: "chesse burger", fatty: true }
            ]
        } //오브젝트를 array안에 넣을 수 있다. 반대도 가능


	console.log(nicoInfo.gender);
        nicoInfo.gender = "female";
         //const로 선언한 nicoinfo 자체는 변경할 수 없지만,
        //안에 있는 값을 바꾸는 것은 상관없다.
        console.log(nicoInfo.gender);
        
        console.log(nicoInfo.favFood[0].fatty);
       
       
        console.log(nicoInfo, console);
        //console.log, alert 등은 내장함수

타입과 크기가 동적으록 결정되니, 배열 안에 문자열이든, 숫자든 마음대로 집어넣고 추가할 수 있다.

var a6 = [1, 2, 3, "문자"];
console.log(a6);
console.log(a6[0]); //요런식으로 해도 전혀 컴파일에러가 안 뜨고, undifiend만 뜰 뿐

자바와 가장 큰 차이점이라면 함수를 변수에 저장할 수 있다는 것이다. 물론 자바도 람다식과 스트림을 활용해 겉보기에는 비슷하게 구현할 수 잇다.

function hello(n) { //타입이 동적이니 함수에 리턴타입을 명시해줄 필요도 없다.
  console.log("hello함수 호출됨");
  return n;
}

var 헬로 = hello; //요렇게 변수에 함수를 매핑
헬로(); //변수 안 넣어도 되고 넣어도 됨. 자유분방

익명함수 사용법은,

var a9 = function(){ //익명함수
    console.log("a9 실행됨");
};
// ECMA 2016버전부터
var a9 = () => { //화살표 함수
  console.log("a9실행됨");
};

a9();

1급 객체

자바스크립트에서 함수는 그 자체로 1급 객체이다.
https://soeunlee.medium.com/javascript%EC%97%90%EC%84%9C-%EC%99%9C-%ED%95%A8%EC%88%98%EA%B0%80-1%EA%B8%89-%EA%B0%9D%EC%B2%B4%EC%9D%BC%EA%B9%8C%EC%9A%94-cc6bd2a9ecac

1급 객체의 조건

  • 변수나 데이터 구조안에 담을 수 있다.
var bar = fucntion() { return 'javscript'; };
console.log(bar()); // javascript
  • 파라미터로 전달 할 수 있다.
var test = function(func) {
   func(); // 파라미터로 받은 함수 호출
}

test(function() {
   console.log('javascript');
});
  • 리턴 값으로 사용할 수 있다.
// 함수를 리턴하는 test() 함수
function test() {
   return function() {
       console.log('javscript');
   }
}

var bar = test();
bar();

대충 봐도 참 관대하고 자유분방하며, 그래서 더 종잡을 수 없고 어렵게 느껴지는 부분이 존재한다. 다음에는 더 종잡을 수 없는 자바스크립트 녀석의 특징에 대해서 알아보자.

내가 적은 글들은 틀릴 여지가 다분히 많으니, 참고는 하지 마라.

https://bigtop.tistory.com/24?category=800038

profile
시간대비효율

0개의 댓글