If you're seeing this message, it means we're having trouble loading external resources on our website.

웹 필터가 올바르게 작동하지 않으면 도메인 *. kastatic.org*.kasandbox.org이 차단되어 있는지 확인하세요.

주요 내용

버튼 객체형

재사용 가능하고 강력한 코드를 만드는 가장 좋은 방법 중 하나는 객체지향적 프로그래밍을 이용하는 것입니다. 특히 버튼과 같은 UI 컨트롤을 만드는 데 좋습니다. 객체지향적 프로그래밍에선 프로그램 세계를 특정 행동을 갖는 추상적인 객체들로 보고 그 추상적인 객체에 매개변수를 입력하여 구체적인 인스턴스로 만듭니다. JavaScript에서 이를 어떻게 구현하는지 기억이 나지 않는다면 여기를 클릭하여 복습하세요.
OOP(객체지향적 프로그래밍)를 이용하여 버튼을 만들려면 Button 객체형을 정의한 후 버튼을 그리고 마우스 클릭을 제어하는 것과 같은 메소드를 정의해야 합니다. 다음과 같이 코드를 작성할 수 있습니다:
var btn1 = new Button(...);
btn1.draw();

mouseClicked = function() {
  if (btn1.isMouseInside()) {
     println("Whoah, you clicked me!");
  }
}
지난 내용에서 작성했던 코드와 대조해 봅시다.
var btn1 = {...};
drawButton(btn1);

mouseClicked = function() {
  if (isMouseInside(btn1)) {
     println("Whoah, you clicked me!");
  }
}
매우 비슷합니다. 그렇죠? 그러나 큰 차이점이 있습니다. 모든 함수가 Button 객체형에서 정의되어 실제로 함수는 버튼에 속하게 됩니다. 이런 구조는 프로퍼티와 행동을 좀 더 엄격하게 연결시켜서 더 명확하고 재사용 가능한 코드가 되도록 합니다.
Button 객체형을 정의하기 위해 생성자로 시작합니다. 생성자는 설정 매개변수를 입력받아 객체 인스턴스의 프로퍼티를 설정하는 특별한 함수입니다.
먼저 x, y, 너비, 높이를 입력받는 생성자를 살펴봅시다.
var Button = function(x, y, width, height) {
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
};

var btn1 = new Button(100, 100, 150, 150);
이 코드도 작동하긴 하겠지만 더 좋은 방법은 개별 매개변수를 입력받는 대신 생성자가 환경설정(configuration) 객체를 입력받게 하는 것입니다.
var Button = function(config) {
    this.x = config.x;
    this.y = config.y;
    this.width = config.width;
    this.height = config.height;
    this.label = config.label;
};
환경설정 객체를 사용하는 것의 장점은 버튼을 만들때 생성자에 ( label 같은) 더 많은 매개변수를 계속 추가해도 각 매개변수가 무엇인지 알기 쉽다는 것입니다.
var btn1 = new Button({
    x: 100, y: 100,
    width: 150, height: 50,
    label: "Please click!"});
한 단계 더 갈 수도 있습니다. 대부분 버튼의 너비나 높이가 같다면 어떨까요? 모든 버튼에 대해 너비와 높이 매개변수를 계속해서 명시하지 않고 필요할 때에만 너비와 높이 매개변수를 명시해야 합니다. 프로퍼티가 실제로 환경설정 객체에 정의되었는지 여부를 생성자가 확인하고 그렇지 않으면 기본값을 설정하도록 할 수 있습니다. 다음과 같습니다:
var Button = function(config) {
    this.x = config.x || 0;
    this.y = config.y || 0;
    this.width = config.width || 150;
    this.height = config.height || 50;
    this.label = config.label || "Click";
};
이제 일부분의 프로퍼티만으로 버튼을 호출할 수 있습니다. 그 외 프로퍼티는 기본값으로 설정될 것이기 때문입니다:
var btn1 = new Button({x: 100, y: 100, label: "Please click!"});
왜 고작 생성자에 이런 노력을 쏟을까요? 나중에 보면 이해가 갈겁니다.
이제 생성자를 완성했으니 함수가 뭘 할지 정의해 볼까요? draw 메소드를 만들어 봅시다. 이것은 drawButton 함수와 동일한 코드가 될 것입니다. 하지만 이는 객체 프로토타입 자체에 정의되기 때문에 this로부터의 모든 프로퍼티를 가져올 겁니다.
Button.prototype.draw = function() {
    fill(0, 234, 255);
    rect(this.x, this.y, this.width, this.height, 5);
    fill(0, 0, 0);
    textSize(19);
    textAlign(LEFT, TOP);
    text(this.label, this.x+10, this.y+this.height/4);
};
일단 정의되면 다음과 같이 호출할 수 있습니다:
btn1.draw();
다음은 Button 객체를 이용하여 두 개의 버튼을 생성하는 프로그램입니다. 버튼 여러개를 생성하고 그리는 것이 얼마나 쉬운지 봅시다:
클릭을 처리하는 어려운 부분은 건너 뛰었습니다. Button 프로토타입에 유저가 특정 버튼의 내부, 즉 박스 안을 클릭하면 참값으로 인지하는 함수를 정의해 봅시다. 이도 마찬가지로 이전의 함수와 비슷하지만 들어온 객체 대신 this로부터의 모든 프로퍼티를 가져옵니다.
Button.prototype.isMouseInside = function() {
    return mouseX > this.x &&
           mouseX < (this.x + this.width) &&
           mouseY > this.y &&
           mouseY < (this.y + this.height);
};
이제 mouseClicked 함수 내부에서 그것을 사용할 수 있습니다:
mouseClicked = function() {
    if (btn1.isMouseInside()) {
        println("You made the right choice!");
    } else if (btn2.isMouseInside()) {
        println("Yay, you picked me!");
    }
};
밑에 있는 각 버튼을 직접 클릭해 보세요.
그러나 클릭 제어를 설정한 방법에 대해 불편한 점이 하나 있습니다. 객체지향적 프로그래밍의 요점은 객체에 관련된 모든 행동을 객체 내부에 묶고 프로퍼티를 이용하여 행동을 원하는 대로 바꾸는 것입니다. 그러나 mouseClicked 내부의 println 을 객체 외부에 나와 있는 것 처럼 일부의 행동이 객체 외부에 있습니다.
mouseClicked = function() {
    if (btn1.isMouseInside()) {
        println("You made the right choice!");
    } else if (btn2.isMouseInside()) {
        println("Yay, you picked me!");
    }
};
이러한 print 문은 생성자로 전달한 것과 마찬가지로 각 버튼에 더 나은 방법으로 연결해야 합니다. 지금 상황을 보면, 생성자 config에 메시지를 전달하고 handleMouseClick함수가 메시지를 출력하도록 할 수 있습니다.
var Button = function(config) {
    ...
    this.message = config.message || "Clicked!";
};

Button.prototype.handleMouseClick = function() {
    if (this.isMouseInside()) {
         println(this.message);
    }
};

var btn1 = new Button({
    x: 100,
    y: 100,
    label: "Please click!",
    message: "You made the right choice!"
});

mouseClicked = function() {
   btn1.handleMouseClick();
};
이게 훨씬 더 좋습니다. 이제는 각 버튼의 특정 행동과 연관된 모든 것이 생성자에 묶여 있기 때문입니다. 그러나 지나치게 간단하기도 합니다. 메시지를 출력하는 것 말고 도형을 몇 개 그린다거나 장면을 바꾸는 등 코드를 꽤 써야 하는 것들을 하고 싶다면 어떻게 해야 할까요? 이 경우 생성자에 한 문자열보다 많은 여러 줄의 코드를 제공해야 합니다. 여러 줄의 코드를 어떻게 전달할 수 있을까요?
...바로 함수를 이용합니다! JavaScript(모든 언어가 그렇지는 않습니다) 안에서는 함수를 매개변수로 취급하여 다른 함수에 전달할 수 있습니다. 이는 많은 상황에서 유용하지만 특히 버튼과 같은 UI 컨트롤에 대한 행동을 정의할 때 유용합니다. 여러분은 버튼에게 "사용자가 버튼을 클릭할 때 여기 이 함수를 호출해"라고 알릴 수 있습니다. 그러한 함수를 "콜백(callback)"함수라고 합니다. 왜냐하면 이 함수는 즉시 호출되지 않고 나중에 적절한 시기에 "다시 호출 (콜백)"되기 때문입니다.
함수인 매개변수  onClick 을 전달해 봅시다.
var btn1 = new Button({
    x: 100,
    y: 100,
    label: "Please click!",
    onClick: function() {
       text("You made the right choice!", 100, 300);
    }
});
다음은 생성자에게 전달된 내용에 따라 onClick프로퍼티를 설정하도록 해야 합니다. onClick이 전달되지 않으면 기본값으로 "no-op" 함수를 생성합니다. 이 함수는 "아무런 연산을 수행하지(no operation)" 않습니다. no-op 함수는 에러가 일어나지 않게 하는 용도일 뿐입니다.
var Button = function(config) {
    // ...
    this.onClick = config.onClick || function() {};
};
마지막으로 사용자가 버튼을 클릭하면 실제로 콜백 함수를 다시 호출해야 합니다. 실제로 꽤 단순합니다. 단지 프로퍼티 이름 다음에 빈 괄호를 써 넣으면 함수를 호출합니다.
Button.prototype.handleMouseClick = function() {
    if (this.isMouseInside()) {
        this.onClick();
    }
};
이제 다 했습니다. 이제 새로운 버튼을 생성할 수 있는 Button 객체가 생겼습니다. 각 버튼을 다르게 보이도록 할 수 있고 클릭 이벤트에 다르게 반응하도록 만들 수 있게 되었어요. 아래 예제에서 버튼 매개변수를 수정했을 때 어떤 일이 발생하는지 확인해 보세요.
이제 템플릿이 생겼으니 버튼의 색을 바꿔 보거나 마우스가 지나가면 반응하는 것과 같이 다른 이벤트에 반응하도록 프로그램을 바꿔 보세요!

대화에 참여하고 싶으신가요?

  • 사용자 nlbo1103의 blobby green style 아바타
    This is so hard.!

    Button.prototype.isMouseInside=function(){
    return....}
    What does return do in the bottom line?
    (추천 1 번)
    사용자 의 Default Khan Academy avatar 아바타
    • 사용자 Inho Lee의 aqualine ultimate style 아바타
      return은 isMouseInside가 호출되었을 때 일정한 값을 되돌려 주게 됩니다. draw 함수와는 다르게 isMouseInside 함수의 경우는 다음과 같이 사용되고 있습니다.
      if (btn1.isMouseInside()) {
      ....
      }

      함수 내부에서 처리된 값을 true 혹은 false로 되돌려주어 if 조건문을 적절히 수행하기 위함입니다. 다음 두 수를 더하는 함수를 보시면 조금 더 이해하기 쉬울 것입니다. 이 함수는 정수 값을 돌려주도록 설계해 보겠습니다.
      var add_two = function(a, b) {
      return (a + b);
      }
      println(add_two(1, 2));
      (추천 2 번)
영어를 잘 하시나요? 그렇다면, 이곳을 클릭하여 미국 칸아카데미에서 어떠한 토론이 진행되고 있는지 둘러 보세요.