Есть ли Javascript-эквивалент Ruby's andand?
В попытке сделать мой Javascript ненавязчивым, я использую onLoad
s, чтобы добавить функциональность <input>
с и тому подобное. С Dojo это выглядит примерно так:
var coolInput = dojo.byId('cool_input');
if(coolInput) {
dojo.addOnLoad(function() {
coolInput.onkeyup = function() { ... };
});
}
Или примерно эквивалентно:
dojo.addOnLoad(function() {
dojo.forEach(dojo.query('#cool_input'), function(elt) {
elt.onkeyup = function() { ... };
});
});
Кто-нибудь написал реализацию Ruby's andand, чтобы я мог сделать следующее?
dojo.addOnLoad(function() {
// the input's onkeyup is set iff the input exists
dojo.byId('cool_input').andand().onkeyup = function() { ... };
});
или же
dojo.byId('cool_input').andand(function(elt) {
// this function gets called with elt = the input iff it exists
dojo.addOnLoad(function() {
elt.onkeyup = function() { ... };
});
});
7 ответов
Точный синтаксис, который вы хотите, невозможен в JavaScript. Способ выполнения JavaScript должен был бы измениться довольно фундаментально. Например:
var name = getUserById(id).andand().name;
// ^
// |-------------------------------
// if getUserById returns null, execution MUST stop here |
// otherwise, you'll get a "null is not an object" exception
Тем не менее, JavaScript не работает таким образом. Это просто не так.
Следующая строка выполняет почти то, что вы хотите.
var name = (var user = getUserById(id)) ? user.name : null;
Но удобочитаемость не увеличится до больших примеров. Например:
// this is what you want to see
var initial = getUserById(id).andand().name.andand()[0];
// this is the best that JavaScript can do
var initial = (var name = (var user = getUserById(id)) ? user.name : null) ? name[0] : null;
И есть побочный эффект этих ненужных переменных. Я использую эти переменные, чтобы избежать двойного поиска. Переменные портят контекст, и если это очень важно, вы можете использовать анонимные функции:
var name = (function() {return (var user = getUserById(id)) ? user.name : null;})();
Теперь пользовательская переменная очищена правильно, и все счастливы. Но вау! как много печатать!:)
Я не знаю Додзё, но разве не стоит читать твой первый пример?
dojo.addOnLoad(function() {
var coolInput = dojo.byId('cool_input');
if(coolInput)
coolInput.onkeyup = function() { ... };
});
В противном случае вы можете попытаться получить доступ к элементу до того, как DOM будет построен.
Вернуться к вашему вопросу: в JavaScript я бы реализовал andand()
как
function andand(obj, func, args) {
return obj && func.apply(obj, args || []);
}
Ваш пример может быть записан как
dojo.addOnLoad(function() {
andand(dojo.byId('cool_input'), function() {
this.onkeyup = function() { ... };
});
});
который на самом деле не намного короче, чем использование явного if
Скажите - так зачем?
Вы хотите dojo.behavior.
dojo.behavior.add({
'#cool_input': {
onKeyUp: function(evt) { ... }
}
});
Как насчет чего-то вроде этого:
function andand(elt, f) {
if (elt)
return f(elt);
return null;
}
Звоните так:
andand(dojo.byId('cool_input'), function(elt) {
// this function gets called with elt = the input iff it exists
dojo.addOnLoad(function() {
elt.onkeyup = function() { ... };
});
});
Для списка:
Array.prototype.andand = function(property, fn) {
if (this.filter(property).length > 0) this.map(fn);
}
Я никогда не использовал dojo, но большинство фреймворков javascript (при работе с DOM) возвращают вызывающий элемент, когда метод вызывается из объекта элемента (плохая формулировка, извините). Так что andand() будет неявным.
dojo.addOnLoad(function() {
dojo.byId('cool_input').onkeyup(function(evt) { /*event handler code*/
});
});
Насколько я знаю, нет встроенной функции JavaScript с такой же функциональностью. Я думаю, что лучшее решение - это запрос по классу вместо id и использование dojo.forEach (...), так как вам гарантирован ненулевой элемент в замыкании forEach.
Вы всегда можете использовать JavaScript-эквивалент:
dojo.byId('cool_input') && dojo.byId('cool_input').whateverYouWantToDo(...);