Pull to refresh

Замена стандартному switch в javascript

Так уже вышло что javascript был написан за 10 дней и у него много проблем с отсутствием единого синтаксиса. Особенно меня огорчает конструкция switch...case о ней и пойдёт речь ниже.


Часто возникает потребность выбрать из нескольких значений и в js для этого приходится писать нечто ужасающее:

switch (value) {
case "value1":
doSomething()
break
case "value2":
doSomethingElse()
break
default:
orDoDefault()
}


Какие собственно недостатки?
Во-первых, не хочется после каждого варианта писать break, иначе будут выполнены все действия, которые описаны после совпавшего варианта при сравнении. Мне это напоминает bat скрипты с архаичными безусловными GOTO переходами.
Во-вторых, хотелось бы что бы можно было работать с объектами, массивами, функциями и самое главное — регулярными выражениями. И что бы это всё было ближе к функциональному, а не процедурному программированию.

Идея вынашивалась давно, годных вариантов ранее я не встречал и поэтому решил написать миниатюрную функцию, которая делала бы всё что я от неё хочу. Вот она:

function swtch(arg,cases){
  return (typeof arg=='string'||typeof arg=='number')
    ?cases[arg]
      ?cases[arg]
      :cases['default']||arg
    :typeof arg=='object'
      ?(function(){
        var ret=arg instanceof Array?[]:{}
          ,i
        if(arg.constructor===RegExp)
          for(i in cases)
            cases.hasOwnProperty(i)&&arg.test(i)&&(ret[i]=cases[i])
        else
          for(i in arg)
            if(arg.hasOwnProperty(i))
              ret[i]=swtch(arg[i],cases)
        return ret
      })()
      :typeof arg=='function'
        ?swtch(arg(),cases)
        :arg
}


cases — это хеш-массив значений, среди которых происходит поиск по переданному первому аргументу.
Если значение не найдено в cases, то будет возвращен сам аргумент, либо то что находится в cases.default
Пример:

swtch('1',{
  "1":'one'
  ,"2":'two'
}) // возвращает 'one'

swtch(2,{
  "1":'one'
  ,"2":'two'
}) // возвращает 'two'

swtch(3,{
  "1":'one'
  ,"2":'two'
}) // возвращает 3

swtch(3,{
  "1":'one'
  ,"2":'two'
  ,default:'default value'
}) // возвращает default value


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

swtch([1,2],{
  "1":'one'
  ,"2":'two'
}) // возвращает ['one','two']

swtch({a:1,b:2},{
  "1":'one'
  ,"2":'two'
}) // возвращает {a:'one',b:'two'}


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

Переданное регулярное выражение будет применено методом .test() к каждому ключу cases и в тех случаях, когда оно true, значения по этим ключам будут собраны в объект, который и вернет функция.
Пример:

swtch(/\d/,{
  "1":'one'
  ,"2":'two'
  ,"foo":'first string'
  ,"bar":'second string'
}) // возвращает {"1":'one',"2":'two'}

swtch(/\D/,{
  "1":'one'
  ,"2":'two'
  ,"foo":'first string'
  ,"bar":'second string'
}) // возвращает {"foo":'first string',"bar":'second string'}


На изобретение велосипеда Я не претендую, это скорее тренировка мозгов для тех кто решил стать на путь js-джедая ну и просто демонстрация, на мой взгляд, изящного обхода фундаментального изъяна в популярном языке программирования.
На этом пожалуй всё.
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.