For...In with custom object in javascript - javascript

function doIt()
{
var person={firstname:"John", lastname:"Smith", age:"25"};
var x;
var txt="";
for (x in person)
{
txt=txt+person[x] +"<br>";
}
document.getElementById("showtext").innerHTML=txt;
}
My question is: Why when I replace
txt=txt+person[x]+"<br>";
with:
txt=txt+person.x+"<br>";
the value of person.x is returned as undefined?
In the first iteration of the loop, x should be 'firstname'. So person.x should be equal to person.firstname, and thus return the value John. I would love to understand why it returns 'undefined' instead.

In the first case you're using 'bracket notation', where the value of the variable x is used to determine the property name.
In the second case you're using 'dot notation', where the property looked for is literally called x.

The Answer is:
Since x ist not the property name and the object doesnt have a property with the name/key x.
person.x
is undefined.
This would be equivalent to
person["x"] (the subtle difference lies in the double quotes)
what is also undefined.
For it to work with the dot-notation, you would have to write :
eval("person." + x); // but this is evil
// Tested on win7 with chrome 45+
so expression eval("person." + x) would expand in the first run to eval("person.firstname" ) which returns "John"
...
What I don't recommend, because eval can introduce may security issues.
Update 1
Disclaimer:
With this answer i only answered the initial question, and tried to explain the problem. With "// but this is evil " i am suggesting not to use this approche.

When you write person[x], it means "look up the value of x, and then find that element in person". When you write person.x it means "look up the value of x inside of person".
person doesn't have an x element, so you're getting undefined. You really do just want person[x].

x will be a string. eg "person" so you have to use [] brackets

You can't use dot notation with a variable key. It will look up the property "x" which is undefined. person[x] is the right way.

Javascript will allow you to access an object's property using a variable if you use the square brackets syntax. Thus, person[x] will do what you are trying to do as long as x contains a string representing the property name. The syntax construction person.x is equivalent to person["x"].

Related

What does [].$ mean in JavaScript?

There is a function in JavaScript which calculates the sum of some digits, however I don't understand what this part ([].$) means:
const sum = d => d != [].$ ? `${d = [...`${d}`].join` + `} = ${eval(d)}` : ``
[].$
[].$ - what is it?
[].$ - what is it?
It's an empty array literal ([]) followed by a property accessor expression (.$) looking up the property called $.
Since arrays don't normally have a property with that name, presumably it's been set there (or potentially set there, given the check) by some previous code. If no code sets it, then it's a short way to write undefined (since [].$ is undefined when $ isn't a property of arrays).
For this particular code, it doesn't have any significant meaning. It's there just to represent the value undefined with the least amount of characters. It could equally be []._ or just undefined.
For how it's interpreted. #T.J.Crowder answer summarised it pretty well

Why does a string literal beside an array like this not throw a syntax error in javascript?

During my coding I made a mistake by calling a function like this
someFunction( 'abc' [someValue] )
I had forgotten the colon inside the function call.
After I found the error I played around.
An assignment like this does not throw an error as well.
let a = 'abc'[someValue];
I would expect a syntax error here. Is there an explanation for this?
A string in Javascript can behave as an object and, as such has properties such as .length and methods such as .slice. So, for any property access on an object in Javascript, one can use either the dot notation as in:
str.length
or the [] syntax as in:
str["length"]
or using a variable:
let len = "length";
str[len]
So, what you have with:
'abc' [someValue]
Is just that syntax. A string followed by a property access. That is legal Javascript. It attempts to get the property from that object with the name of whatever string is in the someValue variable.
Here's are a couple working examples:
// simple property access
let prop = "length";
console.log("abc"[prop]);
// method call
console.log("one fine day"["slice"](4, 8));
One would not generally code this way with a string, but it's perfectly legal as it's just part of how one can access properties on an object in Javascript.
Because that's not a syntax error. The engine thought you were trying to get a letter from that string, so if someValue was a number it will work perfectly fine
let a = "abc"[0]
console.log(a, "abc"[1]) //a, b

Javascript: Why doesn't (p+1)++ work?

Regarding
p = 0;
(p+1)++;
> ReferenceError: Invalid left-hand side expression in postfix operation
and
p = 0;
++(p+4);
> ReferenceError: Invalid left-hand side expression in prefix operation
I just got a bit of a surprise, as I expected postfix/prefix operators to be ok with working on the resolution of the expression (brackets have the highest operator precedence).
Could someone give me with a line or three to explain what is happening here?
Thanks
EDIT: Thanks for the quick responses, first answer marked as the answer. I feel I should also point people to the indepth answer from #thefourtheye below
++ increments the value of a variable, so it is larger than before. Eg:
var x = 3;
x++;
alert(x); // will show 4
For there to be any point for this, the expression to the left of ++ must be accessible and mutable, otherwise the increment would be possible. Eg:
3++
doesn't make any sense, as 3 is a constant and can't be incremented. We don't want this to be possible:
3++;
alert(3); // outputs 4???
This is why your expression doesn't work. Ie:
var p = 2;
(p + 1)++;
has the same problem as above. (p + 1) will evaluate to 3, and ++ can't change the value of the constant 3.
You are trying to increment (), the increment/decrement operator can be apply on variable, try the sample code
(p++) + 1
OR
(++p) + 1
Remember that when you write p++, that actually gets translated to p = p + 1. The operators ++ and -- are convenience notation for incrementing/decrementing a variable for future use. But how is (p+1)++ or ++(p+4) supposed to be translated? Those sort of imply that 1 or 4 are being incremented/decremented for future use, which doesn't make sense.
When you have an expression like this
(expr)++;
These are the operations JavaScript will do internally
Resolve the actual object referenced by expr.
This step is important, because you can even do something like this
var a = {b: 1};
++a.b;
a.b++;
console.log(a.b);
# 3
Now, JavaScript has to resolve the actual object to be incremented. In this case, it will be b in a.
Get the value at the reference and convert that value to a Number.
This step is also very important, because you may even have values like this
var a = {b: '1'};
console.log(++a.b);
# 2
JavaScript will try its best to get a number value, instead of failing immediately.
Increment the number.
Store the new vale in expr. This is step where your expression is failing.
In your case expr is p + 1, when it is resolved the value would be just a numeral, whose value can never be changed. (You can never change the value of 1 to something else). So, after the incrementing part, when the new value has to be stored back, JavaScript doesn't find a valid reference to store it. That is why it throws this error.
ReferenceError: Invalid left-hand side expression in postfix operation
This error message is actually thrown from internal PutValue method. The very first step goes like this
If Type(V) is not Reference, throw a ReferenceError exception.
Reference: ECMA Script 5.1 Standard Specification for Prefix Increment Operator

Why aren't variable names converted to strings when using bracket notation in javascript?

Considering: var foo = {"5" : "ten", fighter : "Grohl"};
Why is this the result?
foo[5];
"ten"
foo[1 + 4];
"ten"
foo[fighter];
ReferenceError: fighter is not defined
Of course, if I start with this: var fighter = 'fighter'; then I get Grohl as expected.
My understanding is that when using bracket notation the expression inside the brackets are evaluated and converted to a string. So, in foo[5], toString() is called on 5 in order to evaluate it to a string, which must be used with bracket notation. So my question is:
Why isn't the same luxury afforded to fighter? I know that foo['fighter'] works, but to know isn't to necessarily understand. I'd like to understand what's going on here.
Edit: Why would I expect this to be the case indeed. If fighter was a variable that held another string... say 'Dave', then how would javascript know whether I meant the reference to 'Dave' or if I wanted to convert fighter to the actual string, 'fighter'. Obviously javascript can't read my mind. Thanks to #DaveNewton and #pointy for the illumination.
Because that's just not what the basic semantics of the language dictate. When you put fighter in brackets, you're saying "please evaluate this subexpression and use its value as the object property name". The subexpression fighter is a reference to a symbol, not a string constant.
If you want to use an identifier's name as a literal property name, use the . operator:
foo.fighter
In your other examples, the same thing is going on. The subexpressions 5 and 1+4 are evaluated in exactly the same way they'd be evaluated elsewhere. That is, consider:
var x = 1 + 4;
What do you expect that "x" will be? OK, so then:
var x = fighter;
Clearly to expect that "x" would be the string "fighter" would be seriously weird; how would you ever reference a variable if the language did that?

Safe way to get a string representation of any JavaScript value or object

I want to get a string represention of any object or value in JavaScript. I did a couple of experiments.
> var a = document.createTextNode('foo'); a
"foo"
> var a = document.createTextNode('foo'); a.toString()
"[object Text]"
> var a = 1; a.toString()
"1"
> (1).toString()
"1"
> 1.toString()
SyntaxError: Unexpected token ILLEGAL
I have the following questions:
Why does 1.toString() fail?
Will the following function return me a string representation of every possible JavaScript object, value or literal? Function: function str(a) {return a.toString()}
Is there any other alternative to the function str I have written in the previous point?
1). Why does 1.toString() fail?
The JavaScript parser only uses a 1 character lookahead and can't determine if that's 1.0 or 1.toString(). You can use 1..toString() to get around that.
2). Will the following function return me a string representation of every possible JavaScript object, value or literal? Function: function str(a) {return a.toString()}
Any literal will be converted to a temporary object in order to have its toString() called. If the object has its own toString() defined, it will be called. Otherwise, it will use Object.prototype.toString() (having gone up the prototype chain) for almost all cases (the other case is an object with a null prototype).
3). Is there any other alternative to the function str I have written in the previous point?
Yes. You can invoke the toString() implicitly by concatenating an empty string, e.g. 1 + "". You can also use the String constructor, e.g. String(value) (thanks T.J. Crowder). The advantages of these other ones is no exception will be thrown if you attempt to call toString() on null or undefined.
However, these tricks will convert null and undefined to their string equivalents (almost never what you want). One dirty trick is to put the value in a literal array, e.g. [value] and then call toString() on it. This will actually invoke join(","), but seeing as it only has one member, the comma will never become part of the string.
The real power of doing this is that null and undefined will just become an empty string. If that's OK for your program, then it can be useful. Keep in mind to comment this solution as it's not immediately obvious what this code is doing. Alternatively, check value == null which will detect null and undefined and handle it appropriately.
However, if you're wanting a string in order to classify a value, you can get the type's [[Class]] like so...
var getInternalClass = function(value) {
return Object.prototype.toString.call(value).slice(8, -1);
};
This will invoke the Object's toString() and set the ThisBinding to the value provided as the argument. This is the only way to expose an object's internal [[Class]]. The advantage of this (over typeof, for example) is that primitives and objects will always return the same value (with the primitives being converted to temporary objects, boxed by the call() context in non-strict mode).
for 1.toString(), you need to do:
1 .toString() //add space before dot (.) to avoid taking it as decimal
shortest way (alternative to function str ) to convert to string is:
var str = str + '';
Your str(a) function is correct but it will call the default implementation of toString() inherited from Object. So yes, your function will give you string representation of every JS object but not in way you want it. You need to override it.
var o = new Object();
o.toString(); // returns [object Object]
See here for reference and overriding: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString

Categories