09. Функции. Часть 3. Конструкторы

Контрольные задания

  1. Испытательный стенд Создать класс Cylinder для работы с цилиндрами.

    
    // Конструктор 
    function Cylinder(radius, height)
    {
      // Свойства экземпляра класса
      ...
    }
    
    // Методы экземпляра класса
    // Метод volume -- возвращает объём цилиндра
    ...
    
    // Свойства класса
    // Число пи
    ...
    
    // Методы класса
    // Метод maxVolume принимает два объекта Cylinder и возвращает  
    // ссылку на объект с большим объёмом.
    ...
    
    // Тестирование
    // ------------
    alert(Cylinder.PI); // 3.14159
    var cyl1 = new Cylinder(10,20);
    var cyl2 = new Cylinder(20,10);
    alert(cyl1.volume()); // 6283.18  -- объём первого цилиндра
    alert(cyl2.volume()); // 12566.36 -- объём второго цилиндра
    // Показать радиус цилиндра с наибольшим объёмом
    alert(Cylinder.maxVolume(cyl1,cyl2).radius); // 20
    
    Решение

    praxis/09/jobs/01/test.htm

    
    // Конструктор 
    function Cylinder(radius, height)
    {
      // Свойства экземпляра класса
      this.radius = radius;
      this.height = height;
    }
    // Методы экземпляра класса
    // Метод volume -- возвращает объём цилиндра
    Cylinder.prototype.volume = function ()
    {
      return Cylinder.PI*this.radius*this.radius*this.height; 
    }
    
    // Свойства класса
    // Число пи
    Cylinder.PI = 3.14159;
    
    // Методы класса
    // Метод maxVolume принимает два объекта Cylinder и возвращает  
    // ссылку на объект с большим объёмом.
    Cylinder.maxVolume = function (x,y)
    {
      return x.volume() > y.volume() ? x : y; 
    };
    // Тестирование
    // ------------
    alert(Cylinder.PI); // 3.14159
    var cyl1 = new Cylinder(10,20);
    var cyl2 = new Cylinder(20,10);
    alert(cyl1.volume()); // 6283.18  -- объём первого цилиндра
    alert(cyl2.volume()); // 12566.36 -- объём второго цилиндра
    // Показать радиус цилиндра с наибольшим объёмом
    alert(Cylinder.maxVolume(cyl1,cyl2).radius); // 20
    
  2. Испытательный стенд Создать три класса:

    • Point — для работы с точками
    • Rectangle — для работы с прямоугольниками
    • Button — для работы с «кнопками» — прямоугольными областями в окне браузера

    Класс Point — базовый. Класс Rectangle опирается на класс Point, а класс Button — на класс Rectangle.

    При создании классов руководствуйтесь комментариями, которыми снабжены заготовки конструкций. После заполнения пустых мест в следующем ниже коде, сохраните код в виде файла index.htm и загрузите его в браузер для проведения тестовых испытаний (уже написанных в коде).

    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
      "http://www.w3.org/TR/html4/loose.dtd">
    <HTML lang="ru">
      <HEAD>
        <META http-equiv="content-type" 
              content="text/html; charset=windows-1251">
        <TITLE>Работа с кнопками</TITLE>
        <SCRIPT>
    //--------------------------------------------------------------------
    // Здесь описаны классы Точка (Point), Прямоугольник (Rectangle) 
    // и Кнопка (Button)
    // Последний класс служит для вывода прямоугольных областей в  
    // произвольные места окна браузера.
    //--------------------------------------------------------------------
    
    // Начало описания класса Point --------------------------------------
    // Конструктор класса Точка 
    // Объекты класса Точка представляют собой точку на экране 
    // в декартовой системе координат (x,y). Точка с координатами (0,0)
    // расположена в верхнем левом углу. Координата x увеличивается 
    // горизонтально вправо, координата y увеличивается вертикально вниз.
    // 
    function Point(x, y)
    {
     ...
    }
    
    // Сложение точек (сложение соответствующих координат). 
    // Результат сохраняется в текущей точке.
    // Текущая точка this складывается с точкой-аргументом.
    // Метод не возвращает никакого значения. 
    Point.prototype.add = function (p)
    {
     ...
    }
    
    // Вычитание точек (вычитание соответствующих координат).
    // Результат сохраняется в текущей точке.
    // От текущей точки this вычитается точка-аргумент. 
    // Метод не возвращает никакого значения. 
    Point.prototype.sub = function (p)
    {
     ...
    }
      
    // Равенство точек. 
    // Текущая точка this сравнивается с точкой-аргументом 
    // Метод возвращает true, если точки совпадают.  
    Point.prototype.isEq = function (p)
    {
     ...
    }
    // Конец описания класса Point ---------------------------------------
    
    // Начало описания класса Rectangle ----------------------------------
    // Конструктор класса Прямоугольник
    // Объект класса Прямоугольник представляют собой прямоугольник, 
    // заданный двумя точками p1 и p2. 
    // Точка p1 задает верхний левый угол прямоугольника.
    // Точка p2 задает нижний правый угол прямоугольника.
    function Rectangle(p1,p2)
    {
     ...
    }
    
    // Вернуть ширину прямоугольника
    Rectangle.prototype.getWidth = function ()
    {
     ...
    }
    
    // Вернуть высоту прямоугольника
    Rectangle.prototype.getHeight = function ()
    {
     ...
    }
    
    // Вернуть новый прямоугольник -- копию данного
    Rectangle.prototype.copy = function ()
    {
     ...
    }
    
    // Переместить прямоугольник на указанные смещения
    Rectangle.prototype.move = function (dx, dy)
    {
     ...
    }
    
    // Переместить прямоугольник в точку p так, чтобы его верхний 
    // левый угол оказалcя в заданной точке.
    Rectangle.prototype.moveToPoint = function (p)
    {
     ...
    }
    
    // Расширить прямоугольник на указанные величины по всем осям
    // в обоих направлениях
    Rectangle.prototype.grow = function (dx, dy)
    {
     ...
    }
    
    // Пересечение прямоугольников. Получить прямоугольник,
    // который является пересечением текущего прямоугольника и 
    // прямоугольника-аргумента.
    // Результат сохраняется в текущем прямоугольнике.
    Rectangle.prototype.intersect = function (r)
    {
     ...
    }
    
    // Пересечение прямоугольников. Получить прямоугольник,
    // который является пересечением текущего прямоугольника и 
    // прямоугольника-аргумента.
    // Результат вернуть в качестве нового прямоугольника
    Rectangle.prototype.intersectNew = function (r)
    {
     ...
    }
    
    // Объединение прямоугольников. Получить прямоугольник,
    // который описан вокруг двух фигур: текущего прямоугольника, и 
    // прямоугольника-аргумента.
    // Результат сохраняется в текущем прямоугольнике.
    Rectangle.prototype.union = function (r)
    {
     ...
    }
    
    // Объединение прямоугольников. Получить прямоугольник,
    // который описан вокруг двух фигур: текущего прямоугольника, и 
    // прямоугольника-аргумента.
    // Результат вернуть в качестве нового прямоугольника
    Rectangle.prototype.unionNew = function (r)
    {
     ...
    }
    
    // Содержится ли точка p в текущем прямоугольнике?
    Rectangle.prototype.contains = function (p)
    {
     ...
    }
    
    // Вырожден ли прямоугольник?
    // Прямоугольник вырожден, если первая точка правее или ниже второй,
    // а также в случае, если точки совпадают. 
    Rectangle.prototype.isEmpty = function ()
    {
     ...
    }
    // Конец описания класса Rectangle ----------------------------------
    
    // Начало описания класса Button -------------------------------------
    // Кнопка на экране
    // Конструктор класса Button
    // Объект класса Button представляют собой закрашенный прямоугольник 
    // с рамкой и надписью внутри
    // Аргументы конструктора:
    // r -- объект-прямоугольник (обязательный параметр)
    // title        -- надпись на кнопке, пустая строка, если аргумента нет
    // fon_color    -- цвет фона кнопки, белый, если аргумент отсутствует 
    // border_color -- цвет рамки, чёрный, если аргумент отсутствует 
    function Button(r, title, fon_color, border_color)
    {
      this.r = ...
      this.title = ...
      this.fon_color = ...
      this.border_color = ...
    
      // Создадим элемент DIV
      // Метод createElement объекта document создаёт элемент,
      // название которого задано аргументом метода
      this.elementHTML = document.createElement("div");
      // Добавим к созданному элементу потомка -- текстовый элемент 
      this.elementHTML.appendChild(document.createTextNode(this.title));
      // Создадим нужные стили для блока DIV
      // Доступ к стилям через свойство style элемента
      this.elementHTML.style.position = "absolute";  
      this.elementHTML.style.left    = this.r.p1.x+"px";
      this.elementHTML.style.top     = this.r.p1.y+"px";
      this.elementHTML.style.width   = this.r.getWidth()+"px";
      this.elementHTML.style.height  = this.r.getHeight()+"px";
      this.elementHTML.style.backgroundColor = this.fon_color;
      this.elementHTML.style.border = "1px solid " + this.border_color;
      this.elementHTML.style.textAlign = "center";
      this.elementHTML.style.font = "icon";
    }
    //  Отобразить Кнопку на экране
    Button.prototype.draw = function ()
    {
      // Добавим элемент потомок к BODY -- и он сразу 
      // отобразится на экране
      document.body.appendChild(this.elementHTML);
    }
    
    // Сместить кнопку на (dx, dy)
    Button.prototype.move = function (dx, dy)
    {
      this.r.move(dx,dy);
      this.elementHTML.style.left = this.r.p1.x+"px";
      this.elementHTML.style.top  = this.r.p1.y+"px";
    }
    // Конец описания класса Button -------------------------------------
    
    // -------------------------------------------------------------------
    // Создадим обработчик события onload ("окончание загрузки документа") 
    // В качестве обработчика этого события задается функциональный литерал,
    // который будет запущен на выполнение один раз после того как наступит 
    // событие "текущий HTML-документ полностью загружен в браузер" 
    // -------------------------------------------------------------------
    window.onload = function()
    {
      //  Создаём первую кнопку
      var button1 = new Button (
          new Rectangle(new Point(100,100), new Point(200,140)), 
          "Кнопка","#ffbf00"
                               );
          
      //  Создаём вторую кнопку
      var button2 = new Button (
          new Rectangle(new Point(250,100), new Point(500,150)), 
          "Очень большая кнопка", "#40ff00", "blue"
                               );
      //  Показываем созданные кнопки на экране
      button1.draw();
      button2.draw();
    
      alert("Покажем массив кнопок"); 
    
      // Готовимся к созданию массива кнопок
      var  n = 10;            // Число кнопок в массиве
      var  b = new Array(n);  // Массив для n кнопок
      var x0 = 0, y0 = 200;   // Начальное положение первой кнопки на экране
      var w  = 80, h = 30;    // Ширина и высота каждой кнопки
      // Создадим массив кнопок и покажем их на экране
      for (var i=0; i<b.length; i++)
      {
        // Создадим кнопку...
        b[i] = new Button (
          new Rectangle(new Point(x0+i*w,y0), new Point(x0+i*w + w,y0+h)), 
          "Кнопка "+ i, "rgb("+Number(250-i*25)+","+i*25+","+i*25+")");
        // и тут же ее покажем 
        b[i].draw();
      }
      
      alert("Сместим кнопку 1 на 50 пикселов вверх"); 
      b[1].move(0, -50);
    
      alert("Сместим кнопку 3 на 50 пикселов вниз"); 
      b[3].move(0, 50);
    
      alert("Сместим кнопку 5 на 20 пикселов влево и вверх"); 
      b[5].move(-20, 20);
    
      alert("Проверим, есть ли пересечение кнопки 5 с кнопкой 4"); 
      alert(!(b[5].r.intersectNew(b[4].r).isEmpty()));
    
      alert("Проверим, есть ли пересечение кнопки 5 с кнопкой 3"); 
      alert(!(b[5].r.intersectNew(b[3].r).isEmpty()));
    };  
        </SCRIPT>
      </HEAD>               
      <BODY>
        <H1>Работа с кнопками</H1>
      </BODY>
    </HTML>
    
    Решение

    praxis/09/jobs/02/index.htm

    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
      "http://www.w3.org/TR/html4/loose.dtd">
    <HTML lang="ru">
      <HEAD>
        <META http-equiv="content-type" 
              content="text/html; charset=windows-1251">
        <TITLE>Работа с кнопками</TITLE>
        <SCRIPT>
    //--------------------------------------------------------------------
    // Здесь описаны классы Точка (Point), Прямоугольник (Rectangle) 
    // и Кнопка (Button)
    // Последний класс служит для вывода прямоугольных областей в  
    // произвольные места окна браузера.
    //--------------------------------------------------------------------
    
    // Начало описания класса Point --------------------------------------
    // Конструктор класса Точка 
    // Объекты класса Точка представляют собой точку на экране 
    // в декартовой системе координат (x,y). Точка с координатами (0,0)
    // расположена в верхнем левом углу. Координата x увеличивается 
    // горизонтально вправо, координата y увеличивается вертикально вниз.
    // 
    function Point(x, y)
    {
      this.x = x;
      this.y = y;
    }
    
    // Сложение точек (сложение соответствующих координат). 
    // Результат сохраняется в текущей точке.
    // Текущая точка this складывается с точкой-аргументом.
    // Метод не возвращает никакого значения. 
    Point.prototype.add = function (p)
    {
      this.x += p.x;
      this.y += p.y;
    }
    
    // Вычитание точек (вычитание соответствующих координат).
    // Результат сохраняется в текущей точке.
    // От текущей точки this вычитается точка-аргумент. 
    // Метод не возвращает никакого значения. 
    Point.prototype.sub = function (p)
    {
      this.x -= p.x;
      this.y -= p.y;
    }
      
    // Равенство точек. 
    // Текущая точка this сравнивается с точкой-аргументом 
    // Метод возвращает true, если точки совпадают.  
    Point.prototype.isEq = function (p)
    {
      return (this.x == p.x) && (this.y == p.y);
    }
    // Конец описания класса Point ---------------------------------------
    
    // Начало описания класса Rectangle ----------------------------------
    // Конструктор класса Прямоугольник
    // Объект класса Прямоугольник представляют собой прямоугольник, 
    // заданный двумя точками p1 и p2. 
    // Точка p1 задает верхний левый угол прямоугольника.
    // Точка p2 задает нижний правый угол прямоугольника.
    function Rectangle(p1,p2)
    {
      this.p1 = new Point(p1.x,p1.y); 
      this.p2 = new Point(p2.x,p2.y); 
    }
    
    // Вернуть ширину прямоугольника
    Rectangle.prototype.getWidth = function ()
    {
      return this.p2.x - this.p1.x;
    }
    
    // Вернуть высоту прямоугольника
    Rectangle.prototype.getHeight = function ()
    {
      return this.p2.y - this.p1.y;
    }
    
    // Вернуть новый прямоугольник -- копию данного
    Rectangle.prototype.copy = function ()
    {
      return new Rectangle(this.p1, this.p2);
    }
    
    // Переместить прямоугольник на указанные смещения
    Rectangle.prototype.move = function (dx, dy)
    {
      this.p1.x += dx;
      this.p1.y += dy;
      this.p2.x += dx;
      this.p2.y += dy;
    }
    
    // Переместить прямоугольник в точку p так, чтобы его верхний 
    // левый угол оказалcя в заданной точке.
    Rectangle.prototype.moveToPoint = function (p)
    {
      var w = this.getWidth();
      var h = this.getHeight(); 
      this.p1.x = p.x;
      this.p1.y = p.y;
      this.p2.x = p.x + w;
      this.p2.y = p.y + h;
    }
    
    // Расширить прямоугольник на указанные величины по всем осям
    // в обоих направлениях
    Rectangle.prototype.grow = function (dx, dy)
    {
      this.p1.x -= dx;
      this.p1.y -= dy;
      this.p2.x += dx;
      this.p2.y += dy;
    }
    
    // Пересечение прямоугольников. Получить прямоугольник,
    // который является пересечением текущего прямоугольника и 
    // прямоугольника-аргумента.
    // Результат сохраняется в текущем прямоугольнике.
    Rectangle.prototype.intersect = function (r)
    {
      this.p1.x = Math.max(this.p1.x,r.p1.x);
      this.p1.y = Math.max(this.p1.y,r.p1.y);
      this.p2.x = Math.min(this.p2.x,r.p2.x);
      this.p2.y = Math.min(this.p2.y,r.p2.y);
    }
    
    // Пересечение прямоугольников. Получить прямоугольник,
    // который является пересечением текущего прямоугольника и 
    // прямоугольника-аргумента.
    // Результат вернуть в качестве нового прямоугольника
    Rectangle.prototype.intersectNew = function (r)
    {
      var rect = this.copy();
      rect.p1.x = Math.max(rect.p1.x,r.p1.x);
      rect.p1.y = Math.max(rect.p1.y,r.p1.y);
      rect.p2.x = Math.min(rect.p2.x,r.p2.x);
      rect.p2.y = Math.min(rect.p2.y,r.p2.y);
      return rect;
    }
    
    // Объединение прямоугольников. Получить прямоугольник,
    // который описан вокруг двух фигур: текущего прямоугольника, и 
    // прямоугольника-аргумента.
    // Результат сохраняется в текущем прямоугольнике.
    Rectangle.prototype.union = function (r)
    {
      this.p1.x = Math.min(this.p1.x,r.p1.x);
      this.p1.y = Math.min(this.p1.y,r.p1.y);
      this.p2.x = Math.max(this.p2.x,r.p2.x);
      this.p2.y = Math.max(this.p2.y,r.p2.y);
    }
    
    // Объединение прямоугольников. Получить прямоугольник,
    // который описан вокруг двух фигур: текущего прямоугольника, и 
    // прямоугольника-аргумента.
    // Результат вернуть в качестве нового прямоугольника
    Rectangle.prototype.unionNew = function (r)
    {
      var rect = this.copy();
      rect.p1.x = Math.min(rect.p1.x,r.p1.x);
      rect.p1.y = Math.min(rect.p1.y,r.p1.y);
      rect.p2.x = Math.max(rect.p2.x,r.p2.x);
      rect.p2.y = Math.max(rect.p2.y,r.p2.y);
      return rect;
    }
    
    // Содержится ли точка p в текущем прямоугольнике?
    Rectangle.prototype.contains = function (p)
    {
      return p.x >= this.p1.x && p.x <= this.p2.x &&
             p.y >= this.p1.y && p.y <= this.p2.y;
    }
    
    // Вырожден ли прямоугольник?
    // Прямоугольник вырожден, если первая точка правее или ниже второй,
    // а также в случае, если точки совпадают. 
    Rectangle.prototype.isEmpty = function ()
    {
      return this.p1.x >= this.p2.x  || this.p1.y >= this.p2.y;
    }
    // Конец описания класса Rectangle ----------------------------------
    
    
    // Начало описания класса Button -------------------------------------
    // Кнопка на экране
    // Конструктор класса Button
    // Объект класса Button представляют собой закрашенный прямоугольник 
    // с рамкой и надписью внутри
    // Аргументы конструктора:
    // r -- объект-прямоугольник (обязательный параметр)
    // title        -- надпись на кнопке, пустая строка, если аргумента нет
    // fon_color    -- цвет фона кнопки, белый, если аргумент отсутствует 
    // border_color -- цвет рамки, чёрный, если аргумент отсутствует 
    function Button(r, title, fon_color, border_color)
    {
      this.r = r;
      this.title = title || "";
      this.fon_color = fon_color || "white";
      this.border_color = border_color || "black";
      // Создадим элемент DIV
      // Метод createElement объекта document создаёт элемент,
      // название которого задано аргументом метода
      this.elementHTML = document.createElement("div");
      // Добавим к созданному элементу потомка -- текстовый элемент 
      this.elementHTML.appendChild(document.createTextNode(this.title));
      // Создадим нужные стили для блока DIV
      // Доступ к стилям через свойство style элемента
      this.elementHTML.style.position = "absolute";  
      this.elementHTML.style.left    = this.r.p1.x+"px";
      this.elementHTML.style.top     = this.r.p1.y+"px";
      this.elementHTML.style.width   = this.r.getWidth()+"px";
      this.elementHTML.style.height  = this.r.getHeight()+"px";
      this.elementHTML.style.backgroundColor = this.fon_color;
      this.elementHTML.style.border = "1px solid " + this.border_color;
      this.elementHTML.style.textAlign = "center";
      this.elementHTML.style.font = "icon";
    }
    //  Отобразить Кнопку на экране
    Button.prototype.draw = function ()
    {
      // Добавим элемент потомок к BODY -- и он сразу 
      // отобразится на экране
      document.body.appendChild(this.elementHTML);
    }
    
    // Сместить кнопку на (dx, dy)
    Button.prototype.move = function (dx, dy)
    {
      this.r.move(dx,dy);
      this.elementHTML.style.left = this.r.p1.x+"px";
      this.elementHTML.style.top  = this.r.p1.y+"px";
    }
    // Конец описания класса Button -------------------------------------
    
    // -------------------------------------------------------------------
    // Создадим обработчик события onload ("окончание загрузки документа") 
    // В качестве обработчика этого события задается функциональный литерал,
    // который будет запущен на выполнение один раз после того как наступит 
    // событие "текущий HTML-документ полностью загружен в браузер" 
    // -------------------------------------------------------------------
    window.onload = function()
    {
      //  Создаём первую кнопку
      var button1 = new Button (
          new Rectangle(new Point(100,100), new Point(200,140)), 
          "Кнопка","#ffbf00"
                               );
          
      //  Создаём вторую кнопку
      var button2 = new Button (
          new Rectangle(new Point(250,100), new Point(500,150)), 
          "Очень большая кнопка", "#40ff00", "blue"
                               );
      //  Показываем созданные кнопки на экране
      button1.draw();
      button2.draw();
    
      alert("Покажем массив кнопок"); 
    
      // Готовимся к созданию массива кнопок
      var  n = 10;            // Число кнопок в массиве
      var  b = new Array(n);  // Массив для n кнопок
      var x0 = 0, y0 = 200;   // Начальное положение первой кнопки на экране
      var w  = 80, h = 30;    // Ширина и высота каждой кнопки
      // Создадим массив кнопок и покажем их на экране
      for (var i=0; i<b.length; i++)
      {
        // Создадим кнопку...
        b[i] = new Button (
          new Rectangle(new Point(x0+i*w,y0), new Point(x0+i*w + w,y0+h)), 
          "Кнопка "+ i, "rgb("+Number(250-i*25)+","+i*25+","+i*25+")");
        // и тут же ее покажем 
        b[i].draw();
      }
      
      alert("Сместим кнопку 1 на 50 пикселов вверх"); 
      b[1].move(0, -50);
    
      alert("Сместим кнопку 3 на 50 пикселов вниз"); 
      b[3].move(0, 50);
    
      alert("Сместим кнопку 5 на 20 пикселов влево и вниз"); 
      b[5].move(-20, 20);
    
      alert("Проверим, есть ли пересечение кнопки 5 с кнопкой 4"); 
      alert(!(b[5].r.intersectNew(b[4].r).isEmpty()));
    
      alert("Проверим, есть ли пересечение кнопки 5 с кнопкой 3"); 
      alert(!(b[5].r.intersectNew(b[3].r).isEmpty()));
    };  
        </SCRIPT>
      </HEAD>               
      <BODY>
        <H1>Работа с кнопками</H1>
      </BODY>
    </HTML>