What is the difference between a key and an identifier in JS? - javascript

Regarding objects, why do they have keys that are associated with their data. For instance: a variable with the identifier 'num' will hold a reference to that value in memory, but why do objects not use this principle? Instead they have keys that are, correct me if I am wrong, actual values themselves that are associated with a property of an object. I hope I am explaining this correctly. In short, why do objects not use identifers like standard variables and instead have keys associated with them that are their own values. I checked it and JS says they are of type 'string'. Standard variables have an identifier that is not a value but a reference to said value, why do objects have this additional layer of complexity?
Why do objects behave like this-
Key variable associated with variable
And not like this (like normal declaration with let, var, const)-
Identifier references variable
Note: I am new to JS

A key is a runtime value whereas an identifier is a syntactical element.
Objects in JS do not have a fixed shape, you can create, update and delete properties in them at will. And you can do so dynamically, without knowing the names of the properties when you write the program, using bracket notation: obj[prop] = val. And similarly you can loop over the keys of an object with for (const prop in obj). This is why keys are strings (or symbols) - you need to access them with/as string values.
The term "identifier" refers to specific syntax in the grammar of the language. It is written by the programmer and parsed by the compiler. Notice that in the expression obj.prop, both "obj" and "prop" are identifiers, so they don't even have to refer to variables. They are just the subset of strings you can write to name variables and properties with dot syntax. They are not values you can access from a javascript program, and don't really exist at runtime any longer.
You might have meant variables though. Variables are distinguished by identifiers, the same identifier in the same scope will refer to the same variable. This distinction happens by name, treating the variable names as strings in the compiler. You just never get in contact with those strings from JS code. When the code is executed, for each declared name a variable with a value will be created in an environment structure for that scope.
So there is some similarity:
An object consists of property keys associated with property values.
A scope environment consists of variable names associated with variable values.
And actually, this similarity is (or has been) exploited by usage of eval and with statements and the global object, that actually allow the dynamic creation and assignment of variables by name. For these, the interpreter has to keep the variable names (as strings) in memory. It's inefficient and despised though. When they (both object keys and variable names) are not dynamic, the interpreter will be able to optimise them a lot.

Related

How can javascript object method refer to variable that is not declared yet?

I'm reading this js tutorial, in Def. 5: Class section there's a code snippet:
// Generic prototype for all letters.
let letter = {
getNumber() {
return this.number;
}
};
I wonder how can getNumber method refer to number which is not declared?
number isn't a variable, it's a property. You don't have to declare properties (in fact, until the class fields proposal progresses [it's currently at Stage 3], you can't declare properties; there's no property declaration syntax, just a property initialization syntax). Variables are storage outside of an object.¹ A property is storage within an object.
If you're wondering how getNumber can use the property before it's created, it's because that's just how JavaScript is defined: Trying to get the value of a property that doesn't exist results in the value undefined, not an error.
¹ "...outside of an object." At least, as far as your code is concerned. In specification terms, variables are bindings (which are very similar to properties) within a lexical environment object, but that's a specification thing, not something you can directly use in code.
In your code, this.number is letter.number which is not defined. And, it means it is evaluted as undefined.
var obj = {};
obj.number; // undefined

Why do variables become keys on the window object?

I've noticed that variables become keys and their values become values of said keys when I am writing on the window object. For instance:
var variable = "value";
console.log(window.variable);//logs "value"
But if I create a new object of my own like:
var o = {
key: "value",
var key2 = "value2"
}; // result: "syntax error"
I have to use the colon to set key/value pairs. And even with constructor functions, although I don't get a syntax error, I don't seem to be able to do this inside the constructor function or during object instantiation or after:
function Blueprint(){
this.key = "value";
var key2 = "value2";
}
var o = new Blueprint;
console.log(o.key); //result: "value"
console.log(o.key2); //result: "undefined"
Now, I understand why, in the former case, I generated a syntax error and why in the latter case I was unable to attach key2 to the Blueprint constructor function but what I don't understand why on the global window object I am given free range to just add properties using variables and they instantly become keys on the window object. Other than on the windows object, variables seem to behave as though they are independent of objects and property creation.
I've also noticed similar behavior on the global object when experimenting with node. Are global objects the only objects that can set key/value pairs in this way using variables? And if so, why? Why aren't we forced to do something like the following when working on the global level:
this.key = "value";
Or...
window.key = "value";
Is this just some caveat to the behavior of the language overall or is there some internally consistent logic about the window object in relation to all other objects that explains this?
Global variables (as opposed to local variables declared within a function) become properties of the global object.
In a browser, the global object is window.
The global environment is a so called Object Environment (Record):
Each object environment record is associated with an object called its binding object. An object environment record binds the set of identifier names that directly correspond to the property names of its binding object.
As you can see, the behavior to create properties for identifiers is explicitly defined. And in the case of the global environment, the binding object is the global object, which is window in browsers.
More detailed information about environments can be found in the spec:
There are two kinds of Environment Record values used in this specification: declarative environment records and object environment records. Declarative environment records are used to define the effect of ECMAScript language syntactic elements such as FunctionDeclarations, VariableDeclarations, and Catch clauses that directly associate identifier bindings with ECMAScript language values. Object environment records are used to define the effect of ECMAScript elements such as Program and WithStatement that associate identifier bindings with the properties of some object.
I can't tell you why these two types exist. If you want to know that, you could ask at http://esdiscuss.org/

What is "multiple variable assignment" really called?

I do this from time to time, especially in Javascript to store references to deeply nested properties in objects, but I am not sure on what this would be called. Multiple variable assigning? Variable reference assignment?
myVar = myObject.myProperty = value
Generally known as "chained assignment".
It is also important to differentiate the fact that you're not just assigning multiple variables, but you are assigning the return value of the deeper assignment operation. That is why it is a "chain" rather than some form of combined operation.

change JavaScript scope

Is there any posibility to exchange the special global window scope by a custom one? I just thought with is meant to, but it only stacks another "lookup" scope. Eg.
test={};
with(test){
a=1;
}
does not create the property test.a but window.a.
So the window object has a JS-specific special quality I cannot recreate with own code?
If the property exists on the object given to with then it will be modified, but it will never be created. This is a major "gotcha" with using with and the primary reason it should be avoided.
With with only if the object passed in has that property, will it be modified. It will not be created.
http://www.yuiblog.com/blog/2006/04/11/with-statement-considered-harmful/

What do square brackets around an expression mean, e.g. `var x = a + [b]`?

We have received some JavaScript from an agency that looks wrong, but works.
For some reason they are adding square brackets ([, ]) around variables, like this:
var some_variable = 'to=' + [other_variable];
This works, but the square brackets seem completely superfluous.
Is there a purpose of using this syntax or is it technically incorrect, but ignored by the browser?
Just in case anyone else arrives here while trying to find out what some weird/new syntax involving [square brackets] (seen in someone else's Javascript) might possibly be, like I was...
Nowadays, with ES6, we also have [] used on the left-hand side for destructuring arrays, e.g.
const names = ['Luke', 'Eva', 'Phil'];
const [first] = names;
console.log(first); // 'Luke'
const [first, second] = names;
console.log(first, second); // 'Luke' 'Eva'
For further info see http://www.deadcoderising.com/2017-03-28-es6-destructuring-an-elegant-way-of-extracting-data-from-arrays-and-objects-in-javascript/ or google 'es6 destructuring'.
Square brackets means new Array.
var ar=new Array("a","b");
var ar=["a","b"]; //Equal to the syntax above
in that situation there's no difference if you use square brackets or not because if it's an array it is converted to string, but if you delete the brackets it takes less time because it doesn't have to build a new array and convert it but it works with a simple string.
Even without changing the Array prototype there are differences:
var other_variable;
var some_variable = 'to=' + [other_variable];
If other_variable is undefined, the return value with the array is "to=".
Without the array, the return value is "to=undefined".
b = "bar" + ["foo"]
This is syntactically correct, but indeed very, very, superfluous. This is how it works:
["foo"]
JavaScript takes the string "foo" and converts it to an array with one element, "foo":
"bar" + ["foo"]
when + is used, and one of the operands is a string, "bar" in this case, JavaScript converts the second one to a string. Since operand two is an Array, the Array.toString method is called, which, by default, returns all elements joined by a comma. We have one element, and the result will be equal to this element, i.e., in this context "foo" is equivalent to ["foo"].
If you redefine Array.toString you can see better what's going on:
alert("bar" + ["foo"])
Array.prototype.toString = function() { return "???"; }
alert("bar" + ["foo"])
I bet someone told that person:
"Do the string concatenation with an array, it's faster!"
Meaning:
var some_variable = ['to=', other_variable].join("");
Which is apparently faster for lots of concatenations, but totally irrelevant, as that code will probably run just once anyway. Premature_optimization = sqrt(all_evil)!
And the poor chap did that other irrelevant thing...
I love people.
It's possible to construct a situation where this:
var some_variable = 'to=' + other_variable;
and this:
var some_variable = 'to=' + [other_variable];
produce different results. Specifically, if the Array.prototype.toString() method (or, I suppose, the Array.prototype.join() method) has been changed from its default, anything could happen. For example, extra functionality could be added to the Array.prototype.toString() method to generate logging information, do some lookups, or anything really.
The likelihood that this has been done is slim, I'd imagine, but it needs to be mentioned for completeness.
May be this ..
Global Variable access with the Square Bracket Notation
The square bracket notation requires that there be some sort of object reference to the left of the brackets.
["document"] //Array literal, not a Property Accessor!
-will produce an error if an attempt is made to assign a value to it, as it will be treated as an Array literal, if an attempt to read from it is made the one element array containing the string within the brackets is returned. Global variables are normally referenced by their one identifier alone. This would seem to exclude global variables from the possibility of being referenced using a string that held their identifier name or an expression that built, or returned, their name. However, javascript global variables (and global function names for that matter) are properties of a global object. Any identifier that holds a reference to the global object can be used to the left of the square brackets to form a property accessor that refers to a global variable.
In a web browser the global object is the window (or frame) in which the script is running. Each window (or frame) object contains a number of properties, at least two of which are references to the window (global object) itself. These properties are 'window' and 'self'. These property names can be used as the identifier to the left of the square brackets when referring to global variables. So given a global variable defined as:-
var anyName = 0;
that global variable can be referenced as:-
window["anyName"]
As with any other use of the square bracket notation, the string within the brackets can be held in a variable or constructed/returned by an expression.
Code that is executing in the global context, the code within global functions (except Object constructors invoked with the new keyword) and inline code outside of any functions, could also use the this keyword to refer to the global object. The this keyword refers to an object depending on the execution context. For code executing in the global context this is the global object (on a web browser, the window object). As a result, the above variable could be referred to as this["anyName"], but only in code that is executing in the global context.
However, using the this keyword is very likely to be confusing, especially in scripts that include custom javascript objects where the methods (and constructors) of those objects would be using this to refer to their own object instances.
Some javascript implementations do not have a property of the global object that refers to the global object. Rather than trying to use the this keyword to access global variables it is possible to create your own global variable that refers to the global object.
var myGlobal = this;
executed as inline code at the start of a script will assign a reference to the global object (this in that context). From then on all global variables can be referenced with square bracket notation as:-
myGlobal["anyName"];
and expect myGlobal to refer to the global object from any execution context.

Categories