Как удалить повторяющуюся функцию в прослушивателе javascript?

Задача

Я хочу удалить код дублирования, вызванный анонимными вызовами функций.

Фон

Я делаю очень простой проект, в котором я использую API Карт Google, чтобы показать карту с двумя окнами поиска. Пользователь вводит в эти поля начальный и конечный адреса, а я показываю маркеры на карте.

Для этого у меня есть две анонимные функции для слушателей, которые абсолютно идентичны, за исключением одного момента: одна использует startSearchBox, а другая — endSearchBox.

Что я пробовал

В этом дублировании кода нет необходимости, поэтому я попытался передать поля поиска в качестве параметра анонимной функции, однако это не сработало.

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

Как я могу устранить дублирование в этом коде?

Код

function initSearchBoxes() {
    // Create the search box and link it to the UI element.
    let startInput = document.getElementById('start-input');
    let startSearchBox = new google.maps.places.SearchBox(startInput);

    let endInput = document.getElementById('end-input');
    let endSearchBox = new google.maps.places.SearchBox(endInput);

    // Bias the SearchBox results towards current map's viewport.
    map.addListener('bounds_changed', function() {
        startSearchBox.setBounds(map.getBounds());
        endSearchBox.setBounds(map.getBounds());
    });

    startSearchBox.addListener('places_changed', function() {

        deleteAllMarkers();

        let places = startSearchBox.getPlaces();
        if (places.length == 0) {
            return;
        }

        // For each place, get the icon, name and location.
        let bounds = new google.maps.LatLngBounds();
        places.forEach(function(place) {

            // // Create a marker for each place.
            let newMarker = createMarker(place.geometry.location, place.name, markerLabels.nextSymbol(), true);
            markerLib.trackMarker(newMarker);

            newMarker.setMap(map);

            if (place.geometry.viewport) {
                // Only geocodes have viewport.
                bounds.union(place.geometry.viewport);
            }
            else {
                bounds.extend(place.geometry.location);
            }
        });
        map.fitBounds(bounds);
    });

    endSearchBox.addListener('places_changed', function() {

        deleteAllMarkers();

        let places = endSearchBox.getPlaces();
        if (places.length == 0) {
            return;
        }

        // For each place, get the icon, name and location.
        let bounds = new google.maps.LatLngBounds();
        places.forEach(function(place) {

            // // Create a marker for each place.
            let newMarker = createMarker(place.geometry.location, place.name, markerLabels.nextSymbol(), true);
            markerLib.trackMarker(newMarker);

            newMarker.setMap(map);

            if (place.geometry.viewport) {
                // Only geocodes have viewport.
                bounds.union(place.geometry.viewport);
            }
            else {
                bounds.extend(place.geometry.location);
            }
        });
        map.fitBounds(bounds);
    });
}

person Flame_Phoenix    schedule 28.06.2016    source источник


Ответы (1)


Вы можете обернуть свою функцию обратного вызова в другую "фабричную" функцию. Фабрика примет параметр (ссылку на поле поиска), а затем вернет фактический обработчик:

function makeSearchHandler(searchBox) {
    return function() {

        deleteAllMarkers();

        let places = searchBox.getPlaces();
        if (places.length == 0) {
            return;
        }

        // For each place, get the icon, name and location.
        let bounds = new google.maps.LatLngBounds();
        places.forEach(function(place) {

            // // Create a marker for each place.
            let newMarker = createMarker(place.geometry.location, place.name, markerLabels.nextSymbol(), true);
            markerLib.trackMarker(newMarker);

            newMarker.setMap(map);

            if (place.geometry.viewport) {
                // Only geocodes have viewport.
                bounds.union(place.geometry.viewport);
            }
            else {
                bounds.extend(place.geometry.location);
            }
        });
        map.fitBounds(bounds);
    };
}

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

Затем вы можете использовать эту функцию для создания обратных вызовов:

startSearchBox.addListener('places_changed', makeSearchHandler(startSearchBox));
endSearchBox.addListener('places_changed', makeSearchHandler(endSearchBox));
person Pointy    schedule 28.06.2016
comment
Аккуратный! Я не подумал об этом, Спасибо! - person Flame_Phoenix; 28.06.2016
comment
@Flame_Phoenix это полезный подход во многих ситуациях. Удачи! - person Pointy; 28.06.2016