Инъекции прототипа, Google Maps API - PullRequest
1 голос
/ 30 октября 2011

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

<input type='text' id='myInput'>
<script src="http://maps.google.com/maps/api/js?libraries=places&amp;sensor=false&amp;language=en-EN"></script>
<script>
function catcher(key) { console.log(key); }

function MyProto() {}
MyProto.prototype = new google.maps.MVCObject();
MyProto.prototype.changed = catcher;

var gAuto = new google.maps.places.Autocomplete(
    document.getElementById('myInput'), ['geocode']);

// one of two should be commented

//gAuto.__proto__.__proto__.changed = catcher; // every key, including 'predictions'

gAuto.__proto__.__proto__ = MyProto.prototype; // only 'types', '0', and 'place' when selected
</script>

JSFiddle link: http://jsfiddle.net/agentcooper/hRyTF/ (проверьте консоль)

Проверьте последние две строки. При настройке функции «поменять» непосредственно в прототипе MVCObject (первый, с комментариями) все отлично работает, и я могу уловить ключевые «предсказания» в функции «ловец». Проблема в том, что catcher должен быть другим, если, например, мне нужно иметь два экземпляра автозаполнения на моей странице. Поэтому, когда я пытаюсь внедрить пользовательский объект в цепочку прототипов autocomplete (последняя строка), все терпит неудачу. Есть ли способ решить эту проблему?

РЕДАКТИРОВАТЬ: рабочая версия , спасибо Саджиду: -)

ОБНОВЛЕНИЕ: Завершил код , возможно, это будет кому-нибудь полезно

1 Ответ

1 голос
/ 30 октября 2011

Во второй строке вы заменяете весь прототип объекта MVC экземпляром объекта MVC, и в зависимости от того, как объект инициализируется, это, скорее всего, не будет работать вообще. Первый like заменяет одну функцию, хотя в процессе он полностью нарушает эту функцию, так как вы не вызываете ее версию суперкласса, то есть вы не расширяете ее, вы действительно забиваете. Чтобы не забить, нужно сделать:

(function() {
    var oldChanged = gAuto.__proto__.__proto__.changed;

    function catcher(key) {
        // call old version, and make sure to maintain this reference correctly
        oldChanged.call(this, key);
        // do your stuff here
    }

    gAuto.__proto__.__proto__.changed = catcher;
})();

Одно простое решение состоит в том, что у каждого объекта есть идея this, упомянутая выше. Таким образом, changed имеет ссылку на this, которая будет ссылаться на объект, используемый в качестве цели вызывающей стороны (за исключением определенных ситуаций, которые здесь немного выходят за рамки). Но в основном:

var x = new MVCObject();
x.changed('hi') // this === x

Так что если вашим двум версиям нужно делать разные вещи, вы можете проверить, из какого this вызван измененный метод, и соответствующим образом отреагировать.

...