[TIL 2023.02.24] CSS position / this keyword

김헤일리·2023년 2월 24일
0

TIL

목록 보기
34/46

지식 보충을 위해 조금씩 정리를 해보자! #4


1. CSS - position

position 속성은 HTML 태그로 제작한 문서의 요소들를 어떻게 위치시킬지를 정의하는 속성이다. 총 5가지 값을 갖고 있고, 좌표를 지정해주기 위해서 left, right, top, bottom 속성과 함께 사용한다.

1. Static

  • postion의 기본 값이며, 다른 태그와의 관계에 의해 자동으로 배치된다.
  • 사용자가 위치를 임의로 설정할 수 없고, top, right, bottom, left와 같은 속성을 사용할 수 없다.
    (float 속성만 임의 설정 가능)

2. Relative

  • 기본 값(static) 속성을 기준으로 top, right, bottom, left 속성을 써서 상대적 위치를 지정할 수 있다.
  • 예를들어, static일 때 기준으로 0,0의 좌표를 갖고 있었다면, style="top:5px; left: 5px;" 을 적용 시, 왼쪽으로부터 5px, 위쪽으로부터 5px 이동하는 형식이다.
  • 연관되는 요소 (부모 요소 등)가 있을 경우, 해당 요소를 기준으로 좌표가 지정된다.

3. Absolute

  • 브라우저가 문서의 흐름과 상관없이 (요소를 수직으로 쭉 놓을지, 수평으로 쭉 놓을지 등을 결정하는 것) left, right, top, bottom 속성값을 이용하여 요소를 위치시키는 속성값이다.
  • 기준이 되는 위치는 가장 가까운 부모 요소 혹은 조상 요소 중 position 속성이 relative인 요소이다.

4. Fixed

  • absolute처럼 문서의 흐름과 상관없이 위치가 고정되는 값이지만, 기준되는 좌표가 브라우저의 왼쪽 최상단이다.
  • 스크롤을 해도 그 자리에 그대로 고정된다.
  • 다른 position 속성과 마찬가지로 left, right, top, bottom 속성값을 이용하여 요소를 위치할 수 있다.

5. Sticky

  • scroll 박스, 혹은 viewport를 기준으로 박스 내부에선 relative처럼 동작하다가 박스 밖으로 넘어갈 경우 그 자리에 고정되어 fixed처럼 동작하게된다.
  • scroll 박스는 overflow 속성이 존재하는 부모요소를 의미한다. 여기서 부모요소가 overflow를 특별히 명시하지 않았다면 부모요소가 바로 scroll 박스가된다!
  • sticky요소는 특정 시점에서 fixed 요소처럼 행동하다 자신의 부모 요소와 만나게 되면 멈추게된다.
  • scroll 박스 사이에 overflow: hidden 이 적용되있는 요소가 있을 경우에는 sticky 속성이 제대로 동작하지 않을 수 있다.
  • sticky 요소는 부모 요소, 정확히는 override: hidden 속성을 가지지 않은 요소의 크기 밖으로 나갈 수 없다.

6. Inherit

  • 부모 element의 position속성을 물려받는다.
  • IE7까지는 지원하지 않으므로 해당브라우저를 고려해야 하는 경우는 사용하지 않도록 한다.
  • 다만 position이 아니라 다른 css의 값을 상속받을때도 사용 가능하다.


2. This

자바스크립트의 함수는 호출될 때, 매개변수로 전달되는 인자값 이외에, arguments 객체와 this를 암묵적으로 전달 받고, 함수 호출 방식에 의해 this에 바인딩할 어떤 객체가 동적으로 결정된다.
다시 말해, 함수를 선언할 때 this에 바인딩할 객체가 정적으로 결정되는 것이 아니고, 함수를 호출할 때 함수가 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정된다.

출처: poiemaweb

❗️ 함수와 메소드의 this

  • This란 함수 내에서 함수 호출 맥락(context)을 의미한다. 함수에서 this를 호출하면 전역객체인 window와 같다.
function func(){
// 익명 함수를 생성하고, 함수 내에 로직을 설정한다.
  if(window === this) {
  // 만약 window와 this의 값이 같다면, 
    console.log("window===this")
    // 콘솔에 "window===this"라는 문자열을 출력한다.
  }
}
func();
// 그리고 해당 함수를 호출하면, 

// result
"window===this"
// 콘솔에 "window===this"라는 문자열이 출력된다.
  • This가 객체의 소속인 메소드에 해당한다면, this는 그 객체를 가르킨다. (자기 자신을 this로 접근할 수 있다.)
let o = {
// 이번엔 객체를 생성한다.
  func:function(){
  // func라는 키의 값으로 함수를 설정한다. (해당 함수는 메소드가 된다)
    if(o === this){
    // 만약 객체인 o가 this와 같다면,
      console.log("o===this")
      // "o===this"라는 문자열을 콘솔에 출력한다.
  }
}

o.func();
// 객체 o의 메소드로 func()를 호출하면,
  
// result
"o===this"
// 콘솔에 "o===this"라는 문자열이 출력된다.
  • 사실 이 의미는 첫번째 예시에서 전역객체인 window가 호출되는 것과 동일한데, 바로 위 메소드 호출 예시처럼 특정 객체가 선언되지 않았다면 익명 함수를 호출했을 때 해당 함수는 window에 소속된 객체라고 볼 수 있는 것이다.
    • this라고 하는 것이 그 메소드가 소속된 객체를 가르키기 때문에 함수를 호출했을 때 this의 값이 window가 되는 것과 어떠한 객체에서 메소드를 호출했을 때 그 this의 값이 그 메소드의 소속인 객체를 가르킨다는 건 같은 의미이다.
    • 다만, 함수는 window가 암시적으로 사용되기 때문에 우리가 보기에 함수 호출과 메소드 호출이 달라보이기 때문에 동일하게 보이지 않는 것 뿐이다.

❗️ 생성자와 this

  • 함수 안에서 this라는 키워드는 그 함수가 소속된 객체를 가르킨다 (기본 원칙)
  • 함수 호출 컨텍스트마다 this는 마치 달라보이지만, 사실은 같은 매커니즘을 지니고 있다.
let funcThis = null;

// 함수 정의
function Func(){
  funcThis = this;
}

// 일반 함수 호출
const o1 = Func();
// 1. 해당 함수 실행 시, Func()가 실행된다.
// 1-1. 이때 Func() 안에 있는 funcThis는 변수 선언문이 없기 때문에, 전역으로 선언되어있는 funcThis와 동일하다.
// 1-2. 그렇기 때문에 일반적으로 Func()를 호출했을 때 Func()에서 가르키는 this는 null을 값으로 갖고있다.

if(funcThis === window){
// 2. 일반 함수 호출 시 funcThis는 전역으로 호출된 funcThis와 같기 때문에 window가 된다.
// 2-1. 함수를 호출하면 함수는 window라는 객체의 메소드이기 때문이다.
  console.log('window')'
}

// 생성자로서 함수 호출
const o2 = new Func();
// 3. 생성자로 함수를 호출할 경우, 자바스크립트는 내부적으로 비어있는 객체를 만든다.
// 3-1. 비어있는 객체는 생성자 안에서의 this가 된다. (새로 생성되는 객체가 생성자 안에서의 this가 된다는 것!)
// 3-2. new Func() 생성자 함수의 내용도 동일하게 funcThis를 this로서 갖게된다.
// 3-3. 여기서 this는 전역 변수 funcThis이기 때문에 일반 함수 호출과 정확하게 같은 값 (null)을 갖는다.

if(funcThis === o2){
// 4. 다만 달라지는 것은 funcThis의 소속(?)이다.
// 4-1. 생성자를 통해서 만들어진 객체는 o2에 담겨있기 때문에, 생성자의 맥락으로 this가 변한다.
// 4-2. Func()에 담겨있던 this는 일반 호출의 경우와 다르게 window가 아니라 this가 속해있는 객체(o2)를 가르키게 된다.
  console.log('o2');
}
  • this라고 하는 것은 객체의 초기화가 끝나서 어떤 식별자에 담기기 전에 그 객체를 참고할 수 있는 레퍼런스(식별자)가 된다.
  • 생성자 안에서의 this는 그 생성자가 만들 객체를 가르킨다.

❗️ apply와 this

  • 함수의 메소드인 apply, call을 이용하면 this의 값을 제어할 수 있다.
const o = {}
const p = {}

function func(){
  switch(this){
    case o:
      console.log('o')
      break;
    case p:
      console.log('p')
      break;
    case window:
      console.log('window')
      break;
  }
}

// func를 함수로서 호출할 경우
func();
// 1. func의 this (switch 안에 this) 는 window가 된다.
// 1-1. 그렇기 때문에 case window에 있는 로직이 실행된다.

// 함수는 객체이기 떄문에 apply라는 표준 메소드를 사용할 수 있다.
func.apply(o);
// 2. apply의 첫번째 인자는 '함수 호출 컨텍스트'이다.
// 2-1. 그렇기 때문에 해당 함수는 func() 함수를 실행하면서, switch문에 있는 this는 선언된 객체 o를 가르키게된다.
// 2-2. case o에 있는 로직이 실행된다.

func.apply(p);
// 3. 위와 동일한 방식으로 인자를 p로 설정한다면,
// 3-1. switch문 안에 있는 this는 선언된 객체 p를 가르키게되고, case p에 있는 로직이 실행된다.
  • 전통적인 객체지향에서 메소드라고 하는 것은, 어떠한 객체의 강하게 소속된 무언가가 된다.
  • 그렇기 때문에 프로그래밍에선 객체는 master, 메소드는 slave라고 칭한다.

  • 하지만 만약 여러개의 객체 (window, o, p)가 있고 함수는 func 1개라면, 어떤 객체가 인자로서 호출되었을 때 함수라는 메소드는 지속적으로 값이 바뀌었다. (switch 문에서 계속 다른 값이 출력)
    • 함수는 계속 다른 객체의 메소드가 되었는데, 객체와 함수는 개별적인 것이다. (함수도 객체이기 때문)
    • 함수가 어떻게 호출되었는지에 따라서 함수의 소속이 변경된다. = "함수 호출 방식에 의해 this에 바인딩할 어떤 객체가 동적으로 결정된다."
    • 함수는 일반적인 객체지향의 메소드보다 훨씬 더 위상이 높은것이다. 하지만 어떻게 호출하냐에 따라 맥락적으로 어떠한 객체에 종속되는 존재인것이다.

핵심:

this는 변화무쌍하다! 함수가 누구의 소속인지에 따라 this의 값은 함수가 소속된 객체를 가르킨다!


출처:

profile
공부하느라 녹는 중... 밖에 안 나가서 버섯 피는 중... 🍄

0개의 댓글