Статьи

Пересмотр основных объектов JavaScript

В моей недавней статье « String базовых объектов JavaScript» было показано, как представить новые свойства и методы базовых объектов JavaScript Array , Boolean , Date , Math , Number и String . Я следовал традиции других статей и постов в блогах, в том числе перечисленных ниже, которые показывают, как расширить эти основные объекты новыми возможностями:

Непосредственно при добавлении свойства основного объекта или его прототип, является спорным. В своем блоге, посвященном расширению JavaScript , Angus Croll рассматривает несколько проблем с этим подходом. Например, в будущих версиях браузера может быть реализовано эффективное свойство или метод, который перекрывается менее эффективным пользовательским свойством / методом. Прочитайте сообщение в блоге Croll для получения дополнительной информации по этой и другим проблемам

Поскольку расширение основных объектов является мощным и элегантным, должен быть способ использовать эту функцию, избегая ее проблем. К счастью, есть способ выполнить эту задачу, используя шаблон проектирования адаптера , который также известен как шаблон оболочки. В этой статье я представляю новую версию моей библиотеки, которая использует обертку для дополнения различных основных объектов, фактически не увеличивая их.

Изучение новой библиотеки дополнения базового объекта

Моя новая библиотека расширения основных объектов пытается минимизировать ее влияние на глобальное пространство имен, используя шаблон модуля JavaScript , который помещает весь код библиотеки в анонимное закрытие. В настоящее время эта библиотека экспортирует _Date и _Math которые обертываются вокруг Date и Math , и для доступа к ней используется ca_tutortutor_AJSCOLib глобальной переменной ca_tutortutor_AJSCOLib .

О ca_tutortutor_AJSCOLib
Глобальная переменная ca_tutortutor_AJSCOLib обеспечивает доступ к библиотеке дополнения. Чтобы свести к минимуму вероятность конфликта имен с другой глобальной переменной, я AJSCOLib префикс AJSCOLib к своему обратному доменному имени в Интернете.

В листинге 1 представлено содержимое моей библиотеки, которая хранится в ajscolib.js сценария ajscolib.js .

  var ca_tutortutor_AJSCOLib = 
    (Функция ()
    {
       var my = {};

       var _Date_ = Date;

       Функция _Date (год, месяц, дата, часы, минуты, секунды, мс)
       {
          если (год === не определено)
             this.instance = new _Date_ ();
          еще
          если (месяц === не определено)
             this.instance = new _Date_ (year);
          еще
          если (часов === не определено)
             this.instance = new _Date_ (год, месяц, дата);
          еще
             this.instance = new _Date_ (год, месяц, дата, часы, минуты, секунды, 
                                        Миз);

          this.copy = 
             Функция ()
             {
                вернуть новый _Date_ (this.instance.getTime ());
             };

          this.getDate =
             Функция ()
             {
                вернуть this.instance.getDate ();
             };

          this.getDay =
             Функция ()
             {
                вернуть this.instance.getDay ();
             };

          this.getFullYear =
             Функция ()
             {
                вернуть this.instance.getFullYear ();
             };

          this.getHours =
             Функция ()
             {
                вернуть this.instance.getHours ();
             };

          this.getMilliseconds =
             Функция ()
             {
                вернуть this.instance.getMilliseconds ();
             };

          this.getMinutes =
             Функция ()
             {
                вернуть this.instance.getMinutes ();
             };

          this.getMonth =
             Функция ()
             {
                вернуть this.instance.getMonth ();
             };

          this.getSeconds =
             Функция ()
             {
                вернуть this.instance.getSeconds ();
             };

          this.getTime =
             Функция ()
             {
                вернуть this.instance.getTime ();
             };

          this.getTimezoneOffset =
             Функция ()
             {
                return this.instance.getTimezoneOffset ();
             };

          this.getUTCDate =
             Функция ()
             {
                вернуть this.instance.getUTCDate ();
             };

          this.getUTCDay =
             Функция ()
             {
                вернуть this.instance.getUTCDay ();
             };

          this.getUTCFullYear =
             Функция ()
             {
                вернуть this.instance.getUTCFullYear ();
             };

          this.getUTCHours =
             Функция ()
             {
                вернуть this.instance.getUTCHours ();
             };

          this.getUTCMilliseconds =
             Функция ()
             {
                вернуть this.instance.getUTCMilliseconds ();
             };

          this.getUTCMinutes =
             Функция ()
             {
                вернуть this.instance.getUTCMinutes ();
             };

          this.getUTCMonth =
             Функция ()
             {
                вернуть this.instance.getUTCMonth ();
             };

          this.getUTCSeconds =
             Функция ()
             {
                вернуть this.instance.getUTCSeconds ();
             };

          this.getYear =
             Функция ()
             {
                вернуть this.instance.getYear ();
             };

          this.isLeap = 
             Функция ()
             {
                var year = this.instance.getFullYear ();
                доход (год% 400 == 0) ||  (год% 4 == 0 && год% 100! = 0);
             };

          _Date.isLeap =  
             Функция (дата)
             {
                if (date instanceof _Date)
                   date = date.instance;
                var year = date.getFullYear ();
                доход (год% 400 == 0) ||  (год% 4 == 0 && год% 100! = 0);
             };

          this.lastDay = 
             Функция ()
             {  
                вернуть новую _Date_ (this.instance.getFullYear (), 
                                  this.instance.getMonth () + 1, 0) .getDate ();
             };

          _Date.monthNames = ["Январь", "Февраль", "Март", "Апрель", "Май",
                              «Июнь», «июль», «август», «сентябрь», «октябрь»,
                              "Ноябрь декабрь"];

          _Date.parse =
             Функция (дата)
             {
                if (date instanceof _Date)
                   date = date.instance;
                return _Date_.parse (date);
             };

          this.setDate =
             Функция (дата)
             {
                if (date instanceof _Date)
                   date = date.instance;
                this.instance.setDate (дата);
             };

          this.setFullYear =
             Функция (дата)
             {
                if (date instanceof _Date)
                   date = date.instance;
                this.instance.setFullYear (дата);
             };

          this.setHours =
             Функция (дата)
             {
                if (date instanceof _Date)
                   date = date.instance;
                this.instance.setHours (дата);
             };

          this.setMilliseconds =
             Функция (дата)
             {
                if (date instanceof _Date)
                   date = date.instance;
                this.instance.setMilliseconds (дата);
             };

          this.setMinutes =
             Функция (дата)
             {
                if (date instanceof _Date)
                   date = date.instance;
                this.instance.setMinutes (дата);
             };

          this.setMonth =
             Функция (дата)
             {
                if (date instanceof _Date)
                   date = date.instance;
                this.instance.setMonth (дата);
             };

          this.setSeconds =
             Функция (дата)
             {
                if (date instanceof _Date)
                   date = date.instance;
                this.instance.setSeconds (дата);
             };

          this.setTime =
             Функция (дата)
             {
                if (date instanceof _Date)
                   date = date.instance;
                this.instance.setTime (дата);
             };

          this.setUTCDate =
             Функция (дата)
             {
                if (date instanceof _Date)
                   date = date.instance;
                this.instance.setUTCDate (дата);
             };

          this.setUTCFullYear =
             Функция (дата)
             {
                if (date instanceof _Date)
                   date = date.instance;
                this.instance.setUTCFullYear (дата);
             };

          this.setUTCHours =
             Функция (дата)
             {
                if (date instanceof _Date)
                   date = date.instance;
                this.instance.setUTCHours (дата);
             };

          this.setUTCMilliseconds =
             Функция (дата)
             {
                if (date instanceof _Date)
                   date = date.instance;
                this.instance.setUTCMilliseconds (дата);
             };

          this.setUTCMinutes =
             Функция (дата)
             {
                if (date instanceof _Date)
                   date = date.instance;
                this.instance.setUTCMinutes (дата);
             };

          this.setUTCMonth =
             Функция (дата)
             {
                if (date instanceof _Date)
                   date = date.instance;
                this.instance.setUTCMonth (дата);
             };

          this.setUTCSeconds =
             Функция (дата)
             {
                if (date instanceof _Date)
                   date = date.instance;
                this.instance.setUTCSeconds (дата);
             };

          this.toDateString =
             Функция ()
             {
                вернуть this.instance.toDateString ();
             };

          this.toISOString =
             Функция ()
             {
                вернуть this.instance.toISOString ();
             };

          this.toJSON =
             Функция ()
             {
                вернуть this.instance.toJSON ();
             };

          this.toLocaleDateString =
             Функция ()
             {
                вернуть this.instance.toLocaleDateString ();
             };

          this.toLocaleTimeString =
             Функция ()
             {
                вернуть this.instance.toLocaleTimeString ();
             };

          this.toString = 
             Функция ()
             {
                вернуть this.instance.toString ();
             };

          this.toTimeString =
             Функция ()
             {
                вернуть this.instance.toTimeString ();
             };

          this.toUTCString =
             Функция ()
             {
                вернуть this.instance.toUTCString ();
             };

          _Date.UTC =
             Функция (дата)
             {
                if (date instanceof _Date)
                   date = date.instance;
                return _Date_.UTC (date);
             };

          this.valueOf =
             Функция ()
             {
                вернуть this.instance.valueOf ();
             };
       }
       my._Date = _Date;

       var _Math = {};

       var props = Object.getOwnPropertyNames (Math);
       props.forEach (функция (клавиша)
       {
          if (Math [ключ]) 
             _Math [ключ] = математика [ключ]; 
       });

       если (! _Math.GOLDEN_RATIO)
          _Math.GOLDEN_RATIO = 1.61803398874;

       if (! _Math.rnd || _Math.rnd.length! = 1)
          _Math.rnd = 
             функция (предел)
             {
                if (typeof limit! = "number")
                   бросить "незаконный аргумент:" + предел;
  
                return Math.random () * limit |  0;
             };

       if (! _Math.rndRange || _Math.rndRange.length! = 2)
          _Math.rndRange = 
             функция (мин, макс)
             {
                if (typeof min! = "number")
                   бросить "незаконный аргумент": + мин;

                if (typeof max! = "number")
                   бросить "незаконный аргумент": + max;
  
                return Math.floor (Math.random () * (max - min + 1)) + min;
             };

       if (! _Math.toDegrees || _Math.toDegrees.length! = 1)
          _Math.toDegrees = 
             Функция (радианы)
             {
                if (typeof радианы! = "число")
                   киньте «незаконный аргумент»: + радианы;

                обратные радианы * (180 / Math.PI);
             };

       if (! _Math.toRadians || _Math.toRadians.length! = 1)
          _Math.toRadians = 
             Функция (в градусах)
             {
                if (typeof градусов! = "число")
                   бросить "незаконный аргумент:" + градусы;

                обратные градусы * (Math.PI / 180);
             };

       if (! _Math.trunc || _Math.trunc.length! = 1)
          _Math.trunc =
             Функция (п)
             {
                if (typeof n! = "number")
                   бросить "недопустимый аргумент": + n;
  
                возврат (n> = 0)?  Math.floor (n): -Math.floor (-n);
             };
       my._Math = _Math;

       вернуть мой;
    } ()); 

Листинг 1: Эта автономная библиотека дополнений может быть расширена для поддержки всех основных объектов

Все переменные и функции, объявленные в анонимном закрытии, являются локальными для этого замыкания. Для доступа извне замыкания необходимо экспортировать переменную или функцию. Чтобы экспортировать переменную или функцию, просто добавьте ее к объекту и верните этот объект из замыкания. В листинге 1 объект известен как my и ему назначена _Date функцию _Date и _Math объект _Math .

После объявления переменной my , которая инициализируется пустым объектом, в листинге 1 объявляется переменная _Date_ , которая ссылается на основной объект Date . Где бы мне ни понадобился доступ к Date из библиотеки, я _Date_ к _Date_ вместо Date . Я объясню причину этого соглашения позже в этой статье.

В листинге 1 теперь объявляется конструктор _Date для _Date объектов- _Date . Этот конструктор объявляет те же параметры year , month , date , hours , minutes , seconds и ms что и базовый объект Date . Эти параметры опрашиваются, чтобы определить, какой вариант конструктора Date вызывать:

  • _Date() вызывает Date() для инициализации объекта Date текущей датой. Этот сценарий определяется year тестирования для undefined .
  • _Date(year) вызывает Date(milliseconds) или Date(dateString) для инициализации объекта Date указанным числом миллисекунд или строкой даты — я оставляю его Date для обработки любого случая. Этот сценарий обнаруживается тестированием month на undefined .
  • _Date(year, month, date) вызывает _Date(year, month, date) для инициализации объекта Date указанным годом, месяцем и днем ​​месяца (дата). Этот сценарий обнаруживается по hour тестирования на undefined .
  • _Date(year, month, day, hours, minutes, seconds, milliseconds) вызывает Date(year, month, day, hours, minutes, seconds, milliseconds) для инициализации объекта Date датой, описанной отдельными компонентами. Этот сценарий по умолчанию.

Независимо от того, какой вариант конструктора (вызов конструктора со всеми или меньшим числом аргументов) вызывается, возвращаемый результат сохраняется в _Date instance _Date . Вы никогда не должны обращаться к instance напрямую, потому что вам может потребоваться переименовать это свойство, если Date введет свойство instance в будущем. Отсутствие доступа к instance за пределами библиотеки уменьшает обслуживание кода.

На данный момент в листинге 1 регистрируются новые методы copy() , isLeap() и lastDay() , а также новое свойство _Date с _Date . Он также регистрирует методы Date . Первые методы дополняют Date новой функциональностью, связанной с _Date вместо Date , и описаны ниже. Последние методы используют instance для доступа к ранее сохраненному экземпляру Date , обычно для вызова своих аналогов Date :

  • copy() создает копию экземпляра объекта Date который вызывает этот метод. Другими словами, он клонирует экземпляр Date . Пример: var d = new Date(); var d2 = d.copy(); var d = new Date(); var d2 = d.copy();
  • isLeap() возвращает true, когда часть года экземпляра вызывающего объекта Date представляет високосный год; в противном случае ложное возвращение. Пример: var d = new Date(); alert(d.isLeap()); var d = new Date(); alert(d.isLeap());
  • isLeap(date) возвращает true, когда годовая часть date представляет високосный год; в противном случае ложное возвращение. Пример: alert(Date.isLeap(new Date()));
  • lastDay() возвращает последний день в месяце вызывающего экземпляра объекта Date . Пример: var d = new Date(); alert(d.lastDay()); var d = new Date(); alert(d.lastDay());
  • Хотя это и не метод, вы можете получить английское длинное имя месяца из Date.monthNames массива Date.monthNames . Передайте индекс в диапазоне от 0 до 11. Пример: alert(Date.monthNames[0])

Методы, связанные с _Date вместо его экземпляров, назначаются непосредственно _Date , как в _Date.UTC = function(date) . Параметр date определяет либо базовую ссылку на объект Date либо ссылку _Date . Для этого _Date методы, связанные с экземплярами _Date . Внутри метода доступ к экземпляру Date осуществляется через this.instance .

Вы будете следовать предыдущему протоколу для поддержки Array , String и других основных объектов — за исключением Math . В отличие от других основных объектов, вы не можете создавать объекты Math . Вместо этого Math — это просто заполнитель для хранения статических свойств и методов. По этой причине я по-разному отношусь к Math , объявляя переменную _Math инициализированную для пустого объекта, и назначая свойства и методы непосредственно этому объекту.

Первым шагом в инициализации _Math является getOwnPropertyNames() метода getOwnPropertyNames() Object (реализованного в ECMAScript 5 и поддерживаемого современными настольными браузерами) для возврата массива всех свойств (перечисляемых или нет), найденных непосредственно в объекте аргумента, то есть Math , Затем в листинге 1 каждое свойство (функция или иное) _Math перед введением новых свойств / методов (если они еще не представлены):

  • GOLDEN_RATIO является константой золотого GOLDEN_RATIO , о котором я упоминал в предыдущей статье. Пример: alert(Math.GOLDEN_RATIO);
  • rnd(limit) возвращает целое число в диапазоне от 0 до значения, которое меньше значения limit . Пример: alert(Math.rnd(10));
  • rndRange(min, max) возвращает случайное целое число в диапазоне от значения min до значения max . Пример: alert(Math.rndRange(10, 20));
  • toDegrees(radians) преобразует значение radians в эквивалентное значение в градусах и возвращает это значение. Пример: alert(Math.toDegrees(Math.PI));
  • toRadians(degrees) преобразует значение в degrees в эквивалентное значение в радианах и возвращает это значение. Пример: alert(Math.toRadians(180));
  • trunc(n) удаляет дробную часть из положительного или отрицательного числа, переданного n и возвращает всю часть. Пример: alert(Math.trunc(5.8));

Каждый метод генерирует исключение, обозначающее недопустимый аргумент, когда он обнаруживает аргумент, который не относится к типу Number .

Зачем создавать библиотеку дополнений вместо создания отдельных служебных объектов (таких как DateUtil или MathUtil )? Библиотека служит массивной прокладкой для обеспечения согласованной функциональности во всех браузерах. Например, объект Math Firefox 25.0 предоставляет метод trunc() тогда как этот метод отсутствует в Opera 12.16. Моя библиотека гарантирует, что метод trunc() всегда доступен.

Тестирование и использование новой библиотеки расширения базовых объектов

Теперь, когда у вас была возможность изучить библиотеку, вы захотите попробовать ее. Я создал пару скриптов, которые тестируют различные новые возможности _Date и _Math , и создал пару более практичных скриптов, которые более полно используют библиотеку. В листинге 2 представлен HTML-документ, в который _Date скрипт для тестирования _Date .

  <! DOCTYPE html>
 <HTML>
   <Голова>
     <Название>
       Тестер дополненной даты
     </ Title>

     <script type = "text / javascript" src = "ajscolib.js">
     </ Скрипт>
   </ HEAD>

   <Тело>
     <Скрипт>
     var Date = ca_tutortutor_AJSCOLib._Date;

     переменная дата = новая дата ();
     оповещение («Текущая дата:» + дата);
     alert («Текущая дата:» + date.toString ());
     var dateCopy = date.copy ();
     alert («Копировать текущую дату:» + date.toString ());
     предупреждение («Текущая дата == Копия текущей даты:» + (date == dateCopy));
     alert ("Isleap" + date.toString () + ":" + date.isLeap ());
     alert («Isleap 1 июля 2012 г .:» + Date.isLeap (новая дата (2012, 6, 1)));
     alert («Последний день:» + date.lastDay ());
     alert («Названия месяцев:» + Date.monthNames);
     </ Скрипт>
   </ Body>
 </ Html> 

Листинг 2: Тестирование «расширенного» объекта Date

При работе с этой библиотекой вы не захотите указывать ca_tutortutor_AJSCOLib._Date и, вероятно, не захотите указывать _Date . Вместо этого вы захотите указать Date как будто вы работаете с самим основным объектом. Вам не нужно менять свой код, чтобы изменить ссылки Date на что-то другое. К счастью, вам не нужно этого делать.

Первая строка в сценарии присваивает ca_tutortutor_AJSCOLib._Date значение Date , фактически удаляя весь доступ к ca_tutortutor_AJSCOLib._Date объекту Date . Это причина для указания var _Date_ = Date; в библиотеке. Если бы я ссылался на Date вместо _Date_ в коде библиотеки, вы бы _Date_ «слишком много рекурсии» (и, возможно, другие проблемы).

Остальная часть кода выглядит знакомой тем, кто работал с Date . Тем не менее, есть небольшой сбой. Что выводится при вызове alert("Current date: " + date); ? Если бы вы использовали основной объект Date , вы бы увидели Current date: после строкового представления текущей даты. В текущем контексте, однако, вы наблюдаете Current date: за ней следует числовое значение в миллисекундах.

toString() против valueOf()
Проверьте преобразования объекта в примитив в JavaScript, чтобы узнать, почему alert("Current date: " + date); приводит к строковому или числовому представлению date .

Давайте применим «расширенный» объект Date для практического использования, например, для создания страницы календаря. Сценарий будет использовать document.writeln() для вывода HTML-кода этой страницы на основе элемента <table> . _Date два варианта конструктора _Date вместе с getFullYear() , getMonth() , getDay() , lastDay() и getDate() и свойство monthNames . Проверьте Листинг 3.

  <! DOCTYPE html>
 <HTML>
   <Голова>
     <Название>
       Календарь
     </ Title>

     <script type = "text / javascript" src = "ajscolib.js">
     </ Скрипт>
   </ HEAD>

   <Тело>
     <Скрипт>
     var Date = ca_tutortutor_AJSCOLib._Date;

     переменная дата = новая дата ();
     var year = date.getFullYear ();
     var month = date.getMonth ();
     document.writeln ("<table border = 1>");
     document.writeln ("<th bgcolor = # eeaa00 colspan = 7>");
     document.writeln ("<центр>" + Date.monthNames [месяц] + "" + год + 
                      "</ Центр>");
     document.writeln ( "</ й>");
     document.writeln ("<tr bgcolor = # ff7700>");
     document.writeln ( "<TD> <B> <центр> S </ центр> </ B> </ TD>");
     document.writeln ( "<TD> <B> <центр> М </ центр> </ B> </ TD>");
     document.writeln ( "<TD> <B> <центр> Т </ центр> </ B> </ TD>");
     document.writeln ( "<TD> <B> <центр> W </ центр> </ B> </ TD>");
     document.writeln ( "<TD> <B> <центр> Т </ центр> </ B> </ TD>");
     document.writeln ( "<TD> <B> <центр> F </ центр> </ B> </ TD>");
     document.writeln ( "<TD> <B> <центр> S </ центр> </ B> </ TD>");
     document.writeln ( "</ TR>");
     var dayOfWeek = new Date (year, month, 1) .getDay ();
     вар день = 1;
     для (переменная строка = 0; строка <6; строка ++)
     {
        document.writeln ( "<TR>");
        для (var col = 0; col <7; col ++)
        {
           var row;
           if ((row == 0 && col <dayOfWeek) || day> date.lastDay ())
           {
              document.writeln ("<td bgcolor = # cc6622>");
              document.writeln ("");
           }
           еще
           {
              if (day == date.getDate ())
                 document.writeln ("<td bgcolor = # ffff00>");
              еще
              если (день% 2 == 0)
                 document.writeln ("<td bgcolor = # ff9940>");
              еще
                 document.writeln ( "<TD>");
              document.writeln (день ++);
           }
           document.writeln ( "</ TD>");
        }
        document.writeln ( "</ TR>");
     }
     document.writeln ( "</ таблицы>");
     </ Скрипт>
   </ Body>
 </ Html> 

Листинг 3: Использование «расширенного» объекта Date для создания страницы календаря

Чтобы создать реалистичную страницу календаря, нам нужно знать, в какой день недели наступает первый день месяца. Выражение new Date(year, month, 1).getDay() дает нам необходимую информацию (0 для воскресенья, 1 для понедельника и т. Д.), dayOfWeek присваивается dayOfWeek . Каждый квадрат в верхней строке, индекс столбца которого меньше, чем dayOfWeek , остается пустым.

На рисунке 1 показан пример страницы календаря.


Текущий день выделен желтым цветом.

Рисунок 1: Текущий день выделен желтым цветом.

В листинге 4 представлен HTML-документ, в который _Math скрипт для тестирования _Math .

  <! DOCTYPE html>
 <HTML>
   <Голова>
     <Название>
       Дополненный тестер по математике
     </ Title>

     <script type = "text / javascript" src = "ajscolib.js">
     </ Скрипт>
   </ HEAD>

   <Тело>
     <Скрипт>
     var Math = ca_tutortutor_AJSCOLib._Math;

     оповещение ("Math.GOLDEN_RATIO:" + Math.GOLDEN_RATIO);

     пытаться
     {
        alert ("Math.rnd (null):" + Math.rnd (null));
     }
     поймать
     {
        alert («нулевое значение не поддерживается.»);
     }
     alert ("Math.rnd (10):" + Math.rnd (10));

     для (var i = 0; i <10; i ++)
        alert (Math.rndRange (5, 9));

     пытаться
     {
        alert ("Math.toDegrees (null):" + Math.toDegrees (null));
     }
     поймать
     {
        alert («нулевые градусы не поддерживаются»);
     }
     alert ("Math.toDegrees (Math.PI):" + Math.toDegrees (Math.PI));

     пытаться
     {
        alert ("Math.toRadians (null):" + Math.toRadians (null));
     }
     поймать
     {
        alert («нулевые радианы не поддерживаются»);
     }
     alert ("Math.toRadians (180):" + Math.toRadians (180));

     пытаться
     {
        alert ("Math.trunc (null):" + Math.trunc (null));
     }
     поймать
     {
        alert («нулевое значение не поддерживается.»);
     }
     alert ("Math.trunc (10.83):" + Math.trunc (10.83));
     alert ("Math.trunc (-10.83):" + Math.trunc (-10.83));
     </ Скрипт>
   </ Body>
 </ Html> 

Листинг 4: Тестирование «дополненного» объекта Math

Давайте применим «расширенный» объект Math для практического использования, например, для отображения кардиоидной кривой , которая представляет собой плоскую кривую, очерченную точкой по периметру круга, который вращается вокруг неподвижного круга того же радиуса. Скрипт будет использовать rndRange() Math : rndRange() , toRadians() , cos() и sin() . Проверьте Листинг 5.

  <! DOCTYPE html>
 <HTML>
   <Голова>
     <Название>
       кардиоида
     </ Title>

     <script type = "text / javascript" src = "ajscolib.js">
     </ Скрипт>
   </ HEAD>

   <Тело>
     <canvas id = "canvas" width = "300" height = "300">
     холст не поддерживается
     </ Холст>

     <Скрипт>
     var Math = ca_tutortutor_AJSCOLib._Math;

     var canvas = document.getElementById ("canvas");
     var canvasctx = canvas.getContext ("2d");

     var width = document.getElementById ("canvas"). width;
     var height = document.getElementById ("canvas"). height;

     canvasctx.fillStyle = "# 000";
     canvasctx.fillRect (0, 0, ширина, высота);
     canvasctx.fillStyle = "RGB (" + Math.rndRange (128, 255) + "," +
                           Math.rndRange (128, 255) + "," +
                           Math.rndRange (128, 255) + ")";

     canvasctx.beginPath ();
     для (var angleDeg = -180,0; angleDeg <180,0; angleDeg + = 0,1)
     {
        var angle = Math.toRadians (angleDeg);

        // Оценить уравнение кардиоидной кривой.  Это производит радиус для
        // заданный угол.  Примечание: [r, угол] - полярные координаты.

        var r = 60,0 + 60,0 * Math.cos (угол);

        // Преобразование полярных координат в прямоугольные.  добавлять
        // ширина / 2 и высота / 2, чтобы переместить начало кривой в центр
        // холста.  (По умолчанию в качестве источника используется верхний левый угол холста.)

        var x = r * Math.cos (угол) + ширина / 2;
        var y = r * Math.sin (угол) + высота / 2;
        если (угол == 0,0)
           canvasctx.moveTo (x, y);
        еще
           canvasctx.lineTo (x, y)
     }
     canvasctx.closePath ();
     canvasctx.fill ();
     </ Скрипт>
   </ Body>
 </ Html> 

Листинг 5: Использование «расширенного» объекта Math для создания кривой кардиоида

В листинге 5 для beginPath() кардиоидной кривой используются элемент canvas из HTML5 и API, который создается в виде многоугольника с помощью beginPath() , moveTo() , lineTo() и closePath() холста контекста. Каждый компонент цвета заливки кривой выбирается случайным образом с помощью rndRange() . Его аргументы гарантируют, что компонент не слишком темный. Кривая заполняется с помощью метода fill() контекста canvas.

Рисунок 2 показывает красочную кардиоидную кривую.

Перезагрузите страницу, чтобы изменить цвет кривой.

Рисунок 2: Перезагрузите страницу, чтобы изменить цвет кривой.

Вывод

В этой статье показано, как создать библиотеку, которая дополняет основные объекты JavaScript, не дополняя их напрямую. Публичный интерфейс библиотеки переносим между браузерами, хотя возможно, что для реализации может потребоваться настройка на совместимость, производительность или другие причины. В качестве упражнения добавьте в эту библиотеку усовершенствования Array , Boolean , Number и String моей предыдущей статьи.