简体   繁体   中英

Add Values to JavaScript object in Array with Anonymous Function

I'm using Filepicker.io to store images. I'm trying to get the image's metadata using their filepicker.stat() function. However, while it allows me to work with the metadata internally like so:

filepicker.stat(InkBlobs[i], { width: true, height: true }, function(metadata){ console.log(JSON.stringify(metadata)) });

I can't get the metadata out of that anonymous function. What I'd like to do is something like this:

for(i = 0; i < InkBlobs.length; i++)
{
    filepicker.stat(InkBlobs[i], { width: true, height: true }, function(metadata){ InkBlobs[i].add(JSON.stringify(metadata)); });
}

This obviously doesn't work (the InkBlobs[i].add( ... ) ) part, so how can I capture that metadata and include it with the other data located in the array? The array contents can each be JSON.stringify() 'd.

First, I assume that the callback receives metadata as an argument; that's missing from the code in the question, but I will assume that below.

You can do basically what you wrote, you just have to manage i slightly differently and have a place to store it. As this is JavaScript, you can just add your own property to the InkBlob instances, but that's typically a bit dangerous (in case you conflict with something non-public, or they add something similar to the objects in the next release, etc.).

First let's deal with i :

for(i = 0; i < InkBlobs.length; i++)
{
    filepicker.stat(InkBlobs[i], { width: true, height: true }, makeCallback(i));
}
function makeCallback(index) {
    return function(metadata){
        InkBlobs[index].add(JSON.stringify(metadata));
        // This bit ^^ is still theoretical
    };
}

Now, instead of closing over i , our callback closes over index , which is the argument we passed to makeCallback when we called it in the loop. Where i changes before the callback occurs, index does not.

You can also use ES5's bind if the this that the callback sees doesn't have to be controlled by stat :

for(i = 0; i < InkBlobs.length; i++)
{
    filepicker.stat(InkBlobs[i], { width: true, height: true }, function(index, metadata){
        InkBlobs[index].add(JSON.stringify(metadata));
        // This bit ^^ is still theoretical
    }.bind(null, i));
}

Note that the argument i we pass bind shows up in front of any supplied by stat (the first argument to bind , null in my example, is what sets this during the callback).

I'll use bind from here on out because it's more concise.

Now we have to store the metadata with the inkblobs. Here's one way:

var data = [];
var count = 0;
for(i = 0; i < InkBlobs.length; i++)
{
    filepicker.stat(InkBlobs[i], { width: true, height: true }, function(index, metadata){
        data[index] = {
            blob:     InkBlobs[index],
            metadata: metadata // No reason to stringify it that I know of, but you could
        };
        ++count;
        if (count === InkBlobs.length) {
            useTheNewArray();
        }
    }.bind(null, i));
}

Note that we wait to call useTheNewArray until we've seen the callback for all blobs. Also note that we don't just push to the new array, because they could arrive out of order (in theory). Of course, if the order doesn't matter, push away and you don't need the count variable anymore.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM