【译】为何我更喜好对象而不是switch语句

原文自工程师Enmanuel Durán博客,
传送门

近来(或许不是近来,这完整取决于您什么时刻浏览这边文章),我正在跟我的团队同伴议论怎样去处置惩罚这类须要依据差别的值去处置惩罚差别的状况的要领,一般关于这类状况下,人们喜好运用switch语句或许运用许多if搭配else if前提。在本文中我将重点引见第三种体式格局(我更加喜好的要领),即运用对象举行疾速地查找。

switch 语句

switch语句许可我们依据通报的表达式的值来实行表达式并实行某些特定的操纵,一般当你进修编写代码和算法时,你会发明能够将它特地用于多种值的状况,你最先运用它,它看起来很好,你很快意想到它给了你很大的自在,耶!然则要警惕,自在度越大责任感也就越大。

让我们疾速相识一下典范的switch语句是怎样的:

switch (expression) {
    case x: {
        /* Your code here */
        break;
    }
    case y: {
        /* Your code here */
        break;
    }
    default: {
        /* Your code here */
    }
}

很好,如今有一些你能够不晓得须要注重的事变:

可选的关键字break

break关键字许可我们在满足前提时住手实行块。假如不将break关键字添加到switch语句,则不会抛出毛病。假如我们不警惕遗忘break的话,能够意味着在实行代码的时刻你以至不晓得代码已正在实行中了,这还会在调试题目时增添完成效果的的不一致性、突变、内存走漏和复杂度等题目。我们来看看这个题目的一种示意情势:

switch ('first') {
    case 'first': {
        console.log('first case');
    }
    case 'second': {
        console.log('second case');
    }
    case 'third': {
        console.log('third case');
        break;
    }
    default: {
        console.log('infinite');
    }
}

假如你在掌握台中实行这段代码,你会看到输出是

firt case
second case
third case

switch语句在第二种和第三种状况下也会实行,纵然第一种状况已是准确的,然后它在第三种状况块中找到关键字break并住手实行,掌握台中没有正告或毛病让你晓得它,这会让你以为这是预期的行动。

每种状况下的大括号都不是强迫的

在javascript中大括号代表着代码块,因为自ECMAscript 2015我们能够运用关键字声明块编译变量,如const或let(但关于switch来讲并非很好),因为大括号不是强迫性的,反复声明会致使毛病变量,让我们看看当我们实行下面的代码时会发作什么:

switch ('second') {
    case 'first':
        let position = 'first';
        console.log(position);
        break;
    case 'second':
        let position = 'second';
        console.log(position);
        break;
    default:
        console.log('infinite');
}

我们会获得:

Uncaught SyntaxError: Identifier ‘position’ has already been declared

这里将会返回一个毛病,因为变量position已在第一种状况下声明过了,而且因为它没有大括号,所以在第二种状况下尝试声明它,它已存在了。

如今设想运用带有不一致break关键字和大括号的switch语句时会发作什么事:

switch ('first') {
    case 'first':
        let position = 'first';
        console.log(position);
    case 'second':
        console.log(`second has access to ${position}`);
        position = 'second';
        console.log(position);
    default:
        console.log('infinite');
}

掌握台将输出以下内容:

first
second has access to first
second
infinite

试想一下,由此而引发的毛病和突变是云云之多,其能够性是无穷无尽的……不管怎样,switch语句已讲够了,我们来这里是为了议论一种差别的要领,我们来这里是为了议论对象。

更平安查找的对象

对象查找速率很快,跟着它们的大小增进它们也会更快,它们也许可我们将数据示意为关于前提实行异常有效的键值对。

运用字符串

让我们从简朴的switch示例最先,让我们假定我们须要有前提地保留和返回一个字符串的情形,并运用我们的对象:

const getPosition = position => {
    const positions = {
        first: 'first',
        second: 'second',
        third: 'third',
        default: 'infinite'
    };

    return positions[position] || positions.default;
};

const position = getPosition('first'); // Returns 'first'
const otherValue = getPosition('fourth'); // Returns 'infinite'

这能够做一样范例的事情,假如你想进一步的紧缩简化代码,我们能够应用箭头函数:

const getPosition = position =>
    ({
        first: 'first',
        second: 'second',
        third: 'third'
    }[position] || 'infinite');

const positionValue = getPosition('first'); // Returns 'first'
const otherValue = getPosition('fourth'); // Returns 'infinite'

这与前面的完成完整相同,我们在更少的代码行中完成了更紧凑的处理计划。

如今让我们更现实一点,不是我们写的一切前提都邑返回简朴的字符串,个中许多会返回布尔值,实行函数等等。

运用布尔值

我喜好建立返回范例一致的值的函数,然则,因为javascript是动态范例言语,因而能够存在函数能够返回动态范例的状况,因而我将在此示例中斟酌这一点,假如找不到键,我将建立一个返回布尔值,未定义或字符串的函数。

const isNotOpenSource = language =>
    ({
        vscode: false,
        sublimetext: true,
        neovim: false,
        fakeEditor: undefined
    }[language] || 'unknown');

const sublimeState = isNotOpenSource('sublimetext'); // Returns true

看起来不错,对吧?别急,彷佛我们有一个题目……假如我们挪用带有参数的函数,会发作什么’vscode’或fakeEditor不是?嗯,让我们来看看:

  1. 它会寻觅对象中的键。
  2. 它会看到vscode键的值是false。
  3. 它会试图返回false,但因为false || ‘unknown’是unknown,我们最终会返回一个不准确的值。

关于key为fakeEditor也会有一样的题目

Oh no, 好吧,不要惊惶,让我们来处理这个题目:

const isNotOpenSource = editor => {
    const editors = {
        vscode: false,
        sublimetext: true,
        neovim: false,
        fakeEditor: undefined,
        default: 'unknown'
    };

    return editor in editors ? editors[editor] : editors.default;
};

const codeState = isNotOpenSource('vscode'); // Returns false
const fakeEditorState = isNotOpenSource('fakeEditor'); // Returns undefined
const sublimeState = isNotOpenSource('sublimetext'); // Returns true
const webstormState = isNotOpenSource('webstorm'); // Returns 'unknown'

这就处理了题目,然则……我愿望你们问本身一件事:这真的是题目所在吗?我以为我们应当更体贴为何我们须要一个返回布尔值,未定义值或字符串的函数,这里存在严峻的不一致性,无论怎样,关于如许一个异常辣手的状况这也只是一个能够的处理计划。

运用函数

我们继承讲函数,一般我们会发明我们须要依据参数来实行一个函数,假定我们须要依据输入的范例来剖析一些输入值,假如剖析器没有注册,我们只返回值:

const getParsedInputValue = type => {
    const emailParser = email => `email,  ${email}`;
    const passwordParser = password => `password, ${password}`;
    const birthdateParser = date => `date , ${date}`;

    const parsers = {
        email: emailParser,
        password: passwordParser,
        birthdate: birthdateParser,
        default: value => value
    };

    return parsers[type] || parsers.default;
};

// We select the parser with the type and then passed the dynamic value to parse
const parsedEmail = getParsedInputValue('email')('myemail@gmail.com'); // Returns email, myemail@gmail.com
const parsedName = getParsedInputValue('name')('Enmanuel'); // Returns 'Enmanuel'

假如我们有一个相似的函数返回另一个函数但这次没有参数,我们能够革新代码,以便在挪用第一个函数时直接返回,如:

const getValue = type => {
    const email = () => 'myemail@gmail.com';
    const password = () => '12345';

    const parsers = {
        email,
        password,
        default: () => 'default'
    };

    return (parsers[type] || parsers.default)(); // we immediately invoke the function here
};

const emailValue = getValue('email'); // Returns myemail@gmail.com
const passwordValue = getValue('name'); // Returns default

通用代码块

Switch语句许可我们为多个前提定义大众代码块。

switch (editor) {
    case 'atom':
    case 'sublime':
    case 'vscode':
        return 'It is a code editor';
        break;
    case 'webstorm':
    case 'pycharm':
        return 'It is an IDE';
        break;
    default:
        return 'unknown';
}

我们怎样运用对象来处置惩罚它?我们能够鄙人一个方面做到这一点:

const getEditorType = type => {
    const itsCodeEditor = () => 'It is a code editor';
    const itsIDE = () => 'It is an IDE';

    const editors = {
        atom: itsCodeEditor,
        sublime: itsCodeEditor,
        vscode: itsCodeEditor,
        webstorm: itsIDE,
        pycharm: itsIDE,
        default: () => 'unknown'
    };

    return (editors[type] || editors.default)();
};

const vscodeType = getEditorType('vscode'); 

如今我们有一种要领:

  1. 更有层次
  2. 更轻易拓展
  3. 更轻易保护
  4. 更轻易测试
  5. 更平安而且副作用和风险更小

注重事项

正如预期的那样,一切的要领都有其瑕玷,这一个也不破例。

  1. 因为我们正在运用对象,所以我们将占用内存中的一些暂时空间来存储它们,当定义对象的作用域不再可接见时,这个空间将被渣滓收集器开释。
  2. 当没有太多状况须要处置惩罚时,对象要领能够比switch语句的速率要慢,这能够是因为我们正在建立一个数据结构,然后吸收一个键,然而在switch中,我们只是搜检值并返回值。

结论

本文不盘算转变你的编码作风或让你住手运用switch语句,它只是试图进步你对switch语句的熟悉,以便它能够准确运用,并开放你的头脑探究新的替换计划,在这类状况下,我已分享了我喜好运用的要领,但另有更多,比方,你能够想看一个称为形式婚配的ES6提案,假如你不喜好它,你能够继承探究。

好的开辟将来,就是如许,我愿望你喜好这篇文章,假如你如许做,你能够会喜好这篇关于工场形式的文章。另外,不要遗忘分享和点赞,你能够在twitter上找到我或经由过程我的电子邮件duranenmanuel@gmail.com联络我,下一个见。

浏览EnmaScript.com上宣布的原始文章

译者总结

本文引见了一种运用对象去替代我们之前用switch和烦琐的if else语句的要领。实在,许多状况下我们能够应用对象与其他组合搭配写出更加高效或可保护的代码。固然,怎样去天真地运用对象去处置惩罚一些对应的状况,照样靠我们本身。好的,这篇就总结到这了,不晓得对你们有什么启示。置信会给到一些协助给读者,我们可不是一个只会if else的工程师,哈哈~

    原文作者:suan_suan
    原文地址: https://segmentfault.com/a/1190000018324041
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞