2015-08-10 2 views
2

Я пытался обернуть вокруг головы и обратных вызовов из любопытства я проходил через исходный код для ванильных JS в todomvc и нашел эту функцию:Являются ли обратные вызовы в JavaScript просто пустыми функциями?

Store.prototype.findAll = function (callback) { 
    callback = callback || function() {}; 
    callback.call(this, JSON.parse(localStorage[this._dbName]).todos); 

}; 

Что делает следующее заявление означает?

callback = callback || function() {}; 

Означает ли это, что обратные вызовы - это просто пустые функции?

Кроме того, в чем разница между callback.call(this) и callback(anything)?

Я попытался модифицировать эту строку

callback.call(this, JSON.parse(localStorage[this._dbName]).todos); 

в

callback(JSON.parse(localStorage[this._dbName]).todos); 

Но результат был тот же. Зачем делать callback.call вместо просто callback?

ответ

2

Являются ли обратные вызовы в JavaScript просто пустыми функциями?

Обратные вызовы - это не просто пустые функции. Это функции, которые можно вызвать (часто с некоторыми аргументами) через некоторое время. Иногда они являются необязательными, и функция хоста позволит вам пройти обратный вызов или не передать обратный вызов. Если обратный вызов не передан, функция хоста может обнаружить, что он не передан в качестве аргумента и соответствующим образом адаптирует его поведение.

Что означает следующее утверждение?

callback = callback || function() {};

Означает ли это, что обратные вызовы - это просто пустые функции?

Это общий шаблон дизайна, чтобы гарантировать, что аргумент функции имеет значимое значение в случае, если он не был передан вызывающим поэтому функция может протекать внутри и выполнять, как правило, предполагая, что аргумент был принят абонентом , даже если вызывающий не прошел аргумент.

Код callback = callback || function() {}; эквивалентно следующему:

if (callback) { 
    callback = callback; 
} else { 
    callback = function() {}; 
} 

В JavaScript, оператор || присваивает результат будет первым из двух операндов, что является truthy (или false, если ни один не truthy), так что если callback имеет значение, то оно становится результатом операнда ||, и вы получаете callback = callback. В противном случае, если callback не является правдивым, он присваивает callback значение функции по умолчанию, которое позволяет остальной функции работать, предполагая, что callback имеет законное значение. Это заставляет все остальные функциональные коды проверять, имеет ли значение callback законное значение перед его использованием.

Кроме того, в чем разница между callback.call(this) и callback(anything)?

someFunction.call() позволяет значению this при выполнении функции. Таким образом, callback.call(this) делает обратный вызов равным this, когда он работает, что делает текущая функция. Если вы только что сделали callback(...) без .call(), то this возьмет на себя значение по умолчанию, которое будет либо объектом window, либо, если работает в строгом режиме, оно будет undefined.

Если конкретный обратный вызов не происходит, чтобы обратиться к значению this в его коде, то не будет никакой разницы в результатах с помощью .call() или не использовать его, но в этом случае, это дополнительная функция, предлагается к обратному вызову, что он может получить доступ к текущему экземпляру объекта Store, который используется при доступе к значению this внутри обратного вызова.


Установка значения this как это позволяет использовать метод объекта как прямой обратный вызов, так что это то же самое, что соглашение о вызове методы объекта есть.

Так что, если у вас есть Store объект вроде этого:

var s = new Store(); 

И был метод этого объекта под названием setName(), который использует this для обозначения своего собственного экземпляра объекта, вы можете сделать:

s.findAll(s.setName); 

Это будет работать только потому, что callback.call(this) установил значение экземпляра в значение this в обратном вызове.

0

Шаблон:

function foo(bar) { 
    bar = bar || someDefault; 
    ... 
} 

является общим (но устаревшим) способом установить параметр функции в значение по умолчанию, если оно было оставлено неопределенным вызывающей сторона.

В этом случае функция использует все функции, являющиеся правдивыми, и JS' unusual OR operator установить callback на пустую (nop) функцию, если она не была установлена. Вы можете видеть, что поведение в следующем примере:

var barDefault = 'No value provided!'; 
 

 
function foo(bar) { 
 
    bar = bar || barDefault; 
 
    console.log(bar); 
 
} 
 

 
foo(); // No value provided, since no arguments passed 
 
foo(3); // Argument passed, value provided 
 
foo(0); // Tricky case: falsy argument passed, so function assumes no value was provided

Как видно из примера, эта картина может вызвать проблемы, когда аргумент был принят, что является falsy, как OR оператор вернитесь к умолчанию. Чтобы решить эту проблему, используйте:

bar = typeof bar !== 'undefined' ? bar : barDefault; 

будет явно проверять неопределенные аргументы.

С ES6 и значения параметров по умолчанию, это может быть выражено более идиоматически как:

function foo(bar = someDefault) { 
    ... 
} 
+2

ES5 совсем не «устарел», поскольку почти все Javascript, предназначенные для запуска в браузере, все еще должны быть совместимы с ES5. Выберите другую фразу для использования. Кроме того, вы подробно рассказываете о местах, которые этот шаблон проектирования может вызвать проблемы, но это не имеет отношения к случаю использования OP, который передает функцию, которая не может быть законно ложной. – jfriend00

+0

@ jfriend00 Даже без ES6 этот шаблон падает, когда вы работаете с чем-либо, кроме объектов. Поскольку существуют лучшие шаблоны ES5, и ES6 предоставил правильное решение (которое теперь можно использовать с помощью транспилеров), это, безусловно, устарело. – ssube

+0

Шаблон работает отлично для функции (в чем заключается этот вопрос) или для любого аргумента, который не имеет законного значения ложности. Нет ничего «устаревшего» об использовании его в коде OP. – jfriend00

2

Нет, обратные вызовы не являются «просто пустой». Здесь функция получает обратный вызов в качестве аргумента и просто гарантирует, что это a. Если обратный вызов не был принят, он будет установлен на пустую функцию, но, по крайней мере, это функция a, которую можно вызвать. Установка аргументов в значение по умолчанию (здесь: пустая функция) упрощает следующий код, который в противном случае нуждался бы в связке условий if..else, чтобы сделать что-то другое, если обратный вызов не был функцией.

Для другой части вопроса см. How does the "this" keyword work?.

Смежные вопросы