Категоризация номера в JavaScript

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

var getSize = function(number){
        var sizes = {
            100 : 'url_t',
            240 : 'url_s',
            320 : 'url_n',
            500 : 'url_m',
            640 : 'url_z',
            800 : 'url_c',
            1024 : 'url_l',
        },
        result = sizes[100];

    for (var size in sizes){
        if(number < size){
            result = sizes[size];
            break;
        }
        result = sizes[1024];
    }
    return result;
};
getSize(10) // returns url_t
getSize(130) // returns url_s
getSize(2000) // returns url_l
getSize(600) // returns url_z

Это работает, и это довольно показательно, это просто немного нехорошо. Я попытался придумать лучшее решение, но это просто неприятно. Есть ли что-то, что мне не хватает, что бы сделать это немного лучше? Я играл с помещением размеров в массив, поэтому они немного больше JSON-ish, но потом я заблудился.

11 голосов | спросил Sam Beckham 22 J000000Tuesday14 2014, 19:12:21

5 ответов


12

Вам может не понадобиться прокручивать объект, и достаточно простого выражения switch.

function getSize(number) {
    switch (true) {
        case number < 100: return "url_t";
        case number < 240: return "url_s";
        case number < 320: return "url_n";
        case number < 500: return "url_m";
        case number < 640: return "url_z";
        case number < 800: return "url_c";
        default:           return "url_l";
    }
}

В качестве побочного примечания, кажется, люди используют switch (true) раньше, когда они хотят использовать некоторую логику в своем case 'вместо строгих кодированных значений. Вид хорошей альтернативы конструкции if-else и, вероятно, будет работать лучше, чем цикл над объектом с помощью for-in.

Вы все равно можете сохранить размеры в объекте:

var sizes = {
    100 : 'url_t',
    240 : 'url_s',
    320 : 'url_n',
    500 : 'url_m',
    640 : 'url_z',
    800 : 'url_c',
    1024 : 'url_l'
};

function getSize(number) {
    switch (true) {
        case number < 100: return sizes[100];
        case number < 240: return sizes[240];
        case number < 320: return sizes[320];
        case number < 500: return sizes[500];
        case number < 640: return sizes[640];
        case number < 800: return sizes[800];
        default:           return sizes[1024];
    }
}

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

ответил Greg Burghardt 22 J000000Tuesday14 2014, 19:39:36
5
  • Конструкция for..in должна содержать Object.hasOwnProperty проверьте в крайне маловероятном случае, что кто-то решает злоупотреблять прототипами (и на Object, не менее!).
  • Ваш отступ немного непоследовательный.
  • Вы произвольно назначаете переменную result.
  • Некоторые значения жестко закодированы, но их не должно быть. По крайней мере, переместите их в константу, а не оставляйте их как магические числа.

Вы можете попробовать что-то вроде следующего:

var getSize = function(number) {
    var MAX_SIZE = 1024;

    var result;
    var sizes = {
        100: 't',
        240: 's',
        320: 'n',
        500: 'm',
        640: 'z',
        800: 'c',
        1024: 'l'
    };

    for (var size in sizes) {
        if (sizes.hasOwnProperty(size)) {
            if (number < size) {
                result = sizes[size];
                break;
            }
        }
    }
    return "url_" + (result || sizes[MAX_SIZE]);
}

Кстати, намеренно ли это, что getSize(100) вернет url_s вместо url_t? Если нет, просто измените < выше на <=


Revision . Еще лучше, мы можем использовать Object.keys(). Преимущество состоит в том, что он полностью не зависит от магических чисел; вместо этого мы можем просто изменить наш sizeMap объект по мере необходимости. Кроме того, это касается беспокойства @ megawac о неопределенном перечислении for...in.

var getSize = function(number) {
    var result;
    var sizeMap = {
        100: 't',
        240: 's',
        320: 'n',
        500: 'm',
        640: 'z',
        800: 'c',
        1024: 'l'
    };

    var sizes = Object.keys(sizeMap).sort(function(a, b) {
        return a - b;
    });

    for (var i = 0; i < sizes.length; i++) {
        if (number < sizes[i]) {
            result = sizeMap[sizes[i]];
            break;
        }
    }
    return "url_" + (result || sizeMap[sizes[sizes.length - 1]]);
}
ответил Schism 22 J000000Tuesday14 2014, 19:27:16
3

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

Итак, вот как я напишу ваш getSize. Вы можете использовать Object.keys(sizes), чтобы создать список диапазонов, но снова - порядок не gaurenteed. Вы можете сортировать его, я полагаю?

var getSize = (function() {
    var sizes = {
        100 : 'url_t',
        240 : 'url_s',
        320 : 'url_n',
        500 : 'url_m',
        640 : 'url_z',
        800 : 'url_c',
        1024 : 'url_l',
    };
    // Note you can do Object.key(sizes); to create this list
    var ranges = [100, 240, 320, 500, 640, 800, 1024];

    return function(number) {
        for (var i = 0, len = ranges.length; i < len; i++) {
            var key = ranges[i];
            if (number < key) {
                return sizes[key];
            }
        }
        // otherwise return the largest size
        return sizes[key];
    };
})();

Это может быть слишком много, но я также создал sizes и ranges один раз

ответил megawac 22 J000000Tuesday14 2014, 19:51:01
2

Я бы выбрал вариант Greg , но я бы инвертировал размеры карты для устранения магических чисел:

var sizes = {
    url_t : 100,
    url_s : 240,
    url_n : 320,
    url_m : 500,
    url_z : 640,
    url_c : 800,
    url_l : 1024
};

function getSize(number) {
    switch (true) {
        case number < sizes.url_t: return 'url_t';
        case number < sizes.url_s: return 'url_s';
        case number < sizes.url_n: return 'url_n';
        case number < sizes.url_m: return 'url_m';
        case number < sizes.url_z: return 'url_z';
        case number < sizes.url_c: return 'url_c';
        default:           return 'url_l';
    }
}

Или вместо switch, чтобы избежать повторения его case:

var names = ['url_t', 'url_s', 'url_n', 'url_m', 'url_z', 'url_c', 'url_l'];

function getSize(number) {
    for (var i in names) {
        var name = names[i];
        if (number < sizes[name]) {
            return name;
        }
    }
    return names[names.length - 1];
}

И еще одно, помните, что , прямо перед закрытием } неверно JavaScript и может не работать во всех браузерах и средах:

// incorrect:
var sizes = { 1024 : 'url_l', }

// correct:
var sizes = { 1024 : 'url_l' }
ответил janos 22 J000000Tuesday14 2014, 21:44:23
0

Я не буду использовать for in .

Это петли, которые определяют свойства объекта, а также свойства его прототипа.

Если это ваш единственный выбор, вы должны использовать hasOwnProperty для каждого размера, который вы проверяете, чтобы избежать возможных ошибок.

Я бы использовал что-то вроде:

var sizes = {
 values: [100,240,320,500,640,800,1024],
 names: ['url_t', 'url_s', 'url_n', 'url_m', 'url_z', 'url_c', 'url_l']
},

, а затем обычный цикл.

ответил david ruiz 22 J000000Tuesday14 2014, 19:32:26

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132