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

30 Ноя
2011

Так уже вышло что 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-джедая ну и просто демонстрация, на мой взгляд, изящного обхода фундаментального изъяна в популярном языке программирования.
На этом пожалуй всё.
По материалам Хабрахабр.



загрузка...

Комментарии:

Наверх