I have managed to create an object connecting to an API. So I have a function loadColors()
loadColors = function() {
var Colors = [];
for (var i =0; i < array.length; i++) {
Card.get({cardName: array[i].object_name}, function(data) {
Colors.push(data.data[0].color);
});
}
return {Colors};
};
var Colors = loadColor();
and inside there I was able to see the result with console.log(Colors) which is:
Object {Colors: Array[0]}
Colors: Array[4]
0: "green"
1: "red"
2: "yellow"
3: "blue"
length: 4
__proto__: Array[0]
__proto__: Object
When I try to access a value like console.log[Colors[0]]; I get undefined.
What am I doing wring?
Why are you wrapping Colors in {} in your return statements?
Just do return Colors; and you would be able to access the indexed array items directly from the return result.
Since you're currently returning an object containing the array, you would have to access it by Colors.Colors[0].
Update
I realize that besides wrapping your result in an object before returning it, you are also returning an array that is not populated with items at the return point, due to the asynchronous nature of Card.get.
This problem is actually rather well suited for a concept called Promises, but rather than introducing another new concept at this point, I will illustrate how you can solve this manually. (IE doensn't have native Promise support, there are frameworks that will solve this but you may not want an entire new framework just for this. jQuery has something called Deferreds, but they're subtly different from the Promise specs).
Instead of returning a result from the function, the callback from Card.get should call the function that moves your code forward. It should only do this once the array is filled, however, and not once for every callback.
Card.get({ your options }, function(data) {
Colors.push(data.data[0].color);
if(Colors.length == array.length) {
allColorsLoaded(Colors);
}
});
So if your logic is currently:
var Colors = loadColors();
alert(Colors.length);
It would need to be updated so that everything that relies on Colors to be populated is initiated by the callback:
var allColorsLoaded = function(Colors) {
alert(Colors.length);
};
loadColors();
It is isn't so clear from the question what is going on but from what I understood, when you try
console.log(Colors[0])
outside the function it returns undefined while inside the function it returns 'green'?
If so you should probably just change:
return {Colors};
to be:
return Colors;
Related
I'm trying to use console.log to get the value of the self.subcategories object after it is created in the subscribe function below. I always get c() in my console from the console.log(self.subcategories) below. I know that the data is there, as I can use it in a different piece of code. I just want to be able to see it in console.log so I can get more info and know what to do with it.
function QuestionFilter(data, categories, getSubcategoriesByCategoryUrl, getQuestionsBySubcategoryUrl) {
var self = this;
self.categories = ko.observableArray(categories);
self.subcategories = ko.observableArray([]);
self.selectedCategory = ko.observable();
self.selectedCategory.subscribe(function(category) {
function search(nameKey, myArray){
for (var i=0; i < myArray.length; i++) {
if (myArray[i].parentCategory_id === nameKey) {
self.subcategories.push(myArray[i]);
}
}
}
search(category, categories);
console.log(self.subcategories);
});
};
The Knockout.js library is included and so there are a couple of references to it. As I mentioned, everything works, I just want to be able to log the object to help me write more code. Any ideas?
Have a look at the documentation (emphasis mine):
Reading information from an observableArray
Behind the scenes, an observableArray is actually an observable whose value is an array (plus, observableArray adds some additional features described below). So, you can get the underlying JavaScript array by invoking the observableArray as a function with no parameters, just like any other observable. Then you can read information from that underlying array. For example,
alert('The length of the array is ' + myObservableArray().length);
alert('The first element is ' + myObservableArray()[0]);
I have a function that receives a list of JS objects as an argument. I need to store information about those objects in a private variable for future reference. I do not want to stuff a property into the objects themselves, I just want to keep it out of band in a dictionary. I need to be able to lookup metadata for an object in sub-linear time.
For this I need a hash function such that, for any two objects o1 and o2,
hash(o1) !== hash(o2) whenever o1 !== o2.
A perfect example of such a hash function would be the memory address of the object, but I don't think JS exposes that. Is there a way?
Each object reference is different. Why not push the object onto an array? Traversing the array looking for an object reference might still perform better than inspecting each object in a recursive manor to generate a hash key.
function Dictionary() {
var values = [];
function contains(x) {
var i = values.length;
while(i--) {
if (values[i] === x) {
return true;
}
}
return false;
}
function count() {
return values.length;
}
function get(i) {
return (i >= 0 && i < values.length) ? values[i] : null;
}
function set(o) {
if (contains(o)) {
throw new Error("Object already exists in the Dictionary");
}
else {
return values.push(o) - 1;
}
}
function forEach(callback, context) {
for (var i = 0, length = values.length; i < length; i++) {
if (callback.call(context, values[i], i, values) === false) {
break;
}
}
}
return {
get: get,
set: set,
contains: contains,
forEach: forEach,
count: count
};
}
And to use it:
var objects = Dictionary();
var key = objects.set({});
var o = objects.get(key);
objects.contains(key); // returns true
objects.forEach(function(obj, key, values) {
// do stuff
}, this);
objects.count(); // returns 1
objects.set(o); // throws an error
To store metadata about objects, you can use an WeakMap:
WeakMaps are key/value maps in which keys are objects.
Note that this API is still experimental and thus not widely supported yet (see support table). There is a polyfill implementation which makes use of defineProperty to set GUIDs (see details here).
Javascript does not provide direct access to memory (or to the file system for that matter).
You'd probably just want to create your properties/variables within the analysis (hash) function, and then return them to where the function was called from to be stored/persisted for later reference.
Thanks everyone who chipped in to reply. You all have convinced me that what I want to do is currently not possible in JavaScript.
There seem to be two basic compromises that someone with this use case can chose between:
Linear search using ===
=== appears to be the only built-in way to distinguish between two identically-valued objects that have different references. (If you had two objects, o1 and o2, and did a deep comparison and discovered that they were value-identical, you might still want to know if they're reference-identical. Besides === you could do something weird like add a property to o1 and see if showed up in o2).
Add a property to the object.
I didn't like this approach because there's no good reason why I should have to expose this information to the outside world. However, a colleague tipped me off to a feature that I didn't know about: Object.defineProperty. With this, I can alleviate my main concerns: first, that my id would show up, unwanted, during object enumeration, and second, that someone could inadvertently alter my id if there were to be a namespace collision.
So, in case anyone comes here wanting the same thing I wanted, I'm putting it up there for the record that I'm going to add a unique id using Object.defineProperty.
I am returning JSON from an API via a $.ajax request and end up with a lump of JSON:
var result = {
"status": 200,
"offset": 5,
"limit": 25,
"total": 7,
"url": "/v2/api/dataset/topten?",
"results": [
{
"datasets": [
"dataset",
"tt_all"
],
"id": "Hxb6VtpFRQ9gEr",
"title": "Venues",
"type": "topten",
"url": "/v2/dataset/topten/Hxb6VtpFRQ9gEr"
},
}
Or something similar. There are nested arrays containing more results in larger requests.
I would like to parse this information, put it into an object and have methods for available for that object to extract specific bits of information, from all levels - something like:
result.title => "Venues" or result.id => "Hxb6v...."
However, the output from the AJAX request can be assigned to a var by a user defined so I would like to make a function to stick this in an object with methods available before it exits the ajax success function and get assigned to result or whatever.
I don't particularly want to go down the:
Object.prototype.method = function(){ // extend Object here }
method as it makes people angry.
If I make another object to extend the prototype:
function Datalump(){};
Datalump.prototype.title = function(){
// get title or something here
};
I am struggling with what to pass to what and assigning things to the wrong thing.
How do I go about this method / object creation?
Any suggestions or pointers would be greatly appreciated.
UPDATE: Thank you all for the help - it's been very enlightening. I've marked Mike Brant's answer as correct as it seems the most appropriate to the question I asked. George Jempty's answer was also a very useful learning experience.
I'm actually going in a slightly different direction in the project (new requirements!), but parts of all the answers will probably make it into the 'alpha'.
Many thanks all.
If you have a javascript object (like you get after your JSON is parsed into object), you can just add whatever methods you want to it like this:
result.getTitle = function() {
// return title value of interest
return this.results.title;
}
result.getId = function() {
// return id value of interest
return this.results.id;
}
Here result is the the object that you have after JSON is parsed.
Create a module that wraps the JSON result. The module will return the original result, plus any convenience methods you might need in addition. Then use underscore.js and in particular _.result to interact with the wrapped result. This way you won't need to care whether you are accessing one of the original properties of the wrapped result or one of the convenience methods.
var wrappedResult = WrappedResult(result);
var status = _.result(wrappedResult, 'status');
var foobar = _.result(wrappedResult, 'foobar');
If the convenience of _.result is outweighed by the verbosity, you can just call wrappedResult.status or wrappedResult.foobar() directly
Implementation of WrappedResult:
var WrappedResult = function(result) {
return _.extend({}, result, {
foobar: function() {
console.log('foobar');
}
}
}
Something like the above anyway; you might want to extend _.clone(result) instead.
BTW underscore.js is by no means necessary, though in this case it does a nice job of describing exactly what you are doing (you "_.extend" the result with some methods in addition to the initial properties). Instead, wrap your result with an object, and then add methods directly, similar to the other answer:
var WrappedResult = function(result) {
result.foobar = function() {
console.log('foobar');
};
return result;
}
I have read this answer but still have a headache on making the code work.
I have a slightly different needs. Instead of alerting I have to bind each object.
My code is:
for (var i = 0; i < markers_length; i++) {
events_number = data.markers[i].events_number //data.markers is a multidimentional array
marker = L.marker([ data.markers[i].latitude , data.markers[i].longitude ]); //just create the new object
marker.on('mouseover', function(){
return function(){
this.bindPopup(" Found"+events_number+" event(s)").openPopup();
}
}(i) );
}
I am using leaflet if you ask. For a single object the bindPopup would work like:
marker.on('mouseover', this.bindPopup('hi').openPopup());
The trouble is that the above code gives the last object for all the. I assume that there is a problem with the this and the level of the functions. So how can I bind each marker with a separate text?
it should be:
marker.on('mouseover', function(en){
return function(){
this.bindPopup(" Found"+en+" event(s)").openPopup();
}
}(events_number) );
You have to pass the value that you want to be saved in the closure (events_number in this case), and the function has to take a parameter to receive that value and use it in the closure (en in my code).
Scenario: I'm searching for a specific object in a deep object. I'm using a recursive function that goes through the children and asks them if I'm searching for them or if I'm searching for their children or grandchildren and so on. When found, the found obj will be returned, else false. Basically this:
obj.find = function (match_id) {
if (this.id == match_id) return this;
for (var i = 0; i < this.length; i++) {
var result = this[i].find(match_id);
if (result !== false) return result;
};
return false;
}
i'm wondering, is there something simpler than this?:
var result = this[i].find(match_id);
if (result) return result;
It annoys me to store the result in a variable (on each level!), i just want to check if it's not false and return the result. I also considered the following, but dislike it even more for obvious reasons.
if (this[i].find(match_id)) return this[i].find(match_id);
Btw I'm also wondering, is this approach even "recursive"? it isn't really calling itself that much...
Thank you very much.
[edit]
There is another possibility by using another function check_find (which just returns only true if found) in the if statement. In some really complicated cases (e.g. where you don't just find the object, but also alter it) this might be the best approach. Or am I wrong? D:
Although the solution you have is probably "best" as far as search algorithms go, and I wouldn't necessarily suggest changing it (or I would change it to use a map instead of an algorithm), the question is interesting to me, especially relating to the functional properties of the JavaScript language, and I would like to provide some thoughts.
Method 1
The following should work without having to explicitly declare variables within a function, although they are used as function arguments instead. It's also quite succinct, although a little terse.
var map = Function.prototype.call.bind(Array.prototype.map);
obj.find = function find(match_id) {
return this.id == match_id ? this : map(this, function(u) {
return find.call(u, match_id);
}).filter(function(u) { return u; })[0];
};
How it works:
We test to see if this.id == match_id, if so, return this.
We use map (via Array.prototype.map) to convert this to an array of "found items", which are found using the recursive call to the find method. (Supposedly, one of these recursive calls will return our answer. The ones which don't result in an answer will return undefined.)
We filter the "found items" array so that any undefined results in the array are removed.
We return the first item in the array, and call it quits.
If there is no first item in the array, undefined will be returned.
Method 2
Another attempt to solve this problem could look like this:
var concat = Function.prototype.call.bind(Array.prototype.concat),
map = Function.prototype.call.bind(Array.prototype.map);
obj.find = function find(match_id) {
return (function buildObjArray(o) {
return concat([ o ], map(o, buildObjArray));
})(this).filter(function(u) { return u.id == match_id })[0];
};
How it works:
buildObjArray builds a single, big, 1-dimensional array containing obj and all of obj's children.
Then we filter based on the criteria that an object in the array must have an id of match_id.
We return the first match.
Both Method 1 and Method 2, while interesting, have the performance disadvantage that they will continue to search even after they've found a matching id. They don't realize they have what they need until the end of the search, and this is not very efficient.
Method 3
It is certainly possible to improve the efficiency, and now I think this one really gets close to what you were interested in.
var forEach = Function.prototype.call.bind(Array.prototype.forEach);
obj.find = function(match_id) {
try {
(function find(obj) {
if(obj.id == match_id) throw this;
forEach(obj, find);
})(obj);
} catch(found) {
return found;
}
};
How it works:
We wrap the whole find function in a try/catch block so that once an item is found, we can throw and stop execution.
We create an internal find function (IIFE) inside the try which we reference to make recursive calls.
If this.id == match_id, we throw this, stopping our search algorithm.
If it doesn't match, we recursively call find on each child.
If it did match, the throw is caught by our catch block, and the found object is returned.
Since this algorithm is able to stop execution once the object is found, it would be close in performance to yours, although it still has the overhead of the try/catch block (which on old browsers can be expensive) and forEach is slower than a typical for loop. Still these are very small performance losses.
Method 4
Finally, although this method does not fit the confines of your request, it is much, much better performance if possible in your application, and something to think about. We rely on a map of ids which maps to objects. It would look something like this:
// Declare a map object.
var map = { };
// ...
// Whenever you add a child to an object...
obj[0] = new MyObject();
// .. also store it in the map.
map[obj[0].id] = obj[0];
// ...
// Whenever you want to find the object with a specific id, refer to the map:
console.log(map[match_id]); // <- This is the "found" object.
This way, no find method is needed at all!
The performance gains in your application by using this method will be HUGE. Please seriously consider it, if at all possible.
However, be careful to remove the object from the map whenever you will no longer be referencing that object.
delete map[obj.id];
This is necessary to prevent memory leaks.
No there is no other clear way, storing the result in a variable isn't that much trouble, actually this is what variables are used for.
Yes, that approach is recursive:
you have the base case if (this.id==match_id) return this
you have the recursive step which call itself obj.find(match_id) { ... var result = this[i].find(match_id); }
I don't see any reason, why storing the variable would be bad. It's not a copy, but a reference, so it's efficient. Plus the temporary variable is the only way, that I can see right now (I may be wrong, though).
With that in mind, I don't think, that a method check_find would make very much sense (it's most probably basically the same implementation), so if you really need this check_find method, I'd implement it as
return this.find(match_id) !== false;
Whether the method is recursive is hard to say.
Basically, I'd say yes, as the implementations of 'find' are all the same for every object, so it's pretty much the same as
function find(obj, match_id) {
if (obj.id == match_id) return obj;
for (var i = 0; i < obj.length; ++i) {
var result = find(obj[i], match_id);
if (result !== false) return result;
}
}
which is definitely recursive (the function calls itself).
However, if you'd do
onesingleobjectinmydeepobject.find = function(x) { return this; }
I'm not quite sure, if you still would call this recursive.