Comments 17
Кто же так обработчики событий назначает? Делаем правильно.a.setAttribute('ommouseover', '__osb.someOtherFunction(\'asdf\', this);')
В этом случае в глобальную область видимости попадает ourSuperBookmarklet и __osbЧтобы не таскать 2 глобальных переменных, можно было сделать Ваш ourSuperBookmarklet синглтоном — все равно больше одного экземпляра Вам не нужно.
И вообще, при использовании замыканий можно было обойтись без каких-либо глобальных переменных. Правда, для JSONP оставить хотя бы одну придется.
+7
Согласен насчет событий, поторопился. Хотелось найти пример для использования нашей глобальной переменной. Что интересного придумаете? =)
0
А зачем Вам глобальная переменная? Если в них нет необходимости, то и использовать их не нужно. Единственная польза от них в том, что Вы описали — прием запросов от JSONP. Там без глобальной переменной-приемника ответов не обойтись. Другого применения глобальной переменной придумать не могу. Разве что, быть может, взаимодействие с флешем.
0
alt="Bookmarklet Title"
Вы ничего не перепутали? У тега <a> нет такого атрибута, зато есть title, и именно title берется в качестве названия букмарклета в Опере. Про остальные не знаю.
0
Используя нативные функции для работы с 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) уверен, что будет в кэше браузера и браузеру не придется закачать дополнительный объем данных.+5
Спасибо, есть над чем поразмыслить. Фреймворки я люблю, просто в небольших реактивных приложениях, какими букмарклеты являются, в большинстве случаев можно обойтись и без них.
0
Только g нужно задавать как
Ну и так, к слову: в HTML5 есть нативное свойство document.head, а доступ к body издавна осуществляется как document.body.
var g = function(tag){return document.getElementsByTagName(tag)};
Ну и так, к слову: в HTML5 есть нативное свойство document.head, а доступ к body издавна осуществляется как document.body.
0
не обязательно так задавать, т.к. приведенная выше запись, это присвоение функции переменной — более чем валидный прием.
Проблема только возникнет на страницах без head, тогда вызов g('head')[0] приведет к ошибке индекса массива.
Проблема только возникнет на страницах без head, тогда вызов g('head')[0] приведет к ошибке индекса массива.
0
Я обычно проверяю, если head нету — создаю его и возвращаю соответственно.
0
> не обязательно так задавать
На самом деле, обязательно.
В последующих апгрейдах DOM это дело ещё больше запутали…
На самом деле, обязательно.
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 это работает и возвращает корректный результат
Я тоже поторапился и написал кривой код выше.+1
про такое поведение конкретно getElementsByTagName я не подумал.
0
Почти, но не совсем.
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. Пример:
В ES5 можно будет сделать так (Впрочем, и сейчас можно, если реализовать функцию bind руками. см. реализацию в prototype.js):
Аналогично для getElementById, getElementsByTagName, querySelector, etc.
Ссылочка по теме.
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.
Ссылочка по теме.
+1
> typeof g вернет function
Мне сейчас самому не понятно как у меня в первом примере оказался undefined, вроде бы тестил в консоли, показалось странно, но оставил. Уж подумал, что открыл что-то новое… Мог бы стер половину глупго коммента :)
Верно так:
Мне сейчас самому не понятно как у меня в первом примере оказался 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 в языках программирования тесно связано с объектно-ориентированным программированием, а именно, указывает на текущий порождаемый конструктором объект.
0
Sign up to leave a comment.
Tips & tricks в разработке букмарклетов