this

  • this는 기본적으로 window

  • 객체 메서드 안에서 this는 객체를 가르킴

    • 객체 메서드 : 객체 안에 있는 함수

    • 객체의 메서드 호출할 때 내부적으로 this를 바꿔줌

    • 단, 객체의 메서드를 호출한 것이 아닌, 객체의 메서드를 변수에 저장해서 호출할 경우 객체가 아닌 window를 가르킴

      1
      2
      3
      4
      5
      6
      7
      var obj = {
          a : function() {console.log(this)}
      };
      obj.a(); // obj
       
      var a2 = obj.a; 
      a2(); // window
      cs
  • 생성자 함수로 만든 객체에서 this는 인스턴스 자신을 나타냄

  • 이벤트 리스너

    • this : 이벤트 발생한 객체
    • 바뀐것이기 때문에 외울수밖에 없음
    1
    2
    3
    document.body.onclick = function(){
    console.log(this); // <body>
    }
    cs
  • 제이쿼리

    • 내부적으로 this를 클릭한 객체로 바꿔줌
    1
    2
    3
    $(‘div’).on(‘click’,function(){
        console.log(this);
    })
    cs
    • click 이벤트 안에서 메소드 나타날경우, this는 window가르킴

      • 함수의 this는 기본적으로 window라는 원칙을 따름
      • 이때 이벤트 호출한 객체를 저장하기 위해 var that = this와 같이 새로운 변수에 저장해서 사용하는 방법이 있음
    1
    2
    3
    4
    5
    6
    7
    $(‘div’).on(‘click’,function(){
        console.log(this); // div
    function inner() {
        console.log(‘inner’,this); // inner window
    }
    });
     
    cs

내부 슬롯, 내부 메서드

  • ECMAScript에서 사용하는 의사 프로퍼티(pseudo property), 의사 메서드(pseudo method)
  • ECMAScript에서 이중 대괄호로 감싸서 표현
  • 실제로 동작하지만, 개발자가 접근할 수 없음
    • 자바스크립트 엔진의 내부 로직
    • 일부 내부 슬롯, 내부 메서드에 한하여 간접적으로 접근 가능
  • 예시
    • 모든 객체 [[Prototype]] 내부 슬롯 직접 접근 불가능, proto로 접근 가능
1
2
3
const o = {};
o.[[prototype]] // Error
o.__proto__ // Object.prototype
cs

프로퍼티 어트리뷰트

  • 객체에서 프로퍼티 생성할 때, 프로퍼티 상태 나타내는 어트리뷰트도 함께 생성
  • 내부슬롯이어서 직접 접근 불가능
  • Object.getOwnPropertyDescriptor 사용해서 간접적 확인 가능
1
2
3
4
const person = {name:’Lee’};
console.log(Object.getOwnPropertyDescriptor(person, ‘name’));
// {value : ‘Lee’, writable : true, enumerable: true, configurable: ture}
 
cs
  • 종류(데이터 프로퍼티의 경우)
    • 데이터 프로퍼티 : 일반적 프로퍼티, 데이터 프로퍼티 외에 접근자 프로퍼티도 있음
      • [[value]] : 값
      • [[writable]] : 갱신 가능여부
      • [[enumerable]] : 열거 가능 여부
      • [[configurable]] : 재정의 가능 여부
    • 갱신과 재정의의 차이 :
      • 갱신 가능할경우, 해당 프로퍼티를 덮어 쓸 수 있음
      • 재정의 가능할 경우, 삭제하거나 재정의 불가능
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Object.defineProperty(person, ‘firstName’, {
    value:’Jango’
}); // value만 명시해줄경우, 나머지 속성들 false
console.log(Object.getOwnPropertyDescriptor(person, ‘firstName’);
// {value:’Jango’, writable: false, enumerable: false, configurable : false};
 
person.firstName = ‘Dingo’; // 갱신 불가능, writable = false이므로
// 에러발생하진 않고 무시됨
 
delete person,firstName; // 삭제 불가능, configurable = false이므로
// 에러 발생하진 않고 무시됨
 
Object.defineProperty(person, ‘lastName, {enumerable:true}) 
// 재정의 불가능, configurable = false이므로
// 에러 발생
 
cs

프로퍼티 종류

  • 데이터 프로퍼티 : 일반적 프로퍼티
    • 앞의 프로퍼티 어트리뷰트를 가짐
  • 접근자 프로퍼티 : 값을 갖지 않고, 다른 프로퍼티 읽거나 저장할때 사용
    • 프로퍼티 어트리뷰트
      • [[get]] : 데이터 프로퍼티 값읽을때 호출
      • [[set]] : 데이터 프로퍼티 값 저장할때 호출
      • [[enumerable]] : 데이터 프로퍼티 enumerable과 일치
      • [[configurable]] : 데이터 프로퍼티 configurable과 일치
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const person = {
    // 데이터 프로퍼티
    firstName : ‘Jango’,
    lastName : ‘Han’
 
    // 접근자 프로퍼티
    get fullName() {
        return `${this.firstName} ${this.lastName}`;
    }
set fullName(name) {
        [this.firstName, this.lastName] = name.split(‘ ‘);
    }
}
 
console.log(person.fullName); // Jango Han
person.fullName = ‘HY L’
console.log(person.firstName); // HY
console.log(person.lastName); // L
cs

출처

  • 모던 자바스크립트 Deep Dive[이웅모 지음], Ch.16

문제 링크 : https://www.acmicpc.net/problem/1520

문제 접근

  • 위에서 아래로 가는 경로가 아닌, 왼쪽이나 오른쪽으로 가는 케이스를 어떻게 해결?
    • 일반적 DP로는 불가능
  • 백트래킹?
    • 시작 위치에서 끝까지 가는 모든 경로를 확인
    • 한 위치에서 갈수 있는 좌표는 크게 4가지
    • 그럼 최악의 케이스 4^(MN) = 4^(2500) = 2^5000 >> 시간초과 >> 불가능
  • 끝에서부터 시작하는 DP?
    • 일반적으로 DP가 연산을 줄이기 위해서 시작점부터 진행하는데
    • 각 정점에서 이전에 온것을 재활용
    • DP[j][i] = (j,i) 좌표까지 올수 있는 경우의 수
    • DP[j][i] = min(DP[j-1][i], DP[j+1][i], DP[j][i-1], DP[j][i+1])
    • 단 현재 노드보다 계단 위치 높은 케이스에서만 진행

시간복잡도 계산

  • O(MN) >> 2500

인트 계산

  • 모든 입력 >> 10억 이하의정음수 >> INT 가능
  • dp값 : 최악의 케이스는 약 4^2500? >> 안전하게 LL 사용

코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include &lt;iostream&gt;
 
using namespace std;
typedef long long ll;
 
int map[510][510];
ll dp[510][510];
int N,M;
int dy[] = {0,1,0,-1};
int dx[] = {1,0,-1,0};
 
ll dfs(int y, int x) {
    if(dp[y][x] != -1return dp[y][x];
    
    dp[y][x] = 0;
    // 다음 노드
    for(int k=0; k&lt;4; k++) {
        int ny = y + dy[k];
        int nx = x + dx[k];
        if(ny&gt;=0 &amp;&amp; ny&lt;N &amp;&amp; nx&gt;=0 &amp;&amp; nx &lt; M) {
            // 무한루프 생각해줄필요 없음
            // 이전값과 비교해서 커야만 다음 재귀함수로 들어가기 때문에, 서로 왔다갔다 무한재귀할일은 없음
            if(map[ny][nx] &gt; map[y][x]) {
                dp[y][x] += dfs(ny, nx);
            }
        }
    }
    return dp[y][x];
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    
    fill(&amp;map[0][0], &amp;map[509][510], 0);
    fill(&amp;dp[0][0], &amp;dp[509][510], -1);
    
    cin &gt;&gt; N &gt;&gt; M;
    for(int j=0; j&lt;N; j++) {
        for(int i=0; i&lt;M; i++) {
            cin &gt;&gt; map[j][i];
        }
    }
    
    // 시작하는 경우
    dp[0][0= 1;
    
    cout &lt;&lt; dfs(N-1, M-1&lt;&lt; '\n';
    
    return 0;
}
 
cs

문제유형

  • 끝에서부터 시작하는 DP
  • DP에서 순차적으로 오는것이 아닌, 여러 경로가 있을떄 사용
  • 특히 2차원에서 상하좌우를 모두 고려해줘야할 때

+ Recent posts