Делаем условную функцию более эффективной - PullRequest
4 голосов
/ 24 мая 2019

Я хочу создать функцию, которая модифицирует переменную на основе заданного аргумента.

Функция проверяет переменную и число в этой строке. Затем с помощью аргумента я указываю либо увеличить, либо уменьшить число на 1 (++ 1).

Также существует массив, который, если число равно длине массива, тогда он становится равным 1, а если число меньше 1, то оно равно размеру массива. Это сделано для того, чтобы номер строки не превышал 1 или больше длины массива.

строка с номером Music1. Таким образом, круг будет выглядеть так: ...., Music1, Music2, Music3, Music4, Music1, Music2, Music3, ....

var MyArray = ["Music1", "Music2", "Music3", "Music4"];
var currentMusic = "Music1";

$(".increase").on('click tap', nextMusic);
$(".decrease").on('click tap', previousMusic);

function nextMusic() {
  unaryChange('plus')
}

function previousMusic() {
  unaryChange('minus')
}

function unaryChange(operation) {
  if (currentMusic === "Music4") {
    currentMusic = "Music1"
  } else if (currentMusic === "Music0") {
    currentMusic = "Music4"
  }
  if (operation === "plus") {
    currentMusic = currentMusic.replace(/\d+$/, function(n) {
      return ++n
    });
  } else {
    currentMusic = currentMusic.replace(/\d+$/, function(n) {
      return --n
    });
  }

  console.log(currentMusic);
  $(".text").text(currentMusic);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<button class="increase">increase</button>
<button class="decrease">decrease</button>
<p class="text">value</p>

Вышеуказанный метод почти справляется со своей задачей, однако я ищу более простое и профессиональное решение. Это не выглядит эффективным. Например, должен быть лучший способ указать аргумент operation вместо строки типа plus или условий.

Мне нужно, чтобы эта функция была переписана лучше, более профессионально и работала, как описано.

Заранее спасибо.

Ответы [ 6 ]

4 голосов
/ 24 мая 2019

Лучше работать с индексом массива, а не со значениями

function unaryChange(operation) {
  var currentIndex = MyArray.findIndex(function(item) {
    return item === currentMusic;
  });

  if(operation === 'plus') {
    newIndex = currentIndex < MyArray.length - 1 && currentIndex + 1 || 0;
  } else {
    newIndex = currentIndex > 0 ? currentIndex -1 : MyArray.length -1;
  }

  currentMusic = MyArray[newIndex]
  $(".text").text(currentMusic);
}

В этом случае, независимо от размера массива, он будет работать.

Рабочий пример https://jsbin.com/rahomorupa/4/edit?html,js,console,output

3 голосов
/ 24 мая 2019

Опираясь на ответ Джо Я бы посоветовал вам определить константы для plus и minus как +1 и -1 соответственно, чтобы упростить логику увеличения / уменьшения, наряду с оператор модуля для обработки обтекания массива:

const PLUS = 1;
const MINUS = -1;

function unaryChange(operation) {
  var currentIndex = MyArray.findIndex(function(item) {
    return item === currentMusic;
  });

  // If it's invoked as unaryChange(PLUS) or unaryChange(MINUS)
  // we don't need any conditional logic to handle the increment,
  // and with the % operator we don't need additional bounds overflow
  // logic. (This latter bit is complicated somewhat by the need to
  // handle a minus step from index 0.)
  const {length} = MyArray;
  const newIndex = ((currentIndex + operation) % length + length) % length;

  currentMusic = MyArray[newIndex]
  $(".text").text(currentMusic);
}

Оператор% возвращает остаток от деления, который удобно возвращается к 0 при использовании с индексом массива по длине массива.:

const array = ['first', 'second', 'third'];

for (let i = 0; i < 20; i++) {
  console.log(array[i % array.length]);
}
2 голосов
/ 24 мая 2019

Вы можете передать логическое значение для plus, использовать функцию стрелки и троичный оператор:

var MyArray = ["Music1", "Music2", "Music3", "Music4"];
var currentMusic = "Music1";

$(".increase").on('click tap', nextMusic);
$(".decrease").on('click tap', previousMusic);

function nextMusic() {
  unaryChange(true)
}

function previousMusic() {
  unaryChange(false)
}

function unaryChange(plus) {
  currentMusic = currentMusic == "Music4" ? "Music1" : (currentMusic == "Music0" ? "Music4" : currentMusic);
  currentMusic = currentMusic.replace(/\d+$/, n => plus ? ++n : --n);
  console.log(currentMusic);
  $(".text").text(currentMusic);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<button class="increase">increase</button>
<button class="decrease">decrease</button>
<p class="text">value</p>
1 голос
/ 24 мая 2019

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

Поскольку мы хотим быть между границами 0 и длиной массива, вот что используется для этого:

  • Получить следующую песню: (currentTrackIndex + 1) % tracks.length. Это позволит получить следующее значение индекса и применить к нему по модулю, чтобы оно округлялось назад, если оно превышает длину массива.
  • Получить предыдущую песню: (currentTrackIndex - 1 + tracks.length) % tracks.length. Это почти то же самое, что получить следующую песню, за исключением случая, когда индекс уже на нуле. Если вы примените модуль по отрицательному числу, вы получите отрицательный результат и испортите индекс вашего массива. Поэтому вместо использования условного предложения ("if (currentTrackIndex === 0 ...)") давайте добавим длину массива. Зачем? Поскольку начиная с 0 % n == 0 и n % n == 0, добавление длины массива не изменит результат по модулю, сохраняя при этом ваш индекс как положительное число.

(я изменил имя с MyArray на tracks и unaryChange на changeTrack, чтобы лучше понять смысл)

var tracks = ["Music1", "Music2", "Music3", "Music4"];

var currentTrackIndex = 0;

$(".increase").on('click tap', nextMusic);
$(".decrease").on('click tap', previousMusic);

function nextMusic() {
  //It will move to the next track. If it's over the array length, it will reset to 0
  changeTrack((currentTrackIndex + 1) % tracks.length)
}

function previousMusic() {
  //It will move to the previous song. If it's below zero, it will reset to the last track index
  changeTrack((currentTrackIndex + tracks.length - 1) % tracks.length)
}

function changeTrack(newTrackIndex) {
  currentTrackIndex = newTrackIndex;
  var currentTrack = tracks[currentTrackIndex];
  console.log(currentTrackIndex);
  $(".text").text(currentTrack);
}
1 голос
/ 24 мая 2019

Вот как бы я это сделал. Поскольку кажется, что слово «Музыка» - это просто префикс, используемый для обозначения конкретного устройства, я не буду хранить его снова и снова в массиве. Что касается jQuery? Да, нет.

"use strict";
function byId(id){return document.getElementById(id)}

window.addEventListener('load', onLoaded, false);

function onLoaded(evt)
{
	let prefix = 'Music';
	let count = 4, index=0;
	byId('increase').addEventListener('click', function(evt){index++; index %= count; update();}, false);
	byId('decrease').addEventListener('click', function(evt){index--; if (index<0) index=count-1; update();}, false);
	
	function update()
	{
		byId('status').textContent = `${prefix}${index+1}`;
	}
}
<span id='status'>Music1</span><br>
<button id='increase'>+</button><button id='decrease'>-</button>
1 голос
/ 24 мая 2019

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

var MyArray = ["Music1", "Music2", "Music3", "Music4"];
var currentMusic = 0;

$(".increase").on('click tap', unaryChange);
$(".decrease").on('click tap', unaryChange);

function unaryChange() {
  if (event.target.className === "increase") {
    currentMusic = (currentMusic < 3 ? currentMusic + 1 : 0)
  } else {
    currentMusic = (currentMusic > 0 ? currentMusic -= 1 : 3) 
  }
  console.log(MyArray[currentMusic]);
  $(".text").text(MyArray[currentMusic]);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<button class="increase">increase</button>
<button class="decrease">decrease</button>
<p class="text">value</p>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...