-
this가 동작하는 원리와 용법JavaScript/모던 자바스크립트 딥다이브 2023. 2. 24. 15:08
position을 어떻게 사용하는지 알려주세요.
CSS에서 position 속성은 HTML 문서 상에서 요소가 배치되는 방식을 결정합니다. 많은 경우, position 속성은 요소의 정확한 위치 지정을 위해서 top, left, bottom, right 속성과 함께 사용됩니다.
position: static
position 속성을 별도로 지정해주지 않으면 기본값인 static이 적용됩니다. position 속성이 static인 요소는 HTML 문서 상에서 원래 있어야하는 위치에 배치됩니다.
이 말은 요소들이 HTML에 작성된 순서 그대로 브라우저 화면에 표시가 된다는 것을 뜻하며, 따라서 top, left, bottom, right 속성값은 position 속성이 static일 때는 무시됩니다.
position: relative
position 속성을 relative로 설정하게 되면, 요소를 원래 위치에서 벗어나게 배치할 수 있게 됩니다. 요소를 원래 위치를 기준으로 상대적(relative)으로 배치해준다고 생각하시면 이해가 쉬울 것 같은데요. 요소의 위치 지정은 top, bottom, left, right 속성을 이용해서, 요소가 원래 위치에 있을 때의 상하좌우로 부터 얼마나 떨어지게 할지를 지정할 수 있습니다.
position: absolute
position 속성값 중 가장 난해하고 주의해서 사용해야하는 속성값은 absolute입니다. 아마도 absolute라는 영단어의 의미 때문일텐데 relative 속성의 정반대 개념이라고 많이 오해를 합니다. 오히려 absolute 속성값은 relative 속성값과 함께 사용되는 경우가 많은 데 말입니다.
position 속성을 absolute로 지정하면 사실 전혀 절대적(absolute)으로 요소를 배치해주지 않습니다. 오히려 배치 기준이 상황에 따라 굉장히 달라질 수 있는데요. 흥미롭게도 position 속성이 absolute일 때 해당 요소는 배치 기준을 자신이 아닌 상위 요소에서 찾습니다. DOM 트리를 따라 올라가다가 position 속성이 static이 아닌 첫 번째 상위 요소가 해당 요소의 배치 기준으로 설정되는데요. 만약에 해당 요소 상위에 position 속성이 static이 아닌 요소가 없다면, DOM 트리에 최상위에 있는 <body> 요소가 배치 기준이 됩니다.
position: fixed
position 속성을 fixed로 지정하면 이렇게 요소를 항상 고정된(fixed) 위치에 배치할 수 있습니다.
이게 가능한 이유는 fixed 속성값의 배치 기준이 자신이나 부모 요소가 아닌 뷰포트(viewport), 즉 브라우저 전체화면이기 때문인데요. top, left, bottom, right 속성은 각각 브라우저 상단, 좌측, 하단, 우측으로 부터 해당 요소가 얼마나 떨어져있는지를 결정합니다.
position: sticky
sticky 속성은 static과 fixed 속성의 특징을 모두 가지고 있는 속성입니다. sticky 영역의 x 또는 y 위치값이 설정한 위치에 도달하기 전까지는 static, 도달 이후에는 fixed처럼 행동하게 됩니다.
this가 동작하는 원리와 용법을 아는대로 설명해주세요. 평소 코드 중에서는 어떤 부분에서 가장 큰 차이가 생기나요?
메서드가 자신이 속한 객체의 프로퍼티를 참조하려면 먼저 자신이 속한 객체를 가리키는 식별자를 참조할 수 있어야 한다. this는 자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수다. this를 통해 자신이 속한 객체 또는 자신이 생성할 인스턴스의 프로퍼티나 메서드를 참조할 수 있다. this가 가리키는 값, 즉 this 바인딩은 함수 호출 방식에 의해 동적으로 결정된다.
// 객체 리터럴 const circle = { radius: 5, getDiameter() { // this는 메서드를 호출한 객체를 가리킨다. return 2 * this.radius; }, }; console.log(circle.getDiameter()); // 10
// 생성자 함수 function Circle(radius) { // this는 생성자 함수가 생성할 인스턴스를 가리킨다. this.radius = radius; } Circle.prototype.getDiameter = function () { // this는 생성자 함수가 생성할 인스턴스를 가리킨다. return 2 * this.radius; }; // 인스턴스 생성 const circle = new Circle(5); console.log(circle.getDiameter()); // 10
// this는 어디서든지 참조 가능하다. // 전역에서 this는 전역 객체 window를 가리킨다. console.log(this); // window function square(number) { // 일반 함수 내부에서 this는 전역 객체 window를 가리킨다. console.log(this); // window return number * number; } square(2); const person = { name: "Lee", getName() { // 메서드 내부에서 this는 메서드를 호출한 객체를 가리킨다. console.log(this); // {name: "Lee", getName: ƒ} return this.name; }, }; console.log(person.getName()); // Lee function Person(name) { this.name = name; // 생성자 함수 내부에서 this는 생성자 함수가 생성할 인스턴스를 가리킨다. console.log(this); // Person {name: "Lee"} } const me = new Person("Lee");
함수 호출 방식에 따라 this 바인딩이 결정된다.
1. 일반 함수 호출
기본적으로 this에는 전역 객체가 바인딩된다. 아래와 같이 일반 함수로 호출된 모든 함수(중첩함수, 콜백 함수 포함) 내부의 this에는 전역 객체가 바인딩된다.
function foo() { console.log("foo's this: ", this); // window function bar() { console.log("bar's this: ", this); // window } bar(); } foo();
// var 키워드로 선언한 전역 변수 value는 전역 객체의 프로퍼티다. var value = 1; // const 키워드로 선언한 전역 변수 value는 전역 객체의 프로퍼티가 아니다. // const value = 1; const obj = { value: 100, foo() { console.log("foo's this: ", this); // {value: 100, foo: ƒ} console.log("foo's this.value: ", this.value); // 100 // 메서드 내에서 정의한 중첩 함수 function bar() { console.log("bar's this: ", this); // window console.log("bar's this.value: ", this.value); // 1 } // 메서드 내에서 정의한 중첩 함수도 일반 함수로 호출되면 중첩 함수 내부의 this에는 전역 객체가 바인딩된다. bar(); } }; obj.foo();
2. 메서드 호출
메서드 내부의 this에는 메서드를 호출한 객체, 즉 메서드를 호출할 때 메서드 이름 앞의 마침표(.) 연산자 앞에 기술한 객체가 바인딩된다. 주의할 것은 메서드 내부의 this는 메서드를 소유한 객체가 아닌 메서드를 호출한 객체에 바인딩된다는 것이다.
const person = { name: "Lee", getName() { // 메서드 내부의 this는 메서드를 호출한 객체에 바인딩된다. return this.name; }, }; // 메서드 getName을 호출한 객체는 person이다. console.log(person.getName()); // Lee const anotherPerson = { name: "Kim", }; // getName 메서드를 anotherPerson 객체의 메서드로 할당 anotherPerson.getName = person.getName; // getName 메서드를 호출한 객체는 anotherPerson이다. console.log(anotherPerson.getName()); // Kim // getName 메서드를 변수에 할당 const getName = person.getName; // getName 메서드를 일반 함수로 호출 console.log(getName()); // '' // 일반 함수로 호출된 getName 함수 내부의 this.name은 브라우저 환경에서 window.name과 같다. // 브라우저 환경에서 window.name은 브라우저 창의 이름을 나타내는 빌트인 프로퍼티이며 기본값은 ''이다. // Node.js 환경에서 this.name은 undefined다.
3. 생성자 함수 호출
생성자 함수 내부의 this에는 생성자 함수가 (미래에) 생성할 인스턴스가 바인딩된다.
// 생성자 함수 function Circle(radius) { // 생성자 함수 내부의 this는 생성자 함수가 생성할 인스턴스를 가리킨다. this.radius = radius; this.getDiameter = function () { return 2 * this.radius; }; } // 반지름이 5인 Circle 객체를 생성 const circle1 = new Circle(5); // 반지름이 10인 Circle 객체를 생성 const circle2 = new Circle(10); console.log(circle1.getDiameter()); // 10 console.log(circle2.getDiameter()); // 20 // new 연산자와 함께 호출하지 않으면 생성자 함수로 동작하지 않는다. 즉, 일반적인 함수의 호출이다. const circle3 = Circle(15); // 일반 함수로 호출된 Circle에는 반환문이 없으므로 암묵적으로 undefined를 반환한다. console.log(circle3); // undefined // 일반 함수로 호출된 Circle 내부의 this는 전역 객체를 가리킨다. console.log(radius); // 15
'JavaScript > 모던 자바스크립트 딥다이브' 카테고리의 다른 글
[모던 자바스크립트 딥다이브] 19장 프로토타입 (0) 2022.12.02 [모던 자바스크립트 딥다이브] 15장 let, const 키워드와 블록 레벨 스코프 (0) 2022.11.26 [모던 자바스크립트 딥다이브] 13장 스코프 (0) 2022.11.26