Pull to refresh

Comments 17

a.setAttribute('ommouseover', '__osb.someOtherFunction(\'asdf\', this);')
Кто же так обработчики событий назначает? Делаем правильно.
В этом случае в глобальную область видимости попадает ourSuperBookmarklet и __osb
Чтобы не таскать 2 глобальных переменных, можно было сделать Ваш ourSuperBookmarklet синглтоном — все равно больше одного экземпляра Вам не нужно.
И вообще, при использовании замыканий можно было обойтись без каких-либо глобальных переменных. Правда, для JSONP оставить хотя бы одну придется.
Согласен насчет событий, поторопился. Хотелось найти пример для использования нашей глобальной переменной. Что интересного придумаете? =)
А зачем Вам глобальная переменная? Если в них нет необходимости, то и использовать их не нужно. Единственная польза от них в том, что Вы описали — прием запросов от JSONP. Там без глобальной переменной-приемника ответов не обойтись. Другого применения глобальной переменной придумать не могу. Разве что, быть может, взаимодействие с флешем.
alt="Bookmarklet Title"

Вы ничего не перепутали? У тега <a> нет такого атрибута, зато есть title, и именно title берется в качестве названия букмарклета в Опере. Про остальные не знаю.
Присмотритесь, там картинка внутри. alt именно у img'a
Ок, alt у картинки. Но это никакой не «Bookmarklet Title». Все равно должен быть title у тега <a>.
Проверил в Опере, действительно нужен title у ссылки. Все остальные браузеры используют alt у картинки. Поправил, спасибо.
Это ведь жутко не логично, брать альт у картинки. А если картинки нет, а если картинок три.
Используя нативные функции для работы с DOM я гарантирую, что скрипт будет работать так, как хочу я.
Иногда, то что вы ожидаете !== то что браузер на самом деле выполняет (взгляните хотя бы на эвенты). Фрэймворки многое дотачивают за вас. Не стоит их так не любить. Многие не используют фрэймворки из-за того, что они много занимают, мне, например, время важнее.

Вытаскивать свои объекты в глобал, конечно не хорошо, но в вашем случае ничего не поделать. Я бы посоветовал не весь объект вытаскивать глобал, а только то, что непосредственно вызывается извне (в вашем случае JSONP callback), остальное следует запереть в замыкании, а «концы» вытащить в эвенты.
(function (window) {
   var myBookmarklet = {
      init: function () {
         // Создаем кнопку
         var e = document.createElement('button');
         e.addEventListener('click', function () {myBookmarklet.onActionButtonClick.call(myBookmarklet)});
         this.actionElem = e;
         /* add button to DOM tree */
      },
      onActionButtonClick: function () {
          // какие-то дествия на клик
          this.requestData(someParams, function () {/* callback */});
          this.processData(someParams);
      },
      ...
      processCallback: function () {
         
      }
   };

   // вытаскиваем Callback наружу это единственное, что видно в глобале
   window.myBookmarkletCallback = function (data) {
      // proxy
      myBookmarklet.processCallback(data);
   } 

   myBookmarklet.init();
}(this));
В замыкание должны быть переданы все внешние объекты, в моём случае это window. И не должны быть экспортировны в глобалы, не использующиеся извне объекты. Все это это гарантирует более быструю работу скрипта и лучшую сжимаемость «умными» сжимателями (Closure compiler, YUI Compresor).

Ну и код вставлялки букмарклета я бы улучшил вот так(на всякий случай):
(function () {
    ...
    var g = document.getElementsByTagName;
    (g('head')[0] || g('body')[0] || g('*')[0]).appendChild(script);
}());
Сейчас огромное количество сайтов использует jQuery вы бы могли тоже использовть jQuery в букмарклетах. Если есть jQuery на сайте — хорошо, не загружаем. Если нет, то подгружаем с CDN (yandex, google, bing) уверен, что будет в кэше браузера и браузеру не придется закачать дополнительный объем данных.
Спасибо, есть над чем поразмыслить. Фреймворки я люблю, просто в небольших реактивных приложениях, какими букмарклеты являются, в большинстве случаев можно обойтись и без них.
Только g нужно задавать как
var g = function(tag){return document.getElementsByTagName(tag)};


Ну и так, к слову: в HTML5 есть нативное свойство document.head, а доступ к body издавна осуществляется как document.body.
не обязательно так задавать, т.к. приведенная выше запись, это присвоение функции переменной — более чем валидный прием.
Проблема только возникнет на страницах без head, тогда вызов g('head')[0] приведет к ошибке индекса массива.
Я обычно проверяю, если head нету — создаю его и возвращаю соответственно.
> не обязательно так задавать
На самом деле, обязательно.
var g = document.getElementsByTagName;
alert(typeof g); // undefined
getElementsByTagName это особый метод, которая возвращает живую коллекцию элементов, на него нельзя создать ссылку извне (getElementById аналогично).
В последующих апгрейдах DOM это дело ещё больше запутали…
var g = document.querySelectorAll; // CSS selectors engine
alert(typeof g); // function вроде бы все ок!
alert(typeof g('*')); // но на самом деле тут будет ошибка "Illegal operation on WrappedNative prototype object"
alert(g.call(document, '*') instanceof NodeList); // true это работает и возвращает корректный результат
Я тоже поторапился и написал кривой код выше.
про такое поведение конкретно getElementsByTagName я не подумал.
Почти, но не совсем.
typeof g вернет function и все с виду нормально, но это только с виду. Вся проблема в том, что будут проблемы с this внутри функции. По сути, this является скрытым аргументом функции и передается неявно при вызове. Грубо говоря, запись вида obj.method(arg1, arg2, ...) будет преобразована в obj_method.call(obj, arg1, arg2, ...), а просто fncName(arg1, arg2, ...) в fncName.call(window, arg1, arg2, ...)
Понятно конечно, зачем всяким getElementById, document.getElementsByTagName, etc нужен объект document и почему нельзя получить его извне, не требуя привязки к объекту.
Поведение это, кстати, никоим образом к DOM'у не относится, а идет из самого языка ECMAScript. Пример:

var obj = {
  fnc: function(){return this.document},
  document: 'Hello, world!'
};
var p = obj.fnc;
alert( [obj.fnc(), p()] )
При вызове функции p this внутри будет указывать на window и функция вернет window.document, а не obj.document, как в первом случае. Соответственно, все эти нативные функции просто проверяют, является ли this экземпляром нужного «класса» HTMLDocument. Если нет — выбрасывают исключение.
В ES5 можно будет сделать так (Впрочем, и сейчас можно, если реализовать функцию bind руками. см. реализацию в prototype.js):
var p = obj.bind(obj);

Аналогично для getElementById, getElementsByTagName, querySelector, etc.

Ссылочка по теме.
> typeof g вернет function
Мне сейчас самому не понятно как у меня в первом примере оказался undefined, вроде бы тестил в консоли, показалось странно, но оставил. Уж подумал, что открыл что-то новое… Мог бы стер половину глупго коммента :)
Верно так:
var g = document.getElementsByTagName;
alert(typeof g); // function
alert(g.call(document, '*') instanceof HTMLCollection); // true
C поведением this знаком. Отличное описание дано тут dmitrysoshnikov.com/ecmascript/ru-chapter-3-this/ На самом деле это давнольно распостраненная проблема (аналогично Date, RegExp) из-за:
Многие привыкли, что ключевое слово this в языках программирования тесно связано с объектно-ориентированным программированием, а именно, указывает на текущий порождаемый конструктором объект.
Sign up to leave a comment.

Articles