Бит опоздал на вечеринку, но я изучал этот вопрос сегодня и заметил, что многие ответы не полностью касаются того, как Javascript обрабатывает области, что по существу то, что это сводится к.
So как упоминалось многими другими, проблема в том, что внутренняя функция ссылается на одну и ту же переменную i
. Итак, почему бы нам просто не создать новую локальную переменную на каждой итерации и вместо этого иметь ссылку на внутреннюю функцию?
//overwrite console.log() so you can see the console output
console.log = function(msg) {document.body.innerHTML += '' + msg + '
';};
var funcs = {};
for (var i = 0; i < 3; i++) {
var ilocal = i; //create a new local variable
funcs[i] = function() {
console.log("My value: " + ilocal); //each should reference its own local variable
};
}
for (var j = 0; j < 3; j++) {
funcs[j]();
}
Точно так же раньше, когда каждая внутренняя функция выдавала последнее значение, присвоенное i
, теперь каждая внутренняя функция просто выводит последнее значение, назначенное на ilocal
. Но не должна ли каждая итерация иметь свою собственную ilocal
?
Оказывается, в этом и проблема. Каждая итерация разделяет одну и ту же область, поэтому каждая итерация после первого просто переписывается ilocal
. Из MDN :
Важно: JavaScript не имеет области блока. Переменные, введенные с блоком, привязаны к содержащейся функции или скрипту, а эффекты их настройки сохраняются за пределами самого блока. Другими словами, операторы блоков не вводят область. Хотя «автономные» блоки являются допустимым синтаксисом, вы не хотите использовать автономные блоки в JavaScript, потому что они не делают то, что, по вашему мнению, они делают, если вы думаете, что они делают что-то вроде таких блоков на C или Java.
Повторяется для акцента:
JavaScript не имеет области блока. Переменные, введенные с блоком, привязаны к содержащейся функции или скрипту
. Мы можем увидеть это, проверив
ilocal
, прежде чем объявить его на каждой итерации:
//overwrite console.log() so you can see the console output console.log = function(msg) {document.body.innerHTML += '
' + msg + '
';}; var funcs = {}; for (var i = 0; i < 3; i++) { console.log(ilocal); var ilocal = i; }Именно поэтому эта ошибка настолько сложна. Несмотря на то, что вы обновляете переменную, Javascript не будет вызывать ошибку, и JSLint даже не выдаст предупреждение. Именно поэтому лучший способ решить эту проблему - воспользоваться преимуществами закрытия, что по сути является идеей, что в Javascript внутренние функции имеют доступ к внешним переменным, потому что внутренние области «заключают» внешние области.
[/g13]
Это также означает, что внутренние функции «удерживают» внешние переменные и сохраняют их, даже если внешняя функция возвращается. Чтобы использовать это, мы создаем и вызываем функцию-оболочку только для создания новой области, объявляем
ilocal
в новой области и возвращаем внутреннюю функцию, которая используетilocal
(более подробное объяснение ниже):
//overwrite console.log() so you can see the console output console.log = function(msg) {document.body.innerHTML += '
' + msg + '
';}; var funcs = {}; for (var i = 0; i < 3; i++) { funcs[i] = (function() { //create a new scope using a wrapper function var ilocal = i; //capture i into a local var return function() { //return the inner function console.log("My value: " + ilocal); }; })(); //remember to run the wrapper function } for (var j = 0; j < 3; j++) { funcs[j](); }Создание внутренней функции внутри функции-обертки дает внутренней функции частную среду, доступ к которой может получить только «закрытие». Таким образом, каждый раз, когда мы вызываем функцию-оболочку, мы создаем новую внутреннюю функцию с ее собственной отдельной средой, гарантируя, что переменные
ilocal
не сталкиваются и не перезаписывают друг друга. Несколько незначительных оптимизаций дают окончательный ответ, который дали многие другие пользователи SO:
//overwrite console.log() so you can see the console output console.log = function(msg) {document.body.innerHTML += '
' + msg + '
';}; var funcs = {}; for (var i = 0; i < 3; i++) { funcs[i] = wrapper(i); } for (var j = 0; j < 3; j++) { funcs[j](); } //creates a separate environment for the inner function function wrapper(ilocal) { return function() { //return the inner function console.log("My value: " + ilocal); }; }Обновить
С ES6 теперь mainstream, теперь мы можем использовать новое ключевое слово
let
для создания переменных с блочным диапазоном:
//overwrite console.log() so you can see the console output console.log = function(msg) {document.body.innerHTML += '
' + msg + '
';}; var funcs = {}; for (let i = 0; i < 3; i++) { // use "let" to declare "i" funcs[i] = function() { console.log("My value: " + i); //each should reference its own local variable }; } for (var j = 0; j < 3; j++) { // we can use "var" here without issue funcs[j](); }Посмотрите, как легко это сейчас! Для получения дополнительной информации см. этот ответ , на котором основана моя информация.
из группы google, удаление каталога невозможно. Вы должны хранить список файлов где-нибудь (в базе данных Firebase) и удалять их по одному.
https://groups.google.com/forum/#!topic/firebase-talk / aG7GSR7kVtw
Я также отправил запрос функции, но поскольку их трекер ошибок не является общедоступным, нет ссылки, которую я мог бы предоставить.
Из контекста безопасной облачной функции google - вы можете удалить весь каталог, используя пакет npm Google Cloud Storage (также известный как Google Cloud Storage API):
const gcs = require('@google-cloud/storage')();
const functions = require('firebase-functions');
...
const bucket = gcs.bucket(functions.config().firebase.storageBucket);
return bucket.deleteFiles({
prefix: `users/${userId}/`
}, function(err) {
if (err) {
console.log(err);
} else {
console.log(`All the Firebase Storage files in users/${userId}/ have been deleted`);
}
});
доступно больше документации в документах GCS API
Как указано выше, удаление каталога недопустимо. Я использую пример запроса списка файлов в базе данных Firebase и их удаления один за другим. Это мой запрос и вызов.
let messagePhotoQuery = messagesRef.child(group.key).child("messages").queryOrdered(byChild: "photoURL")
deleteMessagePhotos(from: messagePhotoQuery)
Это моя функция, проходящая через получение URL-адреса, а затем удаление файла по этой ссылке на хранилище.
func deleteMessagePhotos(from photoQuery: FIRDatabaseQuery) {
photoQuery.observeSingleEvent(of: .value, with: { (messagesSnapshot) in
guard messagesSnapshot.exists() else { return }
print(messagesSnapshot)
for message in messagesSnapshot.children {
let messageSnapshot = message as! FIRDataSnapshot
let messageData = messageSnapshot.value as! [String: AnyObject]
if let photoURL = messageData["photoURL"] as? String {
let photoStorageRef = FIRStorage.storage().reference(forURL: photoURL)
photoStorageRef.delete(completion: { (error) in
if let error = error {
print(error)
} else {
// success
print("deleted \(photoURL)")
}
})
}
}
})
}
В 26/5/2017 нет способа удалить каталог Но вы можете использовать мой алгоритм
blockquote>Использовать этот код.
this.sliders = this.db.list(`users/${this.USER_UID}/website/sliders`) as FirebaseListObservable<Slider[]> /** * Delete image from firebase storage is take a string path of the image * @param _image_path */ deleteImage(_image_path: string) { // first delete the image const storageRef = firebase.storage().ref(); const imageRef = storageRef.child(_image_path); imageRef.delete().then(function() { console.log('file deleted'); // File deleted successfully }).catch(function(error) { // Uh-oh, an error occurred! console.log(error); }); } /** * Deletes multiple Sliders, it takes an array of ids * @param ids */ deleteMutipleSliders(ids: any) { ids.forEach(id => { this.getSliderDetails(id).subscribe(slider => { let id = slider.$key; // i think this is not nesesery const imgPath = slider.path; this.deleteImage(imgPath); }); return this.sliders.remove(id); }); }