Simple JavaScript object comparison - javascript

I am trying to pass a simple string to an event listener in order to identify an appropriate array object to modify. I understand by looking at the log (shown in comments) that what I am passing is an object and it can't be compared directly to another object's property.
Should I pass an object that has the string as a property (like the array object does), or is there a more appropriate way to reference the object as a string or call its name somehow (like the log does in the first comment)?
// I just want to pass a string as an argument. Here is a static example.
var timestampID = '1307740835264';
Ti.App.fireEvent('confirmation',timestampID);
Notice how the first log output interprets the argument as a string, but the if comparison recognizes it as an object.
Ti.App.addEventListener('confirmation',function(timestampID) { // produces "[DEBUG] fire app event: confirmation with 1307740835264"
Ti.API.info(timestampID); // produces "[INFO] { type = confirmation; }"
for (i=0;i<myArray.length;i++) {
Ti.API.info(myArray[i].timestampID + ' | ' + timestampID); // produces "[INFO] 1307740835264 | [object Object]"
if (myArray[i].timestampID == timestampID) { // will produce false
// will never happen
}
}
});
Thanks!

So to me it looks like the timestampID being passed in to the handler is an object, however from the second statement (and accompanying [INFO] comment), I have absolutely no idea what properties it has. Let's assume that it has a property called timestamp. Then your if statement should be
if (myArray[i].timestampID === timestampID.timestamp)
But that's about all I can glean from this code snippet I'm afraid.
UPDATE: OK, I see how you're triggering the event. The Titanium API is bafflingly obtuse on this point (it looks like the help for fireEvent is wrong: two parameters called "name"?). There are no examples that I can see. However it does say that what you pass in as the data is (must be?) serialized as JSON.
Now that I know that, looking at the second statement's [INFO] line it makes more sense. It's a string that has the JSON data. Your data is missing since it was a string value. Try this to fire:
Ti.App.fireEvent('confirmation', { timestampID: '1307740835264' } );
and this in the event handler:
Ti.App.addEventListener('confirmation', function (data) {
for (i=0;i<myArray.length;i++) {
if (myArray[i].timestampID === data.timestampID) {
...code...
}
}
});

Either write a comparison function or find the scalar property (Number or String) that you want to compare.

Related

How to get "property missing" error messages with empty (and thus unsealed) objects

So, I have an API that takes an options object, something like this:
type Options = { pos: number };
function doTheThing(options: Options) {
}
Now, if I call this with any of the below, I get a nice error message:
doTheThing(); // requires another argument.
doTheThing({ something: 20 }); // missing property "pos"
Great. But if I pass an empty object, Flow will consider this "unsealed" and thus have no issue with it:
doTheThing({ }); // No error, would like it to say "pos" missing instead.
So, I tried making it exact:
type Options = {| pos: number |};
Now, I get an error, but it's not very nice:
doTheThing({ }); // Cannot call `doTheThing` with object literal bound to `options` because inexact object literal [1] is incompatible with exact `Options` [2].
But I just want it to say "pos" is missing. The above is more complicated and just forces you to have to read the definition of Options in order to know what it takes. I want it to offer the actual missing property to you. Which it will do, as soon as I put any random thing in there:
doTheThing({ x: 10 }); // Cannot call `doTheThing` with object literal bound to `options` because property `pos` is missing in object literal [1] but exists in `Options`
Is there any way to get it to give me that error message on {}, instead of the less useful message? Ideally through some sort of extra annotation on the type and not some global flow configuration that like turns off unsealed objects or something.

weird Object Destructuring in Javascript { obj : { } }

I was looking at someone's code of a chrome extension where there is an API chrome.storage.local.get which basically takes two parameters: key and callback respectively.
suppose we have a object (named Highlights) stored in local storage. if I wanna access that object then I have to pass 'highlights' as first parameter (i.e. key) to the chrome.storage.local.get function.
code should look like :
chrome.storage.local.get('highlights', callback);
it works fine but the developer of the extension used a different approach, his code look like :
chrome.storage.local.get({highlights: {} }, callback);
Notice the key parameter { highlights : {} } surprisingly it gives the same results.
I just wanna know that what does { highlights: {} } means and why does it works.
some extra information :
highlights is an object of arrays.
snapshot of highlights object in console.log :
That's not destructuring. That's an object literal containing a property, highlights, set to an empty object.
According to the documentation (which was harder to find than I would have expected):
keys
string | string[] | object optional
A single key to get, list of keys to get, or a dictionary specifying default values (see description of the object). An empty list or object will return an empty result object. Pass in null to get the entire contents of storage.
(my emphasis)
So passing in that object is saying: "Give me the highlights value from storage, using {} as the default if there isn't any."

Explain generics using Javascript's Flowtype

I have never written in statically typed language before. I'm mostly developing in Javascript and lately I've been interested in learning more about FB's Flowtype.
I find the documentation nicely written and I understand most of it. However I don't quite get the concept of generics. I've tried googling some examples / explanations but with no luck.
Could someone please explain what generics are, what are they mostly used for and perhaps provide an example?
Let's say I want to write a class that just stores a single value. Obviously this is contrived; I'm keeping it simple. In reality this might be some collection, like an Array, that can store more than one value.
Let's say I need to wrap a number:
class Wrap {
value: number;
constructor(v: number) {
this.value = v;
}
}
Now I can create an instance that stores a number, and I can get that number out:
const w = new Wrap(5);
console.log(w.value);
So far so good. But wait, now I also want to wrap a string! If I naively just try to wrap a string, I get an error:
const w = new Wrap("foo");
Gives the error:
const w = new Wrap("foo");
^ string. This type is incompatible with the expected param type of
constructor(v: number) {
^ number
This doesn't work because I told Flow that Wrap just takes numbers. I could rename Wrap to WrapNumber, then copy it, call the copy WrapString, and change number to string inside the body. But that is tedious and now I have two copies of the same thing to maintain. If I keep copying every time I want to wrap a new type, this will quickly get out of hand.
But notice that Wrap doesn't actually operate on the value. It doesn't care whether it is number or string, or something else. It only exists to store it and give it back later. The only important invariant here is that the value you give it and the value you get back are the same type. It doesn't matter what specific type is used, just that those two values have the same one.
So, with that in mind we can add a type parameter:
class Wrap<T> {
value: T;
constructor(v: T) {
this.value = v;
}
}
T here is just a placeholder. It means "I don't care what type you put here, but it's important that everywhere T is used, it is the same type." If I pass you a Wrap<number> you can access the value property and know that it is a number. Similarly, if I pass you a Wrap<string> you know that the value for that instance is a string. With this new definition for Wrap, let's try again to wrap both a number and a string:
function needsNumber(x: number): void {}
function needsString(x: string): void {}
const wNum = new Wrap(5);
const wStr = new Wrap("foo");
needsNumber(wNum.value);
needsString(wStr.value);
Flow infers the type parameter and is able to understand that everything here will work at runtime. We also get an error, as expected, if we try to do this:
needsString(wNum.value);
Error:
20: needsString(wNum.value);
^ number. This type is incompatible with the expected param type of
11: function needsString(x: string): void {}
^ string
(tryflow for the full example)
Generics among statically typed languages are a method of defining a single function or class that can be applied to any type dependency instead of writing a separate function/class for each possible data type. They ensure that the type of one value will always be the same at the type of another that are assigned to the same generic value.
For example, if you wanted to write a function that added two parameters together, that operation (depending on the language) could be entirely different. In JavaScript, since it is not a statically typed language to begin with, you can do this anyway and type check within the function, however Facebook's Flow allows for type consistency and validation in addition to single definitions.
function add<T>(v1: T, v2: T): T {
if (typeof v1 == 'string')
return `${v1} ${v2}`
else if (typeof v1 == 'object')
return { ...v1, ...v2 }
else
return v1 + v2
}
In this example we define a function with a generic type T and say that all parameters will be of the same type T and the function will always return the same type T. Inside of the function since we know that the parameters will always be of the same type, we can test the type of one of them using standard JavaScript and return what we perceive and "addition" for that type to be.
When in use later in our code, this function can then be called as:
add(2, 3) // 5
add('two', 'three') // 'two three'
add({ two: 2 }, { three: 3 }) // { two: 2, three: 3 }
But will throw typing errors if we attempt:
add(2, 'three')
add({ two: 2 }, 3)
// etc.
Basically, it's just a placeholder for a type.
When using a generic type, we are saying that any Flow type can be used here instead.
By putting <T> before the function arguments, we're saying that this function can (but doesn't have to) use a generic type T anywhere within its arguments list, its body, and as its return type.
Let's look at their basic example:
function identity<T>(value: T): T {
return value;
}
This means that the parameter value within identity will have some type, which isn't known in advance. Whatever that type is, the return value of identity must match that type as well.
const x: string = identity("foo"); // x === "foo"
const y: string = identity(123); // Error
An easy way to think about generics is to imagine one of the primitive types instead of T and see how that would work, then understand that this primitive type can be substituted for any other.
In terms of identity: think of it as a function that accepts a [string] and returns a [string]. Then understand that [string] can be any other valid flow type as well.
This means identity is a function that accepts T and returns a T, where T is any flow type.
The docs also have this helpful analogy:
Generic types work a lot like variables or function parameters except that they are used for types.
Note: Another word for this concept is polymorphism.

Best practice for handling missing properties in a JavaScript object?

I have a client that makes rest web service call and from calling the service returned data is JSON object. It has following field names as name and age. I ran into a case where fields are empty in returned data. Received this {} instead of {"name":"john doe","age":"23"}. What would be the best way to handle exception like that in JavaScript?
It depends on the data you're expecting.
The classic way would be
if (typeof object.property === "undefined") {
...
}
which also implies that undefined is not an acceptable value (and it shouldn't). But if it's not good for you, there's always
if (!object.hasOwnProperty("property")) {
...
}
If you expect a non-empty string (or a non-zero number), you can shortcut to:
if (!object.property) {
...
}
But if you need to accept empty strings or zeroes, this is very common too:
if (object.property == null) {
...
}
This rejects values like undefined (which should be your case) and null (which may be another unacceptable value).
But, in the end, instead of an empty object I'd recommend to return null and do like this:
if (object != null) {
// do your stuff with name and age
...
}

What does JSON.stringify() does with functions in an object?

Assuming a Javascript object has a function:
function Foo() {
this.a = 32;
this.bar = function (){
alert("Hello World!");
}
}
How does JSON.stringify() deal with the bar function? Is it just ignored? Is this standard practice? What does JSON converts and doesn't convert into the Json string?
Rem: I don't know why people downvoted my question, it is obvious one should not stringify an object with a function. I was just trying to understand the default behavior.
JSON.stringify simply changes functions passed into null if passed into an array, and does not include the property in at all if in an object. It makes no attempt to replicate the function, not even in string form.
For example, see this:
JSON.stringify([function () {}]); // "[null]"
JSON.stringify({ x: function () {} }); // "{}"
If you attempt to stringify a function itself, it's not a valid JSON value, which means that JSON.stringify can't make a valid JSON string:
JSON.stringify(function () {}); // undefined
This is specified as part of the ECMAScript specification, though the actual wording of it is rather complex. However, a note is included that summarises this:
NOTE 5
Values that do not have a JSON representation (such as
undefined and functions) do not produce a String. Instead they produce the undefined value. In arrays these values are represented as
the String null. In objects an unrepresentable value causes the
property to be excluded from stringification.

Categories

Resources