객체는 일반적으로 사용자, 주문 등과 같은 실제 세계의 엔터티를 나타내기 위해 생성됩니다.
사용자 = { 이름: "존", 나이: 30 };
그리고 현실 세계에서 사용자는 장바구니에서 항목 선택, 로그인, 로그아웃 등의 작업을 수행 할 수 있습니다.
작업은 JavaScript에서 속성의 함수로 표현됩니다.
먼저 user
인사하는 방법을 가르쳐 보겠습니다.
사용자 = { 이름: "존", 나이: 30 }; user.sayHi = 함수() { Alert("안녕하세요!"); }; user.sayHi(); // 안녕하세요!
여기서는 함수 표현식을 사용하여 함수를 생성하고 이를 개체의 user.sayHi
속성에 할당했습니다.
그런 다음 user.sayHi()
로 호출할 수 있습니다. 이제 사용자가 말할 수 있습니다!
객체의 속성인 함수를 메소드 라고 합니다.
여기에 user
객체의 sayHi
메소드가 있습니다.
물론, 다음과 같이 미리 선언된 함수를 메서드로 사용할 수도 있습니다.
사용자 = { // ... }; // 먼저 선언합니다. 함수 sayHi() { Alert("안녕하세요!"); } // 메소드로 추가 user.sayHi = 말안녕; user.sayHi(); // 안녕하세요!
객체 지향 프로그래밍
엔터티를 표현하기 위해 객체를 사용하여 코드를 작성하는 것을 객체 지향 프로그래밍, 줄여서 "OOP"라고 합니다.
OOP는 그 자체로 흥미로운 과학입니다. 올바른 엔터티를 선택하는 방법은 무엇입니까? 그들 사이의 상호 작용을 구성하는 방법은 무엇입니까? 이것이 바로 아키텍처이며, E. Gamma, R. Helm, R. Johnson, J. Vissides의 "Design Patterns: Elements of Reusable Object-Oriented Software" 또는 "Object-Oriented Analysis and Design with 응용 프로그램”, G. Booch 등.
객체 리터럴의 메소드에 대해 더 짧은 구문이 있습니다.
// 이 객체들은 같은 일을 합니다 사용자 = { sayHi: function() { Alert("안녕하세요"); } }; // 메소드 단축이 더 좋아보이죠? 사용자 = { sayHi() { // "sayHi: function(){...}"과 동일 Alert("안녕하세요"); } };
설명했듯이 "function"
생략하고 sayHi()
만 작성할 수 있습니다.
사실을 말하자면, 표기법은 완전히 동일하지 않습니다. 객체 상속과 관련하여 미묘한 차이가 있지만(나중에 다루겠습니다) 지금은 중요하지 않습니다. 거의 모든 경우에 더 짧은 구문이 선호됩니다.
객체 메서드가 해당 작업을 수행하기 위해 객체에 저장된 정보에 액세스해야 하는 것이 일반적입니다.
예를 들어, user.sayHi()
내부의 코드에는 user
의 이름이 필요할 수 있습니다.
개체에 액세스하려면 메서드에서 this
키워드를 사용할 수 있습니다.
this
값은 메서드를 호출하는 데 사용되는 "점 앞의" 개체입니다.
예를 들어:
사용자 = { 이름: "존", 나이: 30, 안녕하세요() { // "this"는 "현재 객체"입니다. 경고(this.name); } }; user.sayHi(); // 존
여기서 user.sayHi()
를 실행하는 동안 this
값은 user
됩니다.
기술적으로 this
없이 외부 변수를 통해 객체를 참조하여 객체에 액세스하는 것도 가능합니다.
사용자 = { 이름: "존", 나이: 30, 안녕하세요() { 경고(사용자.이름); // "this" 대신 "user" } };
…그러나 그러한 코드는 신뢰할 수 없습니다. user
다른 변수(예: admin = user
에 복사하고 user
다른 변수로 덮어쓰기로 결정하면 잘못된 개체에 액세스하게 됩니다.
아래에 설명되어 있습니다.
사용자 = { 이름: "존", 나이: 30, 안녕하세요() { 경고(사용자.이름); // 오류가 발생합니다. } }; 관리자 = 사용자로 두십시오. 사용자 = null; // 명확하게 하기 위해 덮어쓰기 admin.sayHi(); // TypeError: null의 'name' 속성을 읽을 수 없습니다.
alert
내에서 user.name
대신 this.name
사용하면 코드가 작동합니다.
JavaScript에서 키워드 this
대부분의 다른 프로그래밍 언어와 다르게 동작합니다. 객체의 메서드가 아니더라도 모든 함수에서 사용할 수 있습니다.
다음 예에는 구문 오류가 없습니다.
함수 sayHi() { 경고(this.name); }
this
값은 컨텍스트에 따라 런타임 중에 평가됩니다.
예를 들어, 여기에서는 동일한 함수가 두 개의 서로 다른 객체에 할당되고 호출에서 서로 다른 "this"가 있습니다.
사용자 = { 이름: "John" }; let admin = { 이름: "관리자" }; 함수 sayHi() { 경고(this.name); } // 두 객체에 동일한 함수를 사용합니다. user.f = 안녕하세요; admin.f = 안녕하세요; // 이 호출은 다릅니다. // 함수 내부의 "this"는 "점 앞의" 객체입니다. user.f(); // John (이 == 사용자) admin.f(); // 관리자(이것은 == 관리자) 관리자['f'](); // 관리(점 또는 대괄호가 메소드에 액세스함 - 중요하지 않음)
규칙은 간단합니다. obj.f()
호출되면 f
호출하는 동안 this
obj
입니다. 따라서 위 예에서는 user
또는 admin
입니다.
객체 없이 호출: this == undefined
객체 없이 함수를 호출할 수도 있습니다.
함수 sayHi() { 경고(이); } 안녕하세요(); // 한정되지 않은
이 경우 엄격 모드에서는 undefined
this
this.name
에 액세스하려고 하면 오류가 발생합니다.
엄격하지 않은 모드에서 this
값은 전역 개체 (브라우저의 window
, 나중에 전역 개체 장에서 설명)가 됩니다. 이는 "use strict"
역사적 동작입니다.
일반적으로 이러한 호출은 프로그래밍 오류입니다. 함수 내부에 this
있으면 객체 컨텍스트에서 호출될 것으로 예상됩니다.
this
해제된 결과
다른 프로그래밍 언어를 사용했다면 객체에 정의된 메서드가 항상 해당 객체를 참조하는 this
갖는 "bound this
" 개념에 익숙할 것입니다.
JavaScript에서 this
"무료"이며 해당 값은 호출 시 평가되며 메서드가 선언된 위치가 아니라 "점 앞에" 있는 객체에 따라 달라집니다.
this
평가한 런타임 개념에는 장점과 단점이 모두 있습니다. 한편으로 함수는 다른 객체에 재사용될 수 있습니다. 반면에 유연성이 높을수록 실수할 가능성이 더 커집니다.
여기서 우리의 입장은 이 언어 디자인 결정이 좋은지 나쁜지를 판단하는 것이 아닙니다. 우리는 그것으로 작업하는 방법, 혜택을 얻고 문제를 피하는 방법을 이해할 것입니다.
화살표 함수는 특별합니다. "자신의" this
없습니다. 이러한 함수에서 this
참조하는 경우 외부 "일반" 함수에서 가져온 것입니다.
예를 들어, 여기서 arrow()
는 외부 user.sayHi()
메서드에서 this
사용합니다.
사용자 = { firstName: "일리아", 안녕하세요() { 화살표 = () => 경고(this.firstName); 화살(); } }; user.sayHi(); // 일리아
이는 화살표 함수의 특별한 기능으로, 실제로 별도의 this
원하지 않고 외부 컨텍스트에서 가져오고 싶을 때 유용합니다. 나중에 화살표 함수를 다시 살펴보는 장에서 화살표 함수에 대해 더 자세히 살펴보겠습니다.
객체 속성에 저장된 함수를 "메서드"라고 합니다.
메소드를 사용하면 객체가 object.doSomething()
처럼 "작동"할 수 있습니다.
메소드는 객체를 this
로 참조할 수 있습니다.
this
값은 런타임에 정의됩니다.
함수가 선언되면 this
사용할 수 있지만 함수가 호출될 때까지는 this
에 값이 없습니다.
객체 간에 함수를 복사할 수 있습니다.
"메서드" 구문인 object.method()
에서 함수가 호출되면 호출 중 this
값은 object
입니다.
화살표 함수는 특별하다는 점에 유의하세요. 이 함수에는 this
없습니다. 화살표 함수 내에서 this
액세스하면 외부에서 가져옵니다.
중요도: 5
여기서 makeUser
함수는 객체를 반환합니다.
ref
에 액세스한 결과는 무엇입니까? 왜?
함수 makeUser() { 반품 { 이름: "존", 참조: 이 }; } 사용자 = makeUser()를 보자; 경고(user.ref.name); // 결과는 무엇입니까?
답변: 오류입니다.
시도해 보세요:
함수 makeUser() { 반품 { 이름: "존", 참조: 이 }; } 사용자 = makeUser()를 보자; 경고( user.ref.name ); // 오류: 정의되지 않은 'name' 속성을 읽을 수 없습니다.
이는 this
설정하는 규칙이 객체 정의를 확인하지 않기 때문입니다. 통화하는 순간만이 중요합니다.
여기서 makeUser()
내부의 this
값은 "점" 구문을 사용하는 메서드가 아닌 함수로 호출되기 때문에 undefined
.
this
값은 전체 함수에 대한 값이며 코드 블록 및 객체 리터럴은 영향을 미치지 않습니다.
따라서 ref: this
실제로 함수의 현재 this
사용합니다.
함수를 다시 작성하고 undefined
값으로 동일한 this
반환할 수 있습니다.
함수 makeUser(){ 이거 돌려줘; // 이번에는 객체 리터럴이 없습니다. } 경고( makeUser().name ); // 오류: 정의되지 않은 'name' 속성을 읽을 수 없습니다.
보시 alert( makeUser().name )
의 결과는 이전 예제의 alert( user.ref.name )
결과와 동일합니다.
반대의 경우는 다음과 같습니다.
함수 makeUser() { 반품 { 이름: "존", 심판() { 이거 돌려줘; } }; } 사용자 = makeUser()를 보자; 경고( user.ref().name ); // 존
이제 user.ref()
가 메소드이기 때문에 작동합니다. 그리고 this
의 값은 dot 앞의 객체로 설정됩니다 .
.
중요도: 5
세 가지 방법으로 개체 calculator
만듭니다.
read()
두 개의 값을 입력하라는 메시지를 표시하고 이를 각각 이름이 a
와 b
인 개체 속성으로 저장합니다.
sum()
저장된 값의 합계를 반환합니다.
mul()
저장된 값을 곱하고 그 결과를 반환합니다.
계산기 = { // ... 귀하의 코드 ... }; 계산기.read(); 경고(계산기.sum()); 경고(계산기.mul());
데모 실행
테스트를 통해 샌드박스를 엽니다.
계산기 = { 합계() { this.a + this.b를 반환합니다. }, 멀() { return this.a * this.b; }, 읽다() { this.a = +prompt('a?', 0); this.b = +prompt('b?', 0); } }; 계산기.read(); 경고(계산기.sum()); 경고(계산기.mul());
샌드박스에서 테스트를 통해 솔루션을 엽니다.
중요도: 2
위아래로 이동할 수 있는 ladder
개체가 있습니다.
사다리 = { 단계: 0, 위로() { this.step++; }, 아래에() { this.step--; }, showStep: function() { // 현재 단계를 표시합니다. 경고(this.step); } };
이제 여러 호출을 순서대로 수행해야 하는 경우 다음과 같이 수행할 수 있습니다.
사다리.업(); 사다리.업(); ladder.down(); ladder.showStep(); // 1 ladder.down(); ladder.showStep(); // 0
다음과 같이 호출을 연결 가능하게 만들기 위해 up
, down
및 showStep
의 코드를 수정합니다.
ladder.up().up().down().showStep().down().showStep(); // 1을 표시한 다음 0을 표시합니다.
이러한 접근 방식은 JavaScript 라이브러리 전체에서 널리 사용됩니다.
테스트를 통해 샌드박스를 엽니다.
해결책은 모든 호출에서 객체 자체를 반환하는 것입니다.
사다리 = { 단계: 0, 위로() { this.step++; 이거 돌려줘; }, 아래에() { this.step--; 이거 돌려줘; }, 쇼스텝() { 경고(this.step); 이거 돌려줘; } }; ladder.up().up().down().showStep().down().showStep(); // 1을 표시한 다음 0을 표시합니다.
한 줄에 단일 호출을 작성할 수도 있습니다. 긴 체인의 경우 더 읽기 쉽습니다.
사다리 .위로() .위로() .아래에() .showStep() // 1 .아래에() .showStep(); // 0
샌드박스에서 테스트를 통해 솔루션을 엽니다.