БлогNot. Полезные мини-скрипты на Javascript

Полезные мини-скрипты на Javascript

сейчас в списке: 51 скрипт Этот список будет включать в себя небольшие задачи на Javascript, поменьше объёмом, чем вот эти, и, в общем, представляющие собой законченные мини-приложения, если вставить код в тело любого документа HTML5 в кодировке Юникода UTF-8.

Полезные алгоритмы есть также в этой заметке (с JS-массивами), на сайте nickolay.info в разделе по Javascript и просто по соответствующему тегу блога.

Список будет пополняться, для быстрого поиска на странице нужного слова используйте комбинацию клавиш Ctrl+F в браузере.

1. Разметить строку посимвольно случайными тегами из разрешённого набора, аналог текстовой капчи
<div id="captcha"></div>
<script>
function rndFormat (text) {
 let tags = [
  '<i>',  '<b>',  '<u>',  '<sup>',  '<sub>',  '<big>',  '<small>'
 ];
 let result = '';
 for (let i=0; i<text.length; i++) {
  let num=Math.floor(Math.random()*tags.length);
  result += tags[num] + text[i] + '</' + tags[num].substring(1);
 }
 return result;
}
document.getElementById('captcha').innerHTML = rndFormat('Hello!');
</script> 
2. Проверить корректность даты

Проще всего задействовать стандартный объект Date.

<script>
function validate_date (id) {
 let arrD = document.getElementById(id).value.split('.');
 arrD[1]--;//у обьекта date отсчет месяцев начинается с нуля 
 let dt = new Date(arrD[0], arrD[1], arrD[2]); //встроенный обьект
 return (
  (dt.getFullYear() == arrD[0]) && (dt.getMonth() == arrD[1]) && (dt.getDate() == arrD[2]) 
   ? true : false);
}
</script>
<input type="text" id="dt0" size="25" maxlength="10" placeholder="дата в формате ГГГГ.ММ.ДД">
<input type="button" value="Проверить" 
 onclick="document.getElementById('dateResult').innerHTML = validate_date('dt0');">
<span id="dateResult"></span>
3. Найти день недели по формуле Зеллера

Здесь мы получаем день недели не из объекта, а считаем по формуле. Без parseInt в функции будет считать неправильно :)

Функция pad дополняет слева натуральное число n до size разрядов нулями.

<script>
function weekday (id) {
 let arrD = document.getElementById(id).value.split('.');
 let y = parseInt(arrD[0]), m = parseInt(arrD[1]), d = parseInt(arrD[2]), dday = -1;
 //корректность даты не проверяется!
 if (m<3) { m+=12; y--; }
 let n = y%100, c = Math.floor(y/100);
 dday= (Math.floor((m+1)*26/10)+d+n+Math.floor(n/4)+Math.floor(c/4)-2*c) % 7;
 let wday = new Array ('Сб','Вс','Пн','Вт','Ср','Чт','Пт');
 function pad (n,size) { return String(Array(size-1).fill('0').join('')+n).slice(-size); }
 return pad(arrD[2],2)+'.'+pad(arrD[1],2)+'.'+pad(arrD[0],4)+'='+wday[dday];
}
</script>
<input type="text" id="dt0" size="25" maxlength="10" placeholder="дата в формате ГГГГ.ММ.ДД">
<input type="button" value="Вычислить" 
 onclick="document.getElementById('dateResult').innerHTML = weekday('dt0');">
<span id="dateResult"></span>
4. По заданным интенсивностям красного, зелёного и синего цветов получить строку вида rgb(23,100,134)

Дополнительно код показывает цвет фоном раздела rgbResult.

<script>
 function rgb (r0=0,g0=0,b0=0) {
  let r = Math.max(0,Math.min(r0,255)),
      g = Math.max(0,Math.min(g0,255)),
      b = Math.max(0,Math.min(b0,255));
  return 'rgb('+r+','+g+','+b+')';
 }
 function pad3 (i) { return String('00' + i).slice(-3); } //'0'=>'000', '10'=>'010'
</script>
<div id="rgbResult">&nbsp;</div>
<span id="red_sel" style="font-family: monospace; background-color: red;">128</span>
<input type="range" id="red_val" min="0" max="255" step="1" value="128"
 onchange="document.getElementById('red_sel').innerHTML = pad3(this.value);">
<span id="green_sel" style="font-family: monospace; background-color: green;">128</span>
<input type="range" id="green_val" min="0" max="255" step="1" value="128"
 onchange="document.getElementById('green_sel').innerHTML = pad3(this.value);">
<span id="blue_sel" style="font-family: monospace; background-color: #3333ff;">128</span>
<input type="range" id="blue_val" min="0" max="255" step="1" value="128"
 onchange="document.getElementById('blue_sel').innerHTML = pad3(this.value);">
<input type="button" value="Выполнить" 
  onclick="let c = rgb(document.getElementById('red_val').value,
                       document.getElementById('green_val').value,
                       document.getElementById('blue_val').value);
   document.getElementById('rgbResult').style.backgroundColor = c;
   document.getElementById('rgbString').innerHTML = c;">
<span id="rgbString" style="font-family: monospace;"></span>
5. Выбрать случайную строку из набора строк (случайный элемент массива)
<script>
function randomText() {
 let arr= [
 'Текст 1',
 'Текст 2',
 'Текст 3',
 'Текст 4',
 'Текст 5',
 'Текст 6',
 'Текст 7',
 'Текст 8',
 'Текст "9"',
 'Текст \'10\''
 ];
 return arr[Math.floor(Math.random()*arr.length)];
}
</script>
<div onclick="this.innerHTML=randomText();">Нажми меня!</div>
6. Поменять местами два значения в форме
<form>
 <input type="text" id="a" size="4" maxlength="3">
 <input type="text" id="b" size="4" maxlength="3">
 <input type="button" value="Поменять местами" onclick="f('a','b'); return false;">
</form>
<script>
 function f(id1,id2) {
  let a = document.getElementById(id1).value;
  let b = document.getElementById(id2).value;
  let temp = a; a = b; b = temp;
  document.getElementById(id1).value = a;
  document.getElementById(id2).value = b;
 }
</script>

Если значения должны быть целыми числами и обмен выполняется с проверкой и коррекцией данных, то так (обмен делается арифметически для разнообразия):

<form>
 <input type="text" id="a" size="4" maxlength="3">
 <input type="text" id="b" size="4" maxlength="3">
 <input type="button" value="OK" onclick="f('a','b'); return false;">
</form>
<script>
 function f(id1,id2) {
  let a = parseInt(document.getElementById(id1).value);
  if (isNaN(a)) a = 0; 
  let b = parseInt(document.getElementById(id2).value);
  if (isNaN(b)) b = 0; 
  a += b; b = a - b; a -= b;
  document.getElementById('a').value = a;
  document.getElementById('b').value = b;
 }
</script>
7. Табулировать произвольную функцию одного аргумента в заданных пределах

Пределы и функция передаются аргументами в tab.

<div id="table"></div>
<script>
 function tab (x1,dx,x2,f) {
  let s='<pre>'+"\n";
  for (let x=x1; x<=x2; x+=dx) {
   s += x.toFixed(3).toString().padStart(10)+' '+f(x).toFixed(3).toString().padStart(10)+"\n";
  }
  return s+'</pre>';
 }
 let f = function (x) {
  return Math.sin(x);
 }
 let div = document.getElementById('table');
 div.innerHTML = tab(0,Math.PI/10,2*Math.PI,f);
</script>
8. Заменить символы табуляции пробелами без изменения внешнего вида текста

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

Код, показанный ниже, удаляет из элемента src символы табуляции, стараясь корректно заменить их пробелами, и помещает результат обработки в элемент res.

<script>
 function detab (text, tsize = 8) {
  let arr = text.split("\n");
  let res = '';
  for (let i = 0; i<arr.length; i++) {
   let str = arr[i], newstr = '';
   for (let k = 0; k < str.length; k++) {
    if (str[k] == '\t') {
     let newlen = newstr.length;
     for (let j = 0; j < tsize - newlen % tsize; j++) newstr += ' ';
    }
    else newstr += str[k];
   }
   res += newstr + (i<arr.length-1 ? '\n' : '');
  }
  return res;
 }
</script>
<textarea id="src" rows="5" cols="90" style="font-family: monospace;">
123	вторая позиция, в следующей строке одни табуляции
0	11	222	3333	4444	55555	666666	7777777	88888888	9
</textarea>
<br>
<textarea id="res"  rows="5" cols="90" style="font-family: monospace;"></textarea>
<br>
<button onclick="document.getElementById('res').value = detab (document.getElementById('src').value);">
ok</button>
9. Как "подогнать" размеры канвы под нужные пиксельные размеры рисунка?
<canvas id="canvas1" style="border: 1px dotted red;"></canvas>
<img id="image1" src="kar.jpg" style="visibility: hidden;">
<script>
 let canvas = document.getElementById('canvas1');
 let ctx = canvas.getContext('2d');
 let imageObj = new Image();
 imageObj.src = document.getElementById("image1").src;
 imageObj.onload = function () {
  canvas.width = imageObj.width;
  canvas.height = imageObj.height;
  ctx.drawImage(imageObj,0,0,imageObj.width,imageObj.height,0,0,canvas.width,canvas.height);
 };
</script>

Здесь оригинальный рисунок (с именем kar.jpg из текущей папки скрипта) скрыт стилем, а показан размещённый в канве.

Можно, конечно, и масштабировать рисунок по канве как здесь, и перестраивать изображение при масштабировании окна.

10. Как загрузить файл с рисунком на canvas? Как обработать файл на canvas попиксельно?

Для загрузки файла используется современный подход через FileReader. Рисунок загружается в верхнюю канву, а результат его попиксельной обработки фильтром - в нижнюю. В данном случае фильтрация функцией sepia сводится к наложению одноимённого эффекта.

<input type="file" id="imageLoader">
<br>
<canvas id="sourceCanvas"></canvas>
<br>
<canvas id="targetCanvas"></canvas>
<script>
 let imageLoader = document.getElementById('imageLoader');
 imageLoader.addEventListener('change', handleImage, false);
 let sourceCanvas = document.getElementById('sourceCanvas');
 let ctx = sourceCanvas.getContext('2d');
 let targetCanvas = document.getElementById('targetCanvas');

 function handleImage (e) {
  let reader = new FileReader();
  reader.onload = function (event) {
   let img = new Image();
   img.onload = function() {
    sourceCanvas.width = targetCanvas.width = img.width;
    sourceCanvas.height = targetCanvas.height = img.height;
    ctx.drawImage (img, 0, 0, img.width, img.height);
    let data = ctx.getImageData(0,0,img.width, img.height);
    sepia (data, img);
   }
   img.src = event.target.result;
  }
  reader.readAsDataURL (e.target.files[0]);     
 }

 function sepia (imageData, img) {
  let pixels = imageData.data;
  for (let i = 0; i < pixels.length; i += 4) {
   let r = pixels[i];
   let g = pixels[i + 1];
   let b = pixels[i + 2];
   pixels[i] = (r * 0.393)+(g * 0.769)+(b * 0.189);
   pixels[i + 1] = (r * 0.349)+(g * 0.686)+(b * 0.168);
   pixels[i + 2] = (r * 0.272)+(g * 0.534)+(b * 0.131);
  }
  let ctx = targetCanvas.getContext("2d");
  ctx.drawImage (img, 0, 0, img.width, img.heigth);
  ctx.putImageData (imageData, 0, 0);
 }
</script>
11. Как умножить 2 длинных натуральных числа?

В блоге есть подобное на C++, но компилировать-то обычно лень, пусть будет ещё на JS.

<script>
function mult(strNum1,strNum2){
 let a1 = strNum1.split("").reverse();
 let a2 = strNum2.toString().split("").reverse();
 let aResult = new Array();
 for ( let iterNum1 = 0; iterNum1 < a1.length; iterNum1++ ) {
  for ( let iterNum2 = 0; iterNum2 < a2.length; iterNum2++ ) {
   let idxIter = iterNum1 + iterNum2;
   aResult[idxIter] = a1[iterNum1] * a2[iterNum2] + ( idxIter >= aResult.length ? 0 : aResult[idxIter] );
   if ( aResult[idxIter] > 9 ) {
    aResult[idxIter + 1] = Math.floor( aResult[idxIter] / 10 ) + ( idxIter + 1 >= aResult.length ? 0 : aResult[idxIter + 1] );
    aResult[idxIter] %= 10;
   }
  }
 }
 return aResult.reverse().join("");
}
</script>
<input type="text" maxlength="99" size="100" id="num1">
<br>
<input type="text" maxlength="99" size="100" id="num2">
<br>
<input type="button" value="Умножить" 
 onclick="document.getElementById('res').innerHTML=
  mult(document.getElementById('num1').value,document.getElementById('num2').value);">
<div id="res"></div>
12. Сгенерировать случайный текст на основе последовательности фраз

Примерно как здесь, только проще и на стороне клиента.

<div id="textContent"></div>
<script>
function generateText (id, n) {
 let count = parseInt(n);
 if (isNaN(count) || count<1) count = 1;
 let w1 = new Array ("Товарищи,", "С другой стороны", "Равным образом", "Не следует однако забывать, что", 
  "Таким образом,", "Повседневная практика показывает, что", "Разнообразный и богатый опыт", 
  "Задача организации, в особенности же", "Идейные соображения высшего порядка, а также");
 let w2 = new Array ("реализация намеченных плановых заданий", "рамки и место обучения кадров", 
  "постоянный количественный рост и сфера нашей активности", "сложившаяся структура организации", 
   "новая модель организационной деятельности", "дальнейшее развитие различных форм деятельности", 
  "постоянное информационно-пропагандистское обеспечение нашей деятельности", 
  "укрепление и развитие структуры", "консультация с широким активом", 
  "начало повседневной работы по формированию позиции");
 let w3 = new Array ("играет важную роль в формировании", "требует определения и уточнения", 
  "способствует подготовке и реализации", "обеспечивает широкому кругу специалистов участие в формировании", 
  "позволяет выполнить важные задания по разработке", "в значительной степени обусловливает создание", 
  "позволяет оценить значение", "представляет собой интересный эксперимент проверки", 
  "влечет за собой процесс внедрения и модернизации");
 let w4 = new Array ("существенных финансовых и административных условий", "дальнейших направлений развития", 
  "системы массового участия", "позиций, занимаемых участниками в отношении поставленных задач", 
  "новых предложений", "направлений прогрессивного развития", 
  "системы обучения кадров, соответствующей насущным потребностям", 
  "соответствующих условий активизации", "модели развития", "форм воздействия");
 let phrase = "";
 for (let i = 0; i < count; i++) {
  let rnd1 = Math.floor(Math.random() * w1.length);
  let rnd2 = Math.floor(Math.random() * w2.length);
  let rnd3 = Math.floor(Math.random() * w3.length);
  let rnd4 = Math.floor(Math.random() * w4.length);
  phrase += "<p>" + w1[rnd1] + " " + w2[rnd2] + " " + w3[rnd3] + " " + w4[rnd4] + ".</p>\n";
 }
 document.getElementById(id).innerHTML = phrase;
}

generateText('textContent',4); //id раздела, количество предложений
</script>
13. Составить частотную таблицу слов в документе

Что входит в "слова" - видно из text.replace, таблица формируется просто по порядку встречаемости слов в тексте. Предполагается только латиница и/или кириллица, регистр символов должен игнорироваться.

<p>Текст</p>
<textarea id="input_text"></textarea>
<br>
<button id="btn">Анализировать</button>
<table width="200" style="border-collapse: collapse;">
 <caption>Таблица частот слов</caption>
 <thead>
  <tr>
   <th>Слово</th>
   <th>Частота</th>
  </tr>
 <thead>
 <tbody id="tbody"></tbody>
</table>
<script>
 let input = document.getElementById('input_text');
 let btn = document.getElementById('btn');
 let tbody = document.getElementById('tbody');
 let wordsArray = [];
 function countFrequency() {
  if (tbody.hasChildNodes()) {
   while (tbody.firstChild) {
    tbody.removeChild(tbody.firstChild);
   }
  }
  let text = input.value.toString();
  text = text.replace(/[^\w\s\A-Za-zА-Яа-яЁё0-9\-]/gi,' '); //что входит в "слова"
  words = text.split(/\s/).filter(function(x){return x.length>0; }); //убрали пустые
  for (let word of words) {
   word = word.toLowerCase();
   let row = document.getElementById('tr-'+word);
   if (row == null) {
    let tr = document.createElement('tr');
    tr.id = 'tr-'+word;
    let td1 = document.createElement('td');
    let td2 = document.createElement('td');
    td1.innerHTML = word;
    td2.innerHTML = 1;
    tr.appendChild(td1);
    tr.appendChild(td2);
    tbody.appendChild(tr);
   }
   else {
    let value = row.childNodes[1].innerHTML;
    value++;
    row.childNodes[1].innerHTML = value;
   }
  }
 }
 btn.addEventListener('click',countFrequency);
</script>
14. Получить в разделе документа календарь на произвольные месяц и год

Всё пишется в раздел с id="calendar"

<style>
 .mtab {
  margin: 0 auto; 
  width: 32rem;
  font-family: monospace;
  border-spacing: 1.5rem 0;
 }
 .mrow {
 }
 .mcol {
  text-align: left;
 }
 .mp {
  margin: 0.25rem 0;   
 } 
</style>

<div class="mtab">
 <form name="dataForm" id="dataForm" class="mtab">
  <select size="1" name="monthList" id="monthList"></select>
  <script>
   let d = new Date(), m = d.getMonth(), str = '';
   let names = new Array ('Январь','Февраль','Март','Апрель','Май','Июнь',
    'Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь');
   for (let i=0; i<12; i++) 
    str += '<option value="'+i+'"'+(i==m?' selected':'')+'>'+names[i]+'</option>'+"\n";
   document.getElementById('monthList').innerHTML = str+"\n";
  </script>
  <select size="1" name="yearsList" id="yearsList"></select>
  <script>
   let y = d.getFullYear(), y2 = y + 100, y1 = 1582;
   str = '';
   for (let i=y2; i>=y1; i--) 
    str += '<option value="'+i+'"'+(i==y?' selected':'')+'>'+i+'</option>'+"\n";
   document.getElementById('yearsList').innerHTML = str+"\n";
  </script>
  <input type="button" value="Сформировать" 
   onclick="Calendar(document.dataForm.monthList.options[document.dataForm.monthList.selectedIndex].value,
                     document.dataForm.yearsList.options[document.dataForm.yearsList.selectedIndex].value,'calendar');">
  <input type="button" value="Текущий" onclick="currentCalendar('calendar');">
 </form>
</div>
<div id="calendar" class="mtab"></div>

<script>
 function Calendar(m,y,id) { //месяц (с 0), год (полный), id раздела, куда вставить календарь
  function isLeapYear (y) { return (((y%4==0) && (y%100!=0) || (y%400==0)) ? true : false); }
  function getDaysInMonth (m,y) {
   let mondays = [31,28,31,30,31,30,31,31,30,31,30,31];
   if (isLeapYear (y) == true) mondays[1]=29;
   return (mondays[m]);
  }
  let s = '<table class="mtab">'+"\n", d = new Date(y,m,1), w = d.getDay(), maxd = getDaysInMonth(m,y);
  if (w == 0) w = 6; else w--;
  let arr = Array(maxd).fill(0).map(function(val,index){return index+1;}); //1..maxd
  for (let i=0; i<w; i++) arr.unshift(' '); //пустые дни впереди
  for (let i=arr.length; i<42; i++) arr.push(' '); //пустые дни в конце
  s += '<tr class="mrow">'+"\n";
  let wd = new Array ('Пн','Вт','Ср','Чт','Пт','Сб','Вс');
  for (let i=0; i<7; i++) s += '<th>'+wd[i]+'</th>'+"\n";
  s += '</tr>'+"\n";

  let k = 0;
  for (let r=0; r<6; r++) {  
   s += '<tr class="mrow">'+"\n";
   for (let c=0; c<7; c++) {  
    s += '<td class="mcol"><p class="mp">'+arr[k++]+'</p></td>'+"\n";
   }
   s += '</tr>'+"\n";
  }
  s += '</table>'+"\n";
  document.getElementById(id).innerHTML = s;
 }

 function currentCalendar (id) { 
  let d = new Date(), m = d.getMonth(), y = d.getFullYear();
  document.dataForm.monthList.selectedIndex = m;
  document.dataForm.yearsList.selectedIndex = 100;
  Calendar(m,y,id);
 }
</script>
<noscript>
 <div class="mtab">Включите JavaScript для работы приложения</div>
</noscript>
15. Получить список тегов документа

Берутся теги внутри <body>

 <script>
  function getTags() {
   function walk(node) {
    var child, next;
    if (node.nodeType) {
     if (node.tagName !== undefined) tags.push(node.tagName);
     child = node.firstChild;
     while ( child ) {
      next = child.nextSibling;
      walk(child);
      child = next;
     }
    }
   }
   let elem = document.body;
   let tags = new Array();
   walk (elem);
   return tags.join("\n"); //список названий тегов, разделенных переводом строки
  }
 </script>
 <p>Просто, чтоб были теги</p>
 <p></p>
 <img></img>
 <img></img>
 <img></img>
 <h5></h5>
 <p></p>
 <h5></h5>
 <button onclick="document.getElementById('result').innerHTML = getTags();">OK</button>
 <pre id="result"></pre>
16. Дата плюс/минус количество дней

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

<script>
 function getDateAgo (date, days) {
  let dateCopy = new Date(date);
  dateCopy.setDate(date.getDate() + days);
  return dateCopy;
 }
 alert( getDateAgo(new  Date(), -30));
</script>
17. Самосчётная функция

Без привлечения внешней переменной считаем , сколько раз была вызвана функция

<script>
 function cnt() {
  if ( typeof(cnt.c) == 'undefined' ) {
   cnt.c = 0;
  }
  cnt.c++;
  return cnt.c;
 }

 cnt();
 cnt();
 let n=cnt();
 alert(n);
</script>
18. Упрощение дроби

Вводим из формы целые значения для числителя и знаменателя, сокращаем дробь, учитывая знак и особые случаи.

<form name="dataform">
<p>Введите числитель: <input type="number" name="num" value="0"></input></p>
<p>Введите знаменатель: <input type="number" name="denom" value="0"></input></p>
<input type="button" value="Упростить" 
 onclick="document.getElementById('result').innerHTML = 
          simplifyFraction(document.dataform.num.value,document.dataform.denom.value);">
</form>
<div id="result"></div>

<script>
 function simplifyFraction (num,denom) {
  let M = parseInt(num), N = parseInt(denom);
  let sgn = 0; if (M<0) sgn++; if (N<0) sgn++; 
  sgn %= 2; //- на - дает снова +
  let m = Math.abs(M), n = Math.abs(N); M = m, N = n;
  if (!n) return (sgn?'-':'')+'&infin;';
  for (let i = 2; i <= m; i++) {
   if (m % i == 0 && n % i == 0) {
    M = m / i; N = n / i;
   }
  }
  return (sgn?'-':'') + M + (N!=1 ? '/'+N : ''); 
 }
</script>
19. Отрисовка на канве геометрического примитива

Здесь мы изобразим суперэллипс.

<canvas id="canvas" style="border: 1px dotted red;"></canvas>
<script> 
function start (id,n,a,b) {
 function point (x, y) { ctx.fillRect( x, y, 1, 1); }
  let canvas = document.getElementById(id);
  const PADDING = 20; //отступ
  let size = 2*Math.max(a,b)+PADDING; //размер канвы зависит от a,b
  canvas.width = canvas.height = size;
  let ctx = canvas.getContext( "2d" );
  ctx.rect (0, 0, canvas.width, canvas.height);
  ctx.fillStyle = "#fff"; ctx.fill(); //белая заливка
  ctx.fillStyle = "#000"; //отрисовка чёрным
  for (let t=0; t <= 2*360; t += 0.1) { //прорисовываем дважды для надёжности
   x = Math.pow( Math.abs( Math.cos( t ) ), 2 / n ) * a * Math.sign( Math.cos( t ) );
   y = Math.pow( Math.abs( Math.sin( t ) ), 2 / n ) * b * Math.sign( Math.sin( t ) );
   point (x + ( canvas.width >> 1 ), y + ( canvas.height >> 1 ));
  }
 }

 start ('canvas',2.5,200,200);
</script>
нарисованный суперэллипс, скриншот
нарисованный суперэллипс, скриншот
20. Как извлечь из текстового содержимого только числа в любой допустимой записи?

Метод getArrayFromTextarea извлекает и возвращает массив чисел из значения текстового контейнера с id==srcId. Обратите внимание также на "гибкую" функцию очистки полей clearMe.

 <script> 
  function getArrayFromTextarea (srcId) {
   let text = document.getElementById(srcId).value;
   let arr = text.split(/\s+/);
   arr = arr.filter( function(item){ return item!='' && !isNaN(item) && isFinite(item); });
   return arr;
  }

  function clearMe (...ids) { //очистить элементы из ids
   if (ids === undefined) return;
   for (let id in ids) {
    let elem = document.getElementById(ids[id]);
    if (!elem) continue;
    elem.value = '';
   }
  }

  function selectMe (id) { //выделить элемент с id
   document.getElementById(id).focus();
   document.getElementById(id).select();
  }
 </script> 
 <noscript>  
  <p>Включите Javascript в браузере для работы приложения</p>
 </noscript> 
 
 <p>Введите или вставьте числа:</p>
 <p><textarea id="src" rows="5" cols="90" style="font=family: monospace;"></textarea></p>
 <p>Результат обработки:</p>
 <p><textarea id="res" rows="5" cols="90" style="font=family: monospace;"></textarea></p>
 <p>
  <button onclick="document.getElementById('res').value = 
   getArrayFromTextarea('src').join('\n'); selectMe('res');">Выполнить</button>
  <button onclick="clearMe('src','res');">Очистить</button>
 </p>
21. Можно ли делать арифметические действия с длинными целыми числами нативными методами, а не "вручную", как в задаче 11?

В Javascript уже есть BigInt, правда, работает не везде.

В этом скрипте также особо вычурная функция clearMe очистки нужных свойств у нужных элементов.

<script> 
 function actionMe (id1, id2, action) {
  let n1 = BigInt(document.getElementById(id1).value),
   n2 = BigInt(document.getElementById(id2).value),
   res;
  switch (action) {
   case '*': res = n1 * n2; break;
   //добавьте другие действия
   default: res = 'Неверная операция'; break;
  }
  return res;
 }
 function clearMe (...ids) { 
  //очистить свойства элемент property у элементов с id="item" из ids
  if (ids === undefined) return;
  for (let id in ids) {
   let idn = ids[id].item;
   let elem = document.getElementById(idn);
   if (!elem) continue;
   let prop = ids[id].property;
   if (!prop) continue;
   elem[prop] = '';
  }
 }
</script> 
<noscript>  
 <p>Включите Javascript в браузере для работы приложения</p>
</noscript> 
 
 <p>Число 1: <input type="text" id="n1" size="80" maxlength="128" pattern="-?\d+"></p>
 <p>Число 2: <input type="text" id="n2" size="80" maxlength="128" pattern="-?\d+"></p>
 <p>
  <button onclick="document.getElementById('result').innerHTML = actionMe('n1','n2','*');">[*]</button>
  <button onclick="clearMe(
   {item: 'n1', property: 'value'}, 
   {item: 'n2', property: 'value'}, 
   {item: 'result', property: 'innerHTML'}, 
  );">clear</button>
 </p>
 <p id="result"></p>
22. Как измерить время выполнения вычислительного процесса?
<script>
 let start, end;
 start = new Date();
 for (let i = 0; i < 1e7; i++) { //10 миллионов шагов
  Math.sqrt(i);
 }
 end = new Date();
 alert ((end.getTime() - start.getTime()) + ' мсек');
</script>
23. Как создать на странице динамический элемент, настроить его атрибуты и стилевые селекторы, добавить обработчик события и выполнение кода по таймеру?

Все ответы - в этом небольшом коде с комментариями.

<div id="content"></div> <!-- Элемент для контента -->
<script>
 function onload (id) { //Функция-обёртка приложения
  let elem = document.getElementById(id); //Получить основной элемент для контента
  if (!elem) { console.log('Item id='+id+' not found'); return; }
  let child = document.createElement('p'); //Создать новый абзац
  child.setAttribute('align', 'center'); //Так можно настроить атрибуты тега
  child.style.backgroundColor = '#999'; //И стилевые селекторы
  child.innerHTML = 'Click me'; //И содержимое HTML
  child.addEventListener ('click', function(e) { click1(e); });
   //Добавить обработчик события для элемента
  elem.appendChild (child); //Добавить сам элемент в основной

  function reDraw () { child.innerHTML = new Date(); } //Перерисовка

  function click1 (e) { //Выполнить reDraw и назначить её вызов с таймером 1 сек.
   reDraw();
   let timer = setInterval(function () { reDraw();  }, 1000); 
  }
 }

 window.addEventListener('load', function (e) { onload('content'); }, false); 
  //Выполнить функцию-обёртку по загрузке страницы, без захвата событий
</script>
24. Как избежать обращения из функций к "внешним" по отношению к коду элементам HTML?

Передавать в функции аргументами нужные данные из элементов HTML, если эти данные требуются функциям.

Функции пусть выполняют свою работу - получают данные через аргументы и возвращают результат работы в виде переменной, массива или объекта.

А если писать каждый раз document.getElementById(id).value или document.getElementById(id).innerHTML слишком долго, простейшем случае можно сделать объект-"обёртку" с именами методов покороче, например, как $ в этом коде:

<script>
 function truncate (src, maxlen) {
  return src.length < maxlen ? src : src.substring(0,maxlen)+'...';
 }

 let $ = {
  get (id) { return document.getElementById(id) ? document.getElementById(id) : null; },
  getVal (id) { return document.getElementById(id) ? document.getElementById(id).value : null; },
  getHTML (id) { return document.getElementById(id) ? document.getElementById(id).innerHTML : null; },
  setVal (id, val) { if (document.getElementById(id)) document.getElementById(id).value = val; },
  setHTML (id, html) { if (document.getElementById(id)) document.getElementById(id).innerHTML = html; }
 };
</script>
	
<textarea name="str" id="str"></textarea>
<br><input type="text"  name="maxlength" id="maxlength" value="10">
<br><textarea name="myResult" id="myResult" readonly></textarea>
<br><input type="button" value="Выполнить" 
 onclick="$.setVal('myResult',truncate($.getVal('str'),$.getVal('maxlength')));">
25. Как программно выделить нужную часть текста в текстовом поле ввода?

Можно, например, так (идентификатор элемента и номера позиций в тексте передаются аргументами функции).

<input type="text" id="txt">
<input type="button" value="Выделить" onclick="createSelection('txt', 1, 3);">
<script>
function createSelection(id, start, end) {
 let field = document.getElementById (id);
 if (field.createTextRange) {
  let selRange = field.createTextRange();
  selRange.collapse(true);
  selRange.moveStart('character', start);
  selRange.moveEnd('character', end);
  selRange.select();
  field.focus();
 } 
 else if (field.setSelectionRange) {
  field.focus();
  field.setSelectionRange(start, end);
 } 
 else if (typeof field.selectionStart != 'undefined') {
  field.selectionStart = start;
  field.selectionEnd = end;
  field.focus();
 }
}
</script>
26. Как реализовать операции над множествами?

В современных версиях Javascript есть отдельный объект Set.

<script>
 function isSuperset (set, subset) {
  for (let elem of subset) {
   if (!set.has(elem)) return false;
  }
  return true;
 }

 function union (setA, setB) {
  let _union = new Set(setA);
  for (let elem of setB) _union.add(elem);
  return _union;
 }

 function intersection (setA, setB) {
  let _intersection = new Set();
  for (let elem of setB) {
   if (setA.has(elem)) _intersection.add(elem);
  }
  return _intersection;
 }

 function difference(setA, setB) {
  let _difference = new Set(setA);
  for (let elem of setB) _difference.delete(elem);
  return _difference;
 }

let setA = new Set([1, 2, 3, 4]),
 setB = new Set([2, 3]),
 setC = new Set([3, 4, 5, 6]);

console.log ( isSuperset(setA, setB) );   // => true
console.log ( union(setA, setC) );        // => Set [1, 2, 3, 4, 5, 6]
console.log ( intersection(setA, setC) ); // => Set [3, 4]
console.log ( difference(setA, setC) );   // => Set [1, 2]
</script>
27. Как выделить все вхождения регулярного выражения в строку?

В нашем случае выделение сводится к подчёркиванию найденных вхождений, но принцип обработки не изменится и для других подобных задач.

<p id="result"></p>
<script>
 let str = 'Привет, я очередная строка текста "№;%::?6абв с цифрами 123 и буквами 456! Привет!!';
  //строка откуда-то
 let reg = /[а-яё]+/gi; 
  //регулярка, модификатор g - глобально, i - без регистра букв
 let res = selectByRegex (str,reg); //найти и выделить все вхождения reg в str
 document.getElementById('result').innerHTML = res ? res : 'не найдено';

 function selectByRegex (str,reg) { 
  //Аргументы - строка, регулярка. Вернёт строку, где всё найденное подчёркнуто (или null)
  let str2 = ''; 
  let matches = str.match (reg);
  if (!matches) return null;
  //console.log(matches);
  for (let m in matches) {
   let before = str.indexOf(matches[m]);
   if (before > -1) { //часть до вхождения
   let bstr = str.substring(0,before);
    str2 += bstr; //добавить в целевую строку
    str = str.substring (bstr.length); //и убрать из исходной
   }
   str2 += '<u>' + matches[m] + '</u>'; //подчеркнуть вхождения
   str = str.substring (matches[m].length); //и убрать обработанное
  }
  str2 += str; //хвост строки, если есть
  return str2;
 }
</script>
28. Почему я не могу ввести текст регулярного выражения в поле ввода или строку и потом использовать его в RegExp?

Потому что в поле формы (или в переменную) Вы вводите строку, а регулярное выражение - это объект. Помочь может показанный ниже код, который конструирует регулярку из поля ввода с id="regexp" и применяет её к строке из поля ввода с id="source". Сама функция обработки findAllRegexFromInput просто составляет массив из вхождений регулярного выражения в строку и возвращает строку со списком вхождений, разделённых переводами строк.

<p>
 Текст: <input type="text" size="80" id="source" 
  value="Привет, я очередная строка текста &quot;№;%::?6абв с цифрами 123 и буквами 456! Привет!!">
 RegExp: / <input type="text" size="15" id="regexp" value="[а-яё]+"> /
 <input type="checkbox" id="gFlag" checked><label for="gFlag">G</label>
 <input type="checkbox" id="iFlag" checked><label for="iFlag">I</label>
 <input type="button" value="Выполнить" 
  onclick="
   let str = document.getElementById('source').value,
    regStr = document.getElementById('regexp').value; 
    //В регулярке только основная часть, без обрамления / ... /
   let flags = '';
   if (document.getElementById('gFlag').checked) flags += 'g';
   if (document.getElementById('iFlag').checked) flags += 'i';
   let reg = new RegExp(regStr, flags); //Флаги приходится обрабатывать отдельно
   let res = findAllRegexFromInput (str, reg);
   document.getElementById('result').innerHTML = res ? res : 'не найдено';"
 >
</p>
<p id="result"></p>
<script>
 function findAllRegexFromInput (str, reg) { 
  let arr = []; 
  let matches = str.match (reg);
  if (!matches) return null;
  for (let m in matches) arr.push (matches[m]);
  return arr.join("<br>\n");
 }
</script>
29. Для внешнего файла .js вместо кириллицы в браузере показываются "кракозябры", хотя везде кодировка UTF-8. Как исправить?

Под "кракозябрами" имеется в виду, прежде всего, испорченный Юникод.

Если вдруг ваш сервер не отдаёт в заголовке HTTP-запроса кодировку для js-файлов, укажите дополнительный атрибут charset в теге подключения скрипта, то есть, не

<script src="js/script.js"></script>

а

<script src="js/script.js" charset="utf-8"></script>

Если проблема наблюдается с файлами на хостинге, разместите в папке со скриптами файл .htaccess с директивами

AddDefaultCharset utf-8
AddCharset utf-8 .html .css .js

30. Как преобразовать строку в последовательность Юникод-символов и наоборот?

То есть, "foo АЯая № bar" становится "foo \u0410\u042f\u0430\u044f \u2116 bar", а потом всё обратно.

<div id="result"></div>
<script>
 function chars2utf (s) {
  return s.replace (/[\u0080-\uFFFF]/g,
    function (s) { return "\\u" + ('000' + s.charCodeAt(0).toString(16)).substr(-4); }
  );
 }

 function utf2chars (s) {
  let decoded = JSON.parse('{"data": "'+ s +'"}'); //Декодируем обратно
   //метод escape устарел!
  return decoded.data;
 }

 let s = chars2utf('foo АЯая № bar');
 document.getElementById('result').innerHTML = s;
  // "foo \u0410\u042f\u0430\u044f \u2116 bar"
 s = utf2chars (s);
 alert (s); //foo АЯая № bar
</script>
<noscript>Включите Javascript в браузере!</noscript>

При декодировании в строке не должно быть двойных кавычек или они должны быть перед прямым преобразованием экранированы по принципу " -> \\"

31. Как получить callback-функцию из строки с записью нужного оператора?

"Опасная" функция eval не нужна. Просто укажите там, где нужна callback-функция, конструкцию вида

new Function(callback)()
где callback - строка с оператором Javascript. Пример (использует локальную копию мини-фреймворка Fader):

 <script src="http://blog.kislenko.net/archives/13965.js" charset="utf-8"></script>
 <script>
  let buttonsSwitch3 = true;
  function fadeDemo3(elem,value,callback) {
   if (buttonsSwitch3){
    Fader.fadeOutElement(elem, Math.abs(parseFloat(value)),
     new Function(callback)()
    );  
   }  
   else {
    Fader.fadeInElement(elem, Math.abs(parseFloat(value)),
     new Function(callback)()
    );
   }
   buttonsSwitch3 = !buttonsSwitch3;
  }
 </script>
 <p>Задержка анимации:
  <input type="number" id="fadeNumber3" min="0" max="1" value="0.1" step="0.1" size="3" maxlength="3">
  <input type="button" value="Выполнить" id="fadeButton3" 
   onclick="fadeDemo3(document.getElementById('fadeId3'),document.getElementById('fadeNumber3').value,
    document.getElementById('funcSelector').value);">
 </p> 
 <p>Выберите функцию для выполнения после эффекта:
  <select id="funcSelector">
   <option value="" selected>Ничего не делать</option>
   <option value="alert('ok')">Вывести окно сообщения</option>
   <option value="location.assign('http://disney.ru')">Перейти на другой сайт</option>
   <option value="document.body.style.backgroundColor = 'yellow'">Изменить фон страницы</option>
   <option value="location.reload()">Перезагрузить страницу</option>
  </select>
 </p>
 <p id="fadeId3"><i>Элемент для проверки эффектов "fadeOutElement"/"fadeInElement"</i></p>
 <p>На самом деле, из-за асинхронного выполнения Javascript функция необязательно 
  будет срабатывать после завершения эффекта.</p>

 Файл с фреймворком Fader из примера (прямая ссылка на файл .js) (3 Кб)

32. Как динамически создать "стек" элементов с обработчиками событий?

См. также пример 23. На самом деле, в том и удобство, что нет никакой разницы между элементами, прописанными в разметке и созданными динамически.

Например, здесь мы создаём "стек" из элементов <textarea> и назначаем динамически создаваемым элементам обработчики событий (клика по <textarea>).

<input type="button" onclick="addItem();" value="Добавить">
<input type="button" onclick="deleteItem();" value="Удалить">
</p>
<script>
 let i = 1;
 function addItem() {
  let elem = document.createElement('textarea');
  if (!elem) { alert ('Adding error'); return; }
  elem.setAttribute ('id','area_' + i);
  elem.setAttribute ('onclick','clickItem("area_' + i + '");');
  elem.value = i;
  document.body.appendChild (elem);
  i++;
 }
 function deleteItem() {
  let elem = document.getElementById('area_'+(i-1));
  if (!elem) { alert ('Deleting error'); return; }
  document.body.removeChild (elem);
  if (i > 1) i--;
 }
 function clickItem (id) {
  let elem = document.getElementById(id);
  if (!elem) return;
  alert ('Ok, my id is '+id);
 }
</script>
33. Как принудительно вывести вещественные числа с разделителем дробной части - запятой?

В примере пишем в элемент 10000 чисел, довольно быстро, так как split + join заведомо быстрее, чем RegExp.

<pre>
 <div id="resRandom"></div>
</pre>
<script>
let n = 10000, s = '';
for (let i=0; i<n; i++) {
 s += Math.random().toString().split('.').join(',') + "\n";
}
document.getElementById('resRandom').innerHTML = s;
</script>
34. Найти в строке или массиве наибольшее количество идущих подряд одинаковых элементов, возможно, исключая некоторые значения элементов из рассмотрения

Рассмотрим подход на конкретном примере. Задана строка с прописными и строчными буквами. Требуется, игнорируя прописные буквы, вывести длину той части массива, в которой повторяются друг за другом большее количество одинаковых строчных букв. Например, имея строку "AaaabBbc", получаем значение 3, потому что строчные буквы 'a' повторяются друг за другом 3 раза.

<script>
 let s = "AaaabbBbcaa";
 let arr = s.split('');
 console.log (arr);
 let item = arr[0], maxTimes = 1, currentTimes = 1;
 arr.reduce(function(prev, current) {
  if (prev === prev.toLowerCase() && prev === current) {
   currentTimes++;
   if (currentTimes > maxTimes) {
    maxTimes = currentTimes; item = current;
   }
  } 
  else {
   currentTimes = 1;
  }
  return current;
 });
 console.log (item, maxTimes);
</script>
35. Генерируем все подматрицы для матрицы

Вот вывод в консоль браузера всех возможных подматриц (от одного элемента до самой исходной матрицы) для заданной матрицы целых ненулевых значений.

Алгоритм примитивный, просто перебор, но реализует "вычёркивание" строк и столбцов (на основе двоичных чисел), а не просто выбор подматриц из элементов соседних строк и столбцов.

Для 2 на 2 проверил вручную, сошлось, будем надеяться, и для других размерностей нормально.

<script>
let m = [ //в данных не должно быть нулей!
 [11,12,13,14],
 [21,22,23,24],
 [31,32,33,34]
];
let r = m.length, c = m[0].length; //предполагаем, что все строки одного размера
let qr = Math.pow(2,r), qc = Math.pow(2,c), cnt = 0;
 //любая строка и столбец могут быть вычеркнуты или нет, всего 2 в степени (размер) вариантов
for (let i = 0; i < qr; i++) {
 for (let j = 0; j < qc; j++) {
  let index = new Array (r);
  for (let ii = 0; ii < r; ii++) {
   index[ii] = new Array (c);
   for (let jj = 0; jj < c; jj++) index[ii][jj] = 0;
  }  //Array(r).fill(Array(c).fill(0)) заполняло неправильно, частично дублируя m
  let q = 0;
  for (let kr = 0; kr < r; kr++) {
   for (let kc = 0; kc < c; kc++) {
    if (((i >> kr) & 1) == 1 && ((j >> kc) & 1) == 1) {
     //условие означает, что в kr-ой или kc-ой справа позиции числа i или j в двоичной записи стоит 1
     index[kr][kc] = m[kr][kc]; q++;
    }
   }
  }
  if (q) { //если были добавленные элементы - выводим подматрицу в консоль
   let s = (++cnt) +'\n';
   for (let ii = 0; ii < r; ii++) {
    for (let jj = 0; jj < c; jj++) {
     if (index[ii][jj] != 0) s += index[ii][jj] + ' ';
    }
    s += '\n';
   }
   console.log (s);
  }
 }
}
</script>
36. Как узнать или отобразить текущее время проигрывания аудио в соответствующем теге?
<audio id="track" src="http://upload.wikimedia.org/wikipedia/commons/a/a9/Tromboon-sample.ogg"
 ontimeupdate="document.getElementById('tracktime').innerHTML = 
  Math.floor(this.currentTime) + ' / ' + Math.floor(this.duration);">
   <p>Your browser does not support the audio element</p>
</audio>
<span id="tracktime">0 / 0</span>
<button onclick="document.getElementById('track').play();">Play</button>

Должно работать в "Хроме" и "Лисе", для других браузеров может понадобиться подключение аудио в другом формате.

37. Как вставить в массив или удалить из него значения, отвечающие заданным условиям?

Если стандартных методов массивов недостаточно или их применение трудоёмко, старая добрая поэлементная обработка ничем не хуже. Проще всего, если код формирует новый массив на основе исходного. Например: задан массив из n элементов и значение k. Вставить k перед каждым чётным элементом массива.

<script>
 const n = 5, k = 100;
 let arr = Array(n).fill(0).map(function(val,index) { return index+1; });
 console.log(arr); // [ 1, 2, 3, 4, 5 ]
 let res = [];
 arr.forEach (function (item, index) {
  if (item%2 == 0) res.push(k);
  res.push(item);
 });
 console.log(res);  // [ 1, 100, 2, 3, 100, 4, 5 ]
</script>

Имеются в виду чётные по значению элементы. Если требуется обработка чётных или нечётных индексов массива (напомним, что индексы считаются с нуля, при этом нулевой индекс тоже будет чётным), меняем строчку с условием на

  if (index%2 == 0) res.push(k);

38. Как не отправлять данные от пустых полей формы при нажатии кнопки submit?

Пример показывает форму с двумя текстовыми полями и кнопкой отправки данных. Если второе поле оставить пустым, данные от него не отправятся, что будет видно в адресной строке браузера url/имя_файла.html?param1=test или же url/имя_файла.html?param1=test¶m2=ok, если написать "ok" во втором поле перед отправкой.

При этом, совсем отправку мы здесь не отменяем, чтобы это сделать, нужно бы было вернуть false из функции checkForm. Но в таком случае учтите, что часть полей формы может остаться недоступными (disabled).

<form method="GET" id="myForm" onsubmit="return checkForm(this.id);">
 <input name="param1" value="test"/>
 <input name="param2" value=""/>
 <input type="submit" value="Submit">
</form>
<script>
function checkForm (id) {
 let arr = document.getElementById(id).elements,  
     len = arr.length,
     bads = 0;
 for (let i = 0; i < len; i++) {
  if (arr[i].value.trim() == '') {
   arr[i].disabled = true;
   bads++;
  }
 }
 return (bads >= len - 1 ? false : true);
}
</script>

Аналогично можно сделать "отбор" и для других типов полей ввода.

39. Как для всех браузеров ограничить обработку недопустимых значений из поля ввода числа, например, нужны только натуральные числа в заданном диапазоне?
 <input type="number" id="depth" value="7" min="5" max="9" step="1" maxlength="1" size="2">
 <input type="button" value="Выполнить" onclick="start();">
 <script>
  function digitsOnly (evt) {  //запрещаем всё, кроме цифр в числовом поле
   if (evt.which < 48 || evt.which > 57) { evt.preventDefault(); }
  }
  document.querySelector("#depth").addEventListener("keypress", function (evt) { digitsOnly (evt); });

  function start () {
   let depth = parseInt (document.getElementById('depth').value);
   if (isNaN(depth) || depth < 5 || depth > 10) { depth = 7; document.getElementById('depth').value = depth; }
   f (depth); 
  }
  window.addEventListener ('load', function (e) { start(); }, true); 

  function f (depth) {
   alert ('Я делаю что-то только с допустимыми значениями depth, сейчас это '+ depth);
  }
 </script>

Путь, кажущийся более простым - указать новый атрибут pattern для поля ввода. Но следует учесть, что встроенный в HTML5 контроль правильности ввода с помощью регулярного выражения работает только если применён тег <form> и кнопка отправки данных <input type="submit">, вызывающая перезагрузку страницы:

<form>
<p>Введите 3 цифры:
 <input type="input" maxlength="3" pattern="[0-9]{3}">
 <input type="submit" id="mybutton" value="Выполнить">
</p>
</form>
40. Как найти количество единичных бит в целом положительном числе?

Это можно сделать как с помощью стандартных функций:

<script>
 let n = 12345; //0011 0000 0011 1001
 let cnt = n.toString(2).split('').filter(function(x) { return x=='1'; }).length;
 console.log (cnt); //6
</script>

, так и "вручную" с помощью побитовых операций:

<script>
 let n = 12345, cnt = 0;
 while (n) {
  if (n & 1) cnt++;
  n >>= 1;
 }
 console.log (cnt); //6
</script>
41. Заполнить случайными числами целочисленную матрицу и обработать её

Для примера приведём "ручную" обработку матрицы с поиском в типовом двойном цикле минимальных элементов столбцов и выбора максимального из этих элементов.

Функция rnd(a,b) показывает также более корректный, чем обычно (не занижающий вероятность появления краевых значений интервала) способ генерации целых чисел, значения которых попадают в интервал [a,b].

<script>
 let n = 4, m = 3;
 let arr = Array(n).fill(0).map(() => {return Array(m).fill(0)});

 function rnd (min, max) { return Math.floor(min + Math.random() * (max + 1 - min)); }
 let a = -5, b = 5;
 for (let i =0; i < n; i++)
 for (let j =0; j < m; j++) arr[i][j] = rnd(a,b);
 
 console.log(arr);
 let mins = [], maxmin = Number.MIN_SAFE_INTEGER;
 for (let j = 0; j < m; j++) {
  mins[j] = arr[0][j];
  for (let i =1; i < n; i++) if (arr[i][j] < mins[j]) mins[j] = arr[i][j];
  if (mins[j] > maxmin) maxmin = mins[j];
 }
 console.log (mins);
 console.log (maxmin);
</script>
Пример вывода скрипта 41 в консоли браузера
Пример вывода скрипта 41 в консоли браузера
42. Получить массив 16-ричных цифр числа "вручную"

Объявить функцию xdigits(n), которая получает аргументом натуральное число n и возвращает массив 16-ичных цифр этого числа. В роли цифр выступают строки '1' '2'...'9', 'a', ...'f'. Младшие разряды должны стоять в конце массива. Не использовать стандартный метод toString.

<script>
 function xdigits (num) {
  let hex = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
  let result = [];
  while (num) {
   result.push (hex[num & 0xF]);
   num >>= 4;
  }
  return result.reverse();
 }
 alert (xdigits(32000));
</script>
43. Как собрать весь вывод консоли в отдельном контейнере, например, в элементе HTML?
<pre id="log"></div>
<script>
console.output = [];
console.log = (function() {
 return function() {
  console.output.push(...arguments);
 }
} (console.log));

//Проверка: 
console.log("Hello, world");
console.log([1,2,3]);
document.getElementById('log').innerText = console.output.join('\n');
</script>
44. Как отсортировать массив цветов по возрастанию или убыванию какой-либо цветовой компоненты?
<script>
let colors = [
  [255, 0, 100], [100, 100, 200], [200, 50, 100], [0, 100, 200]
];

colors.sort((a, b) => a[0] - b[0]);
console.log (colors);
</script>

Здесь массив приведён к удобном виду и отсортирован по возрастанию интенсивности красного цвета. Если нужно по убыванию, то b[0] - a[0], с остальными компонентами используем индексы 1 и 2.

Это и же ответ на вопрос "как отсортировать двумерный массив по числовым значениям какого-либо столбца"?

45. Как рассчитать число сочетаний из n элементов по k?

Считаем классическое число сочетаний без повторений, "цэшку" по len выбранных элементов из массива arr.

<script>
function comb (arr, len) {
 const combinations = [];
 if (len <= 1) {
  combinations.push(...arr.map((el) => [el]));
 } 
 else {
  for (let i = 0; i < arr.length; i++) {
   combinations.push (
    ...comb(arr.slice(i + 1), len - 1).map((array) => [arr[i], ...array])
   );
  }
 }
 return combinations;
}
const arr = [1,2,3,4,5];
console.log(comb(arr, 3)); //10 сочетаний
</script>
46. Кнопка, которая при нажатии ведёт монолог и просит её не нажимать

В учебно-развлекательных целях :) Листинг можно сохранить как документ типа .html в кодировке Юникода UTF-8, а полезный код вставить, например, перед вызовом setTimeout.

<!DOCTYPE html>
<meta charset="utf-8">
<script>
 let counter = null, index = -1, indexIn = -1;
 function doMe (id) {
  let elem = document.getElementById(id);
  if (!elem) { alert('Нет элемента с id='+id); return; }
  let cmsg = '';
  let msgs = [
   'Я же сказал, не нажимай!','Ну хватит!','С тобой говорить бесполезно.','x ОТВАЛИ, ДОСТАЛ! x'
  ];
  if (counter) {
   indexIn = -1;
   if (index > -1) index--;
  }
  function nextStep() {
   if (indexIn == -1) {
    indexIn = 0;
    index++;
    if (index < msgs.length) {
     cmsg = msgs[index];
     elem.value='';
    }
    else {
     index = - 1;
     elem.value = 'Не нажимай меня';
    }
   }
   else {
    elem.value += cmsg.charAt (indexIn);
    indexIn++;
   }
   if (counter) {
    clearTimeout (counter);
    counter = null;
   }
   if (indexIn == cmsg.length) {
    indexIn = -1;
    return;
   }
   counter = setTimeout(nextStep, 100);
  }
  nextStep();
 }
</script>
<input type="button" id="btn" value="Не нажимай меня" onclick="doMe(this.id);">
47. Проверить, попадает ли дата из элемента HTML в интервал дат

А также: как получить дату из элемента <input type="date">, как выставить туда текущую дату по загрузке странице, как получить через getTime метку времени от элемента, чтобы легко сравнивать даты.

Даты для интервала можно было получать просто из строк формата ГГГГ-ММ-ДД, например

  let from = new Date("2022-01-01").getTime(),
      to = new Date("2022-12-31").getTime();

Код можно запустить как документ типа .html в кодировке Юникода UTF-8.

<!DOCTYPE html>
<meta charset="utf-8">
<script>
 function dateInInterval (d1,d0,d2,dr) {
  let d1_elem = document.getElementById(d1),
      d0_elem = document.getElementById(d0),
      d2_elem = document.getElementById(d2),
      dr_elem = document.getElementById(dr);
  if (!d1_elem || !d0_elem || !d2_elem || !dr_elem) { 
   alert('Нет элемента с одним из id: '+d1+','+d0+','+d2+','+dr); 
   return; 
  }
  if (!d0_elem.value || !d1_elem.value || !d2_elem.value) {
   dr_elem.innerText = 'Пожалуйста, выберите корректные даты во всех полях ввода'; 
   return; 
  }
  let today = new Date(d0_elem.value).getTime(),
      from = new Date(d1_elem.value).getTime(),
      to = new Date(d2_elem.value).getTime();
  if (from > to) {
   let temp = from; from = to; to = temp;
   temp = d1_elem.value; d1_elem.value = d2_elem.value; d2_elem.value = temp;
  }
  if (today >= from && today <= to) dr_elem.innerText = 'Дата попадает в интервал';
  else dr_elem.innerText = 'Дата не попадает в интервал';
 }
  
 window.addEventListener('load', 
  function (e) {
   let d = new Date(), day = d.getDate(), month = d.getMonth() + 1, year = d.getFullYear(); 
   if (day<10) day='0'+day;
   if (month<10) month='0'+month;
   document.getElementById("mydate").value = year+"-"+month+"-"+day;
  }, false
 );
</script>

<div>Попадание даты в интервал</div>
<p>
 Дата 1: <input type="date" id="date1">
 Моя дата: <input type="date" id="mydate">
 Дата 2: <input type="date" id="date2">
 <input type="button" value="Проверить" onclick="dateInInterval('date1','mydate','date2','dateres')">
</p>
<div id="dateres"></div>
48. Найти в заданном интервале годы, в которых 53, а не 52 недели

...При нумерации недель по ISO.

<script>
let isLongYear = (year) => {
 let jan1 = new Date(year, 0, 1);
 let dec31 = new Date(year, 11, 31);
 return (4 == jan1.getDay() || 4 == dec31.getDay())
}

let result = ''; 
for (let y = 1800; y <= 2100; y++) {
  if (isLongYear(y)) result += y + ' ';
}
console.log (result);
</script>
<p>See results in JS console</p>
49. Как "прокрутить" массив влево или вправо на произвольное целое количество шагов?
<script>
 function arrayRotate (arr, count) {
  let len = arr.length;
  arr.push(...arr.splice(0, (-count % len + len) % len));
  return arr;
 }
 
 for (let i = -6 ; i <= 6 ; i++) {
  console.log('i='+i);
  let arr = [1,2,3,4,5,6];
  console.log(arrayRotate(arr, i));
 }
</script>
<p>See results in JS console</p>
50. Как назначить обработчик клика по ячейке таблицы сразу для всех её ячеек?

Также показано как программно сформировать таблицу заданной размерности в родительском разделе div.

<style>
 .table_ {
  margin: 0 auto;
  border-collapse: collapse;
 }
 .td_ {
  width: 5rem;
  height: 2rem;
  padding: 0;
  border: 1px solid black; 
  text-align: center;
  vertical-align: middle;
   font-size: 1rem;
 }
</style>
<div id="elem"></div>
<script>
function createTable(rows, cols, parent) {
 //формирование таблицы:
 let table = document.createElement('table');
 table.className = 'table_';
 for (let row = 0; row < rows; row++) {
  let tr = document.createElement('tr');
  tr.setAttribute('id','tr_'+row);
  for (let col = 0; col < cols; col++) {
   let td = document.createElement('td');
   td.setAttribute('id','td_'+row+'_'+col);
   td.className = 'td_';
   td.innerHTML = String(row*col);
   tr.appendChild(td);
  }
  table.appendChild(tr);
 }
 parent.appendChild(table); 
 //назначение обработчика события клика по ячейкам:
 table.addEventListener('click', function (e) {
  let cell = e.target.closest('td');
  if (!cell) return;
  let row = cell.parentElement;
  //узнали число из ячейки, номер строки номер столбца:
  let val = parseInt(cell.innerHTML), r = parseInt(row.rowIndex), c = parseInt(cell.cellIndex);
  alert(val + ' ' +  r + ' ' + c);
 });
}

let div = document.querySelector('#elem');
createTable(6, 5, div);
</script>
51. Как сделать кнопку "Сохранить" для канвы с возможностью ввода имени файла?

Вот самый простой путь.

<canvas id="canvas" style="border: 1px dotted red;"></canvas>
<button id="save" type="button">Save</button>
<script> 
 //отрисовка
 let canvas = document.getElementById('canvas'), w = canvas.width, h = canvas.height;
 let ctx = canvas.getContext( "2d" );
 ctx.fillStyle = "#fff"; 
 ctx.fillRect (0, 0, w, h); 
 ctx.fillStyle = "#f00"; 
 ctx.fillRect (w/3, h/3, w/3, h/3);

 //сохранение
 let saveButton = document.getElementById("save");
 saveButton.addEventListener("click", function () {
  let imageName = prompt("Введите имя картинки [canvas]");
  let canvasDataURL = canvas.toDataURL();
  let a = document.createElement("a");
  a.href = canvasDataURL;
  a.download = imageName || "canvas";
  a.click();
 });
</script>

26.04.2020, 15:25 [3425 просмотров]


теги: учебное javascript список алгоритм избранное

К этой статье пока нет комментариев, Ваш будет первым