12월 TIL 기록

Soo Im·2021년 12월 1일
0

일별 TIL 기록

목록 보기
6/19
post-custom-banner

2021-12-01

딥브레인AI 풀스택 과정 코딩테스트 완료~ 만점이다!

2021-12-03~04

통계치 나오는 기능까지 만들었다! 이제 가장 기본적인 기능은 끝!!!

2021-12-06

추가하고 싶은 기능 목록!

  1. '추가'를 누르면 맨 밑이 아니라 누른 블록 바로 아래에 추가 + startTime도 누른 블록 기준으로 세팅
  2. 블록 삭제 기능
  3. 시작 시간 순서대로 정렬해주는 기능
  4. 00:00 형식을 00.00h 형식으로 바꾸는 옵션
  5. 입력 값 저장 기능

1. .insertAfter()?
myParentNode.insertBefore(newChild, oldChild)myParentNode가 가지고 있는 기존 자식노드 oldChild (기준) 앞에 새로운 자식노드 newChild 를 추가하는 함수이다.
하지만 그 반대로 기준 자식노드 뒤에 추가하는 함수는 따로 정의되어 있지 않아서 보통 다음과 같은 스니펫을 사용한다.

Object.prototype.insertAfter = function (newNode) {     
    if (!!this.nextSibling) {
      this.parentNode.insertBefore(newNode, this.nextSibling);
    } else {
      this.parentNode.appendChild(newNode);
    }
  };

2. Node vs. Element
나의 경우에는 위의 스니펫에서 parentNode 대신 parentElement를 사용했다. 둘의 차이점은 노드와 요소(element)의 차이일텐데, 정확히 무엇이 다른걸까?
설명에 따르면 노드 ⊃ 요소 라고 보면 된다. 노드는 docuement, document.body, <p> 등 DOM 요소, html 태그 등등을 포함하는 개념이다. 반면 요소는 특정 유형의 노드로 html 태그를 이용해 지정 가능한 것을 말한다. 그러면 어떻게 노드와 요소를 구분해서 호출할 수 있을까?
이 블로그의 맨 아래 파트 예시를 보면 요소는 태그 안에 들어가 있는 것을, 노드는 전체를 다 가져온다고 이해하면 될 것 같다.

2021-12-08

  1. 블록 시작 시각 수정
    항상 맨 마지막 블록에만 시간이 입력되게 만들어서 시작 시각을 맨 마지막 블록의 종료 시각으로 설정했는데, 어제 중간에도 추가되게 만들면서 '추가를 누른 블록의 종료 시각'으로 설정하게 만들어야 했다.
    처음에는 this가 함수를 불러온 요소 그 자체를 가리킨다고 착각해서;; this.previousElement를 시도하는 등의 헛발질을 하다가... (this는 파이썬의 self랑 유사한 것 같음)
    버튼 클릭 함수로부터 e를 받아와서 간단히 해결했다! 바뀐 코드는 이렇다↓
// 전: 맨 마지막 블록의 시간을 가져옴
const latestTime = allBlocks[allBlocks.length-1].querySelector(".endTime").value;
// 후: 클릭 이벤트가 일어난 블록의 시간을 가져옴
const latestTime = e.target.previousSibling.previousSibling.value;
  1. 프로토타입?
    .insertAfter 프로토타입 함수를 만든 후 집계 버튼을 누르면 "insertAfter NaN:NaN"라는 예상하지 못한 게 나온다. 정작 html을 확인해보면 저런 요소도 존재하지도 않는데 왜 나오는지 아직 잘 모르겠다. 그냥 함수랑 프로토타입 함수의 차이 때문에 그런 것 같은데... 🙄 내일 검색 좀 해봐야겠다

2021-12-09

  1. 프로토타입

파이썬 클래스와 유사한 개념이라고 이해했다! MDN 설명에서 아래와 같은 생성자 함수(≃클래스 생성자 함수)를 선언하고 그걸 이용해 인스턴스를 만들었다.

function Person(first, last, age, gender, interests) {
  // 속성과 메소드 정의
  this.first = first;
  this.last = last;
//...
}

var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);

그러면 person1 인스턴스에는 first, last,...와 같이 생성자 함수에서 정의한 속성도 들어있다. 이 때 Person()person1의 프로토타입 객체(≃상위 클래스)이다. 그리고 person1에는 Person()의 속성 뿐 아니라 Person()의 프로토타입 객체인 Object의 속성인 vaueOf와 같은 속성도 들어있다.
파이썬에서 인스턴스에서 메소드를 호출하면 상위 클래스의 메소드를 확인하고, 없으면 상위 클래스의 상위 클래스의 메소드를 확인하는 것과 똑같은 방식이다.

출처: MDN

하지만 person1Object의 모든 속성을 상속받은 것은 아니다. 프로토타입 객체가 인스턴스에게 상속해줄 속성은 따로 지정할 수 있는데, 그런 속성을 프로토타입 속성이라고 부른다. 즉 Object.prototype.valueOf()로 메소드가 정의되었기 때문에 Person()person1이 상속받을 수 있는 것이다.

"보통 this가 현재 객체의 프로토타입 객체를 가리킬 것이라 오해하지만 그렇지 않죠. (프로토타입 객체는 __proto__ 속성으로 접근 가능한 내장 객체인 것 기억 하시나요?). 대신에 prototype 속성은 상속 시키려는 멤버들이 정의된 객체를 가리킵니다."

뭔가 이해했다고 생각했는데 이 글을 보니 다시 혼란에 빠졌다... OOP는... 참 묘하다... 시간을 좀 더 들여야겠다 🤨 아직 Python OOP도 완벽히 이해를 못한 것 같다

  1. 그래서 왜 집계 버튼 오류가 생기는가

디버그를 돌려봐도 마지막에 writeTrack(trackObj) 함수에 전달하는 객체에는 insertAfter가 없는데... 왜 저 함수가 실행되고 나면 없던 게 생기는 건지 나 참 ㅠㅠ
지금은 도저히 알 수 없어서 그냥 마지막 <ul> 을 제거하는 식으로 작업했다. 좀 더 연습하다보면 이유를 알게 되겠지...?

  1. 총 시간 추가

    얘도 이러네...ㅎ 도대체 프로토타입 함수는 왜 다 끌려나오는걸까 부른 적도 없는데

2021-12-12

저놈의 프로토타입... 해결책이 안 보여서 JS 객체지향 인강을 좀 들어보기로 🙃 (코드잇과 생활코딩 섞어서 들음)

Prototype-based Programming
자바스크립트는 다른 언어와는 다른 방법으로 객체 지향에 접근한다. 자바스크립트에서 객체 지향 프로그래밍을 논의할 때 Prototype-based Programming이라고 부른다.

  1. Factory Function
    (이 부분은 생활코딩에서는 따로 설명하지 않았고, 다른 자료에서도 자주 보지 못한 내용이라 그냥 참고만 하고 넘어가면 되겠다.)
    아래와 같이 객체를 생성하는 함수를 'Factory Function'이라고 부른다. 공장처럼 객체를 찍어낸다는 의미에서 이렇게 부른다.
    여기에서 this는 생성된 객체(정확히는 인스턴스인듯?) 그 자체를 가리킨다.
function createUser (name, age) {
  const user = {
    //name: name,
    //age: age,
    name,
    age,	// 프로퍼티와 파라미터가 동일한 경우에는 이렇게 생략해서 써도 된다(모던 JS).
    helloTo(others) {
      console.log(`${this.name} says hello to ${others.name}`);
    },
  };
  return user;
}

const user1 = createUser('Soo',27);
  1. Constructor Function
    자바스크립트에서 함수는 로직의 재사용 기능뿐 아니라 객체 생성자의 역할도 한다. 함수를 호출할 때 new를 붙이면 해당 함수는 새로운 객체를 초기화하한다. 이 함수를 생성자 함수라고 부른다.
    파이썬에서는 생성자는 클래스 내부에 존재하고 클래스의 인스턴스를 만들어내었다. 하지만 자바스크립트에서는 생성자가 어디에도 소속되어 있지 않고 new와 결합하여 객체를 생성한다.
    관습적으로 함수명을 대문자로 시작하고, 예상치 못한 객체 반환을 막기 위해return 값을 지정하지 않는다.
function User (name, age) {
  this.name = name;
  this.age = age;
  this.helloTo = function (others) {
    console.log(${this.name} says hello to ${others.name}`);
    };
}

const user1 = new User('Soo', 27);

2021-12-13

Prototype-based Programming

  1. class
    ES6부터 class를 사용할 수 있다. 이전에 배운 파이썬 OOP와 유사해 보인다.
class User {
  constructor (name, age) {	// 파이썬으로 치면 __init()__ 인 듯?
    this.name = name;
    this.age = age;
  }
  
  helloTo(others) {
    console.log(`${this.name} says hello to ${others.name}`);
  }
}

const user1 = new User('Soo', 27);
  1. Global Object
    모든 객체는 전역 객체의 프로퍼티이다.
    myFunc() 함수를 정의한 후에 myFunc()을 호출해도 되지만 window.myFunc()을 호출해도 결과는 동일하다. 이는 myFunc()window 객체의 메소드라는 의미이다. 즉 우리는 function myFunc() 과 같이 함수를 정의할 때 window라는 전역 객체의 내부에 메소드로 정의한 것이다. window는 편의를 위해 생략된 것이다.
    그래서 모든 객체가 전역 객체(window)의 프로퍼티라고 하는 것이다.

    참고
    전역 객체의 명칭은 호스트 환경에 따라 달라질 수 있다. node.js에서 전역 객체는 window가 아니라 global이다.

2021-12-14

Prototype-based Programming

  1. this
    함수 안에서 사용하는 특수한 변수. 어떤 함수에서 실행했는지에 따라 값이 달라진다.

1) 함수에서 this는 전역 객체window를 의미한다.

// 출처: 생활코딩
function func(){
    if(window === this){
        document.write("window === this");
    }
}
func(); // 실행 결과는 "window === this"

2) 메소드에서 this는 메소드를 가지고 있는 객체를 가리킨다. 이것을 통해 1)의 결과도 이해할 수 있다. func()은 전역 객체 window의 메소드이기 때문이다.

var o = {
    func : function(){
        if(o === this){
            document.write("o === this");}
    }
}

2021-12-17

Prototype-based Programming

  1. 함수 리터럴
    아래의 두 코드는 동일한 기능을 한다.
function sum(x, y) { return x+y; }	// 함수 리터럴
var sum2 = new Function('x', 'y', 'return x+y;');

sum2와 같이 생성자 함수를 통해 함수를 정의할 수도 있고, sum과 같이 함수를 정의할 수도 있다. sum과 같이 정의하는 것을 '함수 리터럴'이라고 부른다. 이는 const a = { ... };를 객체 리터럴 이라고 부르는 것과 마찬가지이다.
sum, sum2 함수는 둘 다 객체이다.

  1. apply
    JS에서는 함수(메소드)가 반드시 특정 객체에만 종속되지는 않는다. 위에서 함수 리터럴로 정의한 함수는 window의 메소드이지만, 다르게 호출할 경우 다른 객체의 메소드가 될 수도 있다. 그 예가 apply이다.
// 출처: 생활코딩
var o = {}
function func(){
    switch(this){
        case o:
            document.write('o<br />');
            break;
        case window:
            document.write('window<br />');
            break;          
    }
}
func();	// window 의 객체이므로 this === window
func.apply(o);	// o 의 객체로 호출되었으므로 this === o

(강의에서 apply 자체를 자세히 다루지 않아서 좀 더 찾아보고 있는데 뭔가... 왜 굳이 이렇게 하나 싶게 생긴 예제가 나온다; 함수를 호출할 때 인자를 그냥 주는 거랑 무슨 차이인거지?)

2021-12-20

Prototype-based Programming 상속(하는 법)

// 출처: 생활코딩
function Person(name){
    this.name = name;
}

// 사람 객체의 프로퍼티 선언
Person.prototype.name=null;	// 굳이 안 해줘도 되지만 name 프로퍼티가 있음을 보여주기 위함
Person.prototype.introduce = function(){
    return 'My name is '+this.name; 
}
 
function Programmer(name){
    this.name = name;
}

// 사람 객체의 프로퍼티를 프로그래머 객체에 상속시킴
Programmer.prototype = new Person();	// 작동 방식은 다음 장에 설명
Programmer.prototype.coding = function(){
    return "hello world";
}
 
var p1 = new Programmer('Soo');
document.write(p1.introduce()+"<br />");
document.write(p1.coding()+"<br />");

2021-12-21

Prototype-based Programming 프로토타입!

  1. 왜 필요할까?
    prototype 말 그대로 그 객체의 '원형'이다. 즉 생성될 때부터 기본적으로 가지고 있어야 하는 것을 의미한다.
    만약 '원형'이 필요가 없다면 굳이 힘들게 const obj = new myFunc(); 과 같이 생성자 함수를 이용해 객체 obj를 만들 필요가 없다. 그냥 const obj = {} 이렇게 객체 리터럴로 선언해도 된다.
    하지만 obj 안에 어떤 프로퍼티가 처음부터 담겨있기를 원한다면, 즉 특정 '원형'을 원한다면 prototype를 이용해 그것을 줄 수 있다.

  2. 어떻게 상속하나?
    prototype은 객체 안의 객체이다. myFunc.prototype에 프로퍼티를 주어 사용할 수 있다. myFunc.prototype.name = 'Soo';와 같이 부여하면 const obj = new myFunc();으로 obj 객체를 만들었을 때 그 객체 안에 {name : 'Soo'}가 들어간다. 전달하는 과정은 아래와 같다.

function Person(){}
Person.prototype.hi = 'hi';

function Programmer(){}
Programmer.prototpye = new Person();

const soo = new Programmer();
console.log(soo.hi);	// 'hi'

네 번째 라인에서 new Person();{hi : 'hi'}Programmer.prototype에 전달해준다. 그래서 Programmer.prototypePerson.prototpye과 같은 프로퍼티를 가지는 것이다. 이런 식으로 prototype을 통해 객체 간의 프로퍼티를 전달하는 것을 prototype chain이라고 부른다.

  1. prototype chain 추가
    반드시 생성자 함수(객체)를 통해서만 프로퍼티를 전달할 필요는 없다. 아래처럼 임의의 객체 someone을 만들고 그 프로퍼티 {hi : 'hello world'}를 전달하는 것도 가능하다.
function Person(){}
Person.prototype.hi = 'hi';

const someone = new Person();
someone.hi = 'hello world';

function Programmer(){}
Programmer.prototpye = someone;

const soo = new Programmer();
console.log(soo.hi);	// 'hello world'

Programmer.prototpye = Person.prototype이라고 하지 않나?
이렇게 해도 결과는 동일하게 나온다. 하지만 Person.prototype을 전달하면 문자 그대로 Person의 prototpye 그 자체가 전달되어 버린다. 그래서 Programmer에 프로퍼티를 추가할 때 Person에도 똑같이 추가가 된다.
이렇게 부모 객체에 영향을 주는 것을 막기 위해서 Person의 복사본을 만들어 prototype에 주는 것이다.

2021-12-22

Prototype-based Programming Object 확장

  1. Object 확장의 위험성
    드디어 insertAfter가 출력되는 이유를 찾았다!!!
    내가 한 것처럼 Object에 변수 neddle을 찾는 함수 contain을 프로토타입에 추가해 확장했다고 가정해보자.
//코드 출처: 생활코딩
Object.prototype.contain = function(neddle) {
    for(const name in this){
        if(this[name] === neddle){
            return true;
        }
    }
    return false;
}

이렇게 확장 한 뒤에 임의의 객체 내부의 프로퍼티를 출력하면 우리가 추가한 메소드까지 출력된다.

const o = {'name':'Soo', 'hello':'world'}
for(const name in o){
    console.log(name);  
}

// 출력 결과
// name
// hello
// contain <-- 우리가 추가한 메소드까지 출력된다! 모든 객체에 contain이 상속되었기 때문에 이렇게 나온다.

따라서 넓은 범위에 영향을 주는 Object와 같은 객체를 확장하는 것은 위험하다.

  1. hasOwnProperty
    확장한 Object 프로퍼티까지 출력하는 것을 방지하는 방법이 있다. 상속받은 것인지, 혹은 자기 자신만의 프로퍼티인지 체크해서 상속받은 Object 프로퍼티를 건너뛰는 방식이다.
for(const name in o){
    if(o.hasOwnProperty(name))	// o 안의 프로퍼티 name이 o 만의 것인지 체크한다. 상속받은 contain은 false이기 때문에 출력되지 않는다.
        console.log(name);  
}

와아악 해결했다 이제 안나온다 🤗

2021-12-23

깃 브랜치 잘못 합쳐서 날아갔다... ^^ 이젠 깃 공부다

2021-12-27

Python
여러 값을 반환하는 함수를 apply(혹은 map)해서 한 번에 여러 열을 채우려고 했다. 예를 들어 'a'열의 값을 map해서 df의 'c', 'd'열을 한 번에 채우는 상황이다.

def my_function(x):
	a = x + 1
   	b = x + 2
    	return a, b
    
df = pd.DataFrame(np.array([[1, 2], [11, 12]]), columns=['a', 'b'])

하지만 df['a'].map(lambda x: my_function(x))의 반환값은 [2, 3], [12, 13] 의 object이기 때문에 이걸 단번에 'c', 'd'열로 넘길 수는 없다. 이걸 object->array->pd로 바꾸어서 넣어야 하나 고민하고 있는데 이 글을 보고 쉽게 해결했다.

def my function(s):
	s['c'] = s['a'] + 1
    	s['d'] = s['a'] + 2
    	return s
        
df = df.apply(my_function, axis = 1)        

함수에 단일 값 x 대신 pd.Series를 넘겨주고 함수가 pd.DataFrame을 반환하는 방식이다. 이번에는 apply로 끝냈지만 map으로 하는 방법도 있지 않을까 궁금하다.

2021-12-28

아!!!! 드디어!!!! Object 프로토타입 함수 문제 해결했다!!!!! 오래걸렸다 정말 ㅠㅠㅠ 이제 꼭 구현해야 하는 'Start!' 버튼 hidden이랑 삭제 만들어보자! 그리고 빈 칸은 읽어오지 않는 것까지 구현해야겠다

2021-12-29

시작 hidden & 삭제 버튼 & 모든 block 삭제되었을 때 시작 다시 나타나는 것까지 구현 완료!! 이제 더 이상 근무시간은 기록하지 않아도 된다고 해서... 살짝 당황스럽지만... 혼자서라도 쓰면 되니까~ 😄 (아까운데 어디 뿌릴 곳 없을까)

2021-12-31

1년 동안 CS(알고리즘, 자료구조)기초, SQL, HTML&CSS, JS, OOP 기초를 공부했다. 데이터 분석 직무로 가고 싶다→근데 분석만 하면 안 되고 데이터 추출도 알아야 한다고?→데이터 추출하려면 웹을 알아야 한다고? 하는 사고를 거쳐 어쩌다보니 JS를 제일 많이 공부했다. 원래 목표는 백엔드였는데 JS에 빠져들어서 미니 웹 어플리케이션을 만드는 것으로 한 해를 마무리했다 🤗
JS를 예상 외로 오래 공부했지만 실제로 동작하는 무언가를 만드는 것은 정말 재미있는 경험이었다! 내년에는 개발과 분석 사이의 줄타기를 좀 더 잘 하며 공부해야겠다.

post-custom-banner

0개의 댓글