Недавно я попытался использовать реализацию карты в javascript для создания набора элементов, а затем применить их к методу добавления объектов.
Во-первых, с использованием стандартной реализации болота.
var map = function (fn, a) { for (i = 0; i < a.length; i++) { a[i] = fn(a[i]); } }
Настроить.
var translateMenu = new Menu; var languages = [ ['Chinese' , 'zh-CN'] , ['German' , 'de'] , ['French' , 'fr'] , ['Portugese' , 'pt'] , ['Hindi' , 'hi'] ];
И моя функция … (не анонимная, так как она позже используется при добавлении translateMenu к mainMenu.)
var langItem = function (language, subMenu) { return new MenuItem(language[0], 'http://translate.google.com/translate?u=www.example.com&hl=en&ie=UTF-8&tl=en&sl=' + language[1] , "" , subMenu); } map ( langItem , languages );
Все это прекрасно работало, теперь у меня появился массив MenuItems.
Попытка вызова map( Menu.add , languages )
приведет к тому, что внутренние переменные Menu не определены, а вызов не будет выполнен.
Теперь я уверен, что это связано с объемом метода Menu.add()
, поэтому я подумал, что если бы я прошел и в объекте, это может сработать.
Я попытался создать новую функцию карты, которая будет принимать объекты и функции, но имела ту же неопределенную ошибку.
objMap (fn , obj , a) { for (i = 0; i < a.length; i++) { obj.fn(a); } } objMap ( add , translateMenu , languages ); // failed
Я работал над этим, расширив Menu с помощью addAll (), чтобы взять массив, который отлично работает …
Menu.prototype.addAll = function (items){ for (i = 0; i < items.length; i++) { this.add(items[i]); } } translateMenu.addAll( languages ); // yay! but I want a more elegant solution.
Во всяком случае, мой вопрос заключается в том , как я могу реализовать карту (или аналогичную общую функцию) для фактической поддержки методов объектов в качестве моих отображаемых функций? ,
Попытка позвонить по карте (Menu.add, языки)
Здесь ваша проблема почти наверняка связана с отсутствием связанных методов JavaScript.
Установка «this» для функции определяется только во время вызова, путем изучения способа получения метода. Если вы скажете одно:
obj.method(); obj['method']();
JavaScript заберет ссылку на «obj» и установит «this = obj» внутри вызова метода. Но если вы скажете:
obj2.method= obj.method; obj2.method();
Теперь «это» внутри функции будет obj2, а не obj!
Аналогично, если вы выберете метод с его объекта и обратитесь к нему как к первоклассному объекту:
var method= obj.method; method();
Не будет объекта для этого, чтобы его установить, поэтому JavaScript устанавливает его на глобальный объект (например, «окно» для веб-браузеров). Вероятно, это происходит в вашем случае: метод «Menu.add» теряет всю ссылку на его «Меню» владельца, поэтому, когда он получает обратный вызов, он, скорее всего, неосознанно пишет членам «окна», а не меню.
Это, конечно, очень необычно для языка OO и почти никогда не то, что вы хотите, но эй, вот как работает JavaScript. Причинение молчащих, трудно отлаживаемых ошибок является частью обоснования языка.
Чтобы обойти эту проблему, вы можете передать ссылку на объект в свою функцию карты, а затем использовать Function.call () / apply (), чтобы правильно установить эту ссылку:
function mapMethod(fn, obj, sequence) { for (var i= 0; i<sequence.length; i++) sequence[i]= fn.call(obj, sequence[i]); } mapMethod(Menu.add, Menu, languages)
Более общий способ – связать ссылки на функции вручную, используя закрытие:
function bindMethod(fn, obj) { return function() { fn.apply(obj, arguments) }; } map(bindMethod(Menu.add, Menu), languages)
Эта возможность будет встроена в будущую версию JavaScript:
map(Menu.add.bind(Menu), languages)
И это свойство можно добавить к текущим браузерам, написав в Function.prototype.bind – действительно, некоторые JS-фреймворки уже есть. Однако примечание:
ECMAScript 3.1 обещает, что вы также сможете передать дополнительные аргументы в bind () для выполнения приложения с частичной функцией, для чего требуется немного больше кода, чем bindMethod () выше;
IE любит утечку памяти, когда вы начинаете оставлять ссылки как связанные методы на объектах DOM, таких как обработчики событий.