Есть ли Javascript-эквивалент Ruby's andand?

В попытке сделать мой Javascript ненавязчивым, я использую onLoads, чтобы добавить функциональность <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(...);
Другие вопросы по тегам