딥다이브 스터디 10,11,12(객체,함수)

김영현·2023년 9월 25일
2

서론

일주일에 두번 발표. 참여자는 4명. => 차례가 2주싸이클로 돌아간다.
보통 두챕터씩 하기로 했지만, 이번 10,11챕터가 둘다 객체기때문에 한번에 묶어서 진행.

객체란 무엇일까?


객체

JS는 객체기반언어다. 원시타입을 제외한 나머지 모두는 객체!
원시타입은 단 하나의 값. 객체는 모든 값을 저장할 수 있음. => 묶어서 관리하기 용이
객체에 할당된 함수는 편의상 구분짓기 위해 메서드라고 함
보통 객체 내부 값은 두가지로 구분짓는다.

  • 프로퍼티 : 객체의 상태를 나타내는 값. 키-값쌍으로 구성.
  • 메소드 : 프로퍼티를 조작하는 용도.

=> 상태-조작을 한군데로 묶어서 관리함.

객체 리터럴

리터럴은 값을 나타내는 표기법. => 사람이 이해할 수 있는 문자 또는 약속된 기호 사용
클래스 기반 객체지향 언어는 보통 클래스(객체를 찍어내기 위한 템플릿new연산자를 사용해
인스턴스(객체. 메모리에 저장되는 실체를 의미)를 생성.
JS는 프로토타입기반 객체지향 언어 => 약간 다르다(물론, ES6부턴 class로 찍어낼수 있다. 본질은 프로토타입)

객체지향JS는 여기서..
https://velog.io/@loevray/OOJSObject-oriented-JavaScript

아무튼 다양한 객체생성 방법이 있음

  • 객체 리터럴 : {}
  • Object 생성자 함수 : new Object()
  • 생성자 함수 new func()
  • Object.create()
  • 클래스(위에설명)

주의할 점 : 코드블록과 혼동가능하기에, 블록에는 세미콜론x

프로퍼티

쉼표로 구분. 문자열 or 심볼. 따옴표 생략 가능. 모든값은 문자열로 암묵적 타입 변환.
중복값은 덮어쓰기.
표현식으로도 가능. 이때는 대괄호 표기법Obj[1+2]사용.
대괄호 표기법 쓸땐, 표현식인지 아닌지 구분해야 함

const obj = {
	a:1
};
obj.a // 1
obj["a] // 1
obj[a] // a is not defined...

없는 프로퍼티는 undefined반환. 에러가 아니니 유의.

es6이후 추가된 확장기능들이 몇가지 있음.

  • 프로퍼티 축약
const x = 1;
const obj = {
	x
};
console.log(obj) // { x: 1 }
  • 메서드 축약
const obj = {
  	//es6 이전
	sayHi : function()...
	//es6 이후
    sayHi() {
		something...
	}
}

참고로 메서드축약은 생성자 함수로 호출x => 당연한거긴함


원시값 VS 객체

  • 숫자
  • 불리언
  • 문자열
  • null
  • undefined
  • Symbol

을 제외한 모든 값은 객체임. (함수, 배열 기타등...)
구분하는 기준은 뭘까?

  • 원시타입 변경 불가능, 객체타입 변경 가능한 값.
    변경 불가능변수가 아니라 . => 불변성
    문자열은 참고로 유사 배열 객체(길이,인덱스), 이터러블하기에 순회,인덱스 조회가능.
    But! 원시값 => str[0] = something처럼 변경 불가능.
//1이라는 값이 메모리상 저장. x는 1의 주소 가리킴
let x = 1;
//1이라는 값은 메모리에 남아있고, 1을 더한 값이 메모리상 추가됨.
x = x + 1;
//x는 1+1=2의 주소를 가리킨다.
x // 2
  • 원시타입은 메모에 실제 값, 객체타입은 참조 값 저장.(stack, heap).
  • 원시값 변수 다른변수 할당하면 원시 값 복사전달. 객체참조값 복사전달.
//80값 생성 후 a가 가리킴.
let a = 80;
//a는 80의 주소를 가리킴. b는 80이라는 값을 메모리에 새로 생성하고, 가리킨다. or 같은 메모리 가리키는중
let b = a;
//a의 포인터는 100으로 이동
a = a + 20;
// a = 100, b = 80

아래는 객체의 경우다

const obj1 = {
	a : 1,
  	b : 2,
};
//객체는 stack에 변수명이 저장되고, heap에 실체가 저장된다.
//따라서 obj1이 stack에서 참조하고있는 heap의 주소를 obj2도 갖게된다.
//이는 한쪽 객체 내부의 값(heap)이 변경되면 둘 다 바뀌어 버리는 사태를 초래함.
const obj2 = obj1;
obj1.a = 5; // obj1,obj2의 a값이 둘다 바뀐다.
obj2.b = 3; // 역시 둘다 바뀐다.

위와 같이 같은 heap을 가리키는 복사를 얕은 복사(shallow copy).

const obj = {
	x : 10
}
const obj2 = {...obj};
obj === obj2 //false

이렇게 새로운 heap을 할당하는 복사를 깊은 복사(deep copy).
스프레드 문법 or Object.asgin은 1depth까지만 깊은복사.
=> 재귀로 모든 중첩객체에 적용하면 됨


함수

입력받으면 출력함. 수학의 함수와 일치하는 개념.
=> 일련 과정을 statement로 구현, 하나의 실행단위(코드블록)로 감쌈.

JS에서 함수는 객체다.

함수의 장점은...

  • 코드의 재사용성
  • 코드의 가독성
  • 코드의 신뢰성

JS에서 함수 정의방법은 여러가지가 있음.

  • 선언문
// 할당이 안된 것 처럼 보이지만, 식별자가 암묵적으로 생성됨.
function add(x,y){
	return x+y;
}
//함수 리터럴은 이름생략해서 표기가 가능하다
function (x,y){
	return x+y;
}
  • 표현식
//함수에 이름을 붙이는게 아닌, 변수에 붙임
const add = function (x,y){
	return x+y;
}
  • 생성자 함수
const add = new Function("x","y", "return x+y");
  • 화살표(es6)
//return하는 값만 존재하면 자동 return
const add = (x,y) => x+y;

표현식이 아닌 문은 변수에 할당할 수 없는데, 어떻게 가능할까?
JS엔진은 코드 문맥에따라 표현식, 선언문구분해서 처리함.
이름이 있는 기명 함수 리터럴에 한해서.

//피연산자로 사용되지 않는다면 선언문으로 인식.
function foo() {console.log("foooooo")} 
foo()// fooooo
//괄호 안의 피연산자로 사용됐기에 표현식으로 해석된다.
(function bar(){console.log("baaaar")}); 
bar()// bar is not defined...

함수는 객체다. 함수의 이름은 함수 몸체 내부에서만 사용가능하다. 그럼, 함수는 어떻게 호출하지?
=> 함수를 호출하기위해 엔진이 암묵적으로 식별자 할당
이를 코드로 나타내보면 이런 셈이다.

const add = function add(x,y){return x+y};

add라는 식별자를 생성한거임!

함수와 호이스팅

함수는 호이스팅된다. 실행 전 수집과정에서 식별자를 찾아 읽기 때문이다.

console.log(add(2,5)) //7
console.log(hi())//hi is not a function
//선언문
function add(){...}
//표현식. var에 할당해도 마찬가지다.
const hi = function (){...}

그리고, 기존의 var처럼 변수 호이스팅과는 결이 다르다.
varundefined로 초기화 되지만, 선언문이미 작성된 함수 객체로 초기화된다
=> 함수를 늦게 작성해도, 작동한다.

표현식변수를 할당하는 과정이다. 따라서 hiundefined로 초기화된다.
=> 그래서 is not a function 오류가 나옴.

생성자 함수

클로저 생성x 기존 함수들과 작동방식이 다르니 쓰지말자.

화살표 함수

ES6이후 도입.function 키워드 대신 => 사용, ()괄호의 위치 바뀜
const x = () => {...}

  • 생성자로 사용 불가능
  • this 바인딩 방식 다름(?)
  • prototype 존재 x
  • arguments객체 생성 x

난중에 알아보자

함수의 호출

  • 매개변수에 암묵적으로 undefined할당.
    인수가 많으면 무시. 사실 arguments객체에 들어감. 추후 18장에서 봄.
  • 인수 갯수, 타입은 고려하지 않는다. => ts의 필요성..
  • ES6이후로 매개변수에 기본값 할당 가능
    function(x = 5, y= 6){...}
  • 매개변수의 최대개수는 제한이 없다. 그러나 가급적 3개이하 유지 + 한 가지 일만 하도록.
    여러개의 변수가 필요하다면 그냥 객체로 던지자
  • 함수는 반환문(return)으로 값을 반환함. return 만나면 함수 실행 중단 후 빠져나감.
    기본적으로 undefined을 돌려준다.
  • 함수에 객체 전달할때, 얕은복사, 깊은복사유의.

함수의 다양한 형태

즉시실행 함수

(function(){
  ...
}());

피연산자, 익명함수. 다시호출 불가능(함수 몸체 외부)
반드시 그룹연산자()로 감싸야함.
값 반환, 인수 전달 가능.
실행 후 바로 사라지기에 변수,함수 이름 출동 방지 용이

재귀 함수

function hi(){
	...
    hi();
}
hi();

자기자신 호출. 탈출조건없으면 무한루프

중첩 함수

function outer(){
	const a = 10;
  	function inner(x){
  		return x + 10;
  }
  inner(a);
}
outer();

중첩함수는 스코프와 클로저에 깊은 연관이 있다.

https://velog.io/@loevray/JS-%EB%8F%99%EC%9E%91%EC%9B%90%EB%A6%AC-2-%EC%8A%A4%EC%BD%94%ED%94%84-%ED%81%B4%EB%A1%9C%EC%A0%80

콜백 함수
매개변수를 통해 다른 함수의 내부로 전달되는 함수. 콜백함수를 전달받은 함수는 고차함수라 함.
어렵게 생각할 필요 없다.

//각각 콜백, 고차함수
function callback(){...}
document.addEventListner("click", callback);
//or
document.addEventListner("click", function () {...}); //익명으로 전달 가능

요런거다.

콜백함수가 자주 쓰이지 않는다면 익명으로 전달, 자주쓰인다면 분리해서 만들어놓는게 낫다.
=> 이벤트때만 함수 생성 or 계속 생성 되어있음.

순수함수와 비순수 함수

클린 코드와 연관이 깊다.

  • 순수함수 : 어떠한 외부 상태에 의존x 변경x. 항상 동일인자, 동일결과. => side Effect가 없다.
  • 비순수 함수 : 순수함수의 반대. 의존하거나, 변경하거나.
let cnt = 0;
const pure = (n) => {
  	return ++n;
}
const notPure = () => {
  	return ++cnt;
} 

함수가 외부상태를 변경하면 추적이 어려움.
함수형 프로그래밍의 의의 => 사이드 이펙트 최소화 및 불변성 지향. 순수함수 지향!

출처

https://www.yes24.com/Product/Goods/92742567
이웅모 저자님의 '모던 자바스크립트 deep dive'

profile
모르는 것을 모른다고 하기

0개의 댓글