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/
Related
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.
If I open a javascript console on a web page and add a variable:
var abc = "Hello";
Javascript attaches that property to the window object so I can simply access the object by window.abc or directly abc
console.log(window.abc)
console.log(abc)
Now, if I try to access something not defined yet through the window object
console.log(window.notdefinedyet)
> undefined
It simply returns undefined. So if I do
console.log(notdefinedyet)
why is that an error and not just undefined?
Because trying to read the value of an undeclared identifier is a ReferenceError. This is fundamentally a different operation from trying to read a property from an object that the object doesn't have.
Trying to use an undeclared identifier is usually a bug (for instance, a typo). That's part of why ES5's strict mode made assigning to an undeclared identifier a ReferenceError (instead of the old behavior — still in loose mode for backward-compatibility — where it creates a new global variable, something I call The Horror of Implicit Globals).
One could argue (and many have) that trying to get a property from an object that the object doesn't have is also a bug. But it's often really useful to get undefined instead of an error in that case. Whether one agrees with that distiction, this is how JavaScript is defined.
It's probably worth noting tangentially that this business of global variable declarations creating properties on the global object is legacy behavior that has to remain in place for backward compatibility, but isn't consistent with current thought on language design in TC39 (the committee behind JavaScript standards). Newer constructs like let, const, and class don't create properties on the global object even when used at global scope (although they do create globals):
var a = 1;
let b = 2;
console.log("a" in window); // true
console.log("b" in window); // false
console.log(a); // 1
console.log(b); // 2
It always check for reference so console.log(notdefinedyet) gives an error but in case of console.log(window.notdefinedyet), window has reference of object type built in only thing it does not have notdefinedyet key
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
This question is inspired by:
ng-model in numeric input does not affect scope
In that question I was surprised to learn that somehow I have nested controllers even though I have exactly one controller per template and I have no custom directives. This might have something to do with Ionic.
I had a problem that I couldn't access primitive $scope properties without wrapping them in objects. I had this problem regardless what I named the primitive property. I could only access it from my template if I wrapped it in an object or referred to $parent.
How come I can't access the primitives regardless of name? I would understand that there can be a naming conflict, but no name worked. And if no name works, then why do primitives wrapped in objects work? Why do I not need to write $parent.object in my template to access an object attached to my $scope?
Accessing vs Defining values
When accessing a value (such as using {{ value }}, or method()), the application will climb up parent scopes looking for the value until it reaches $rootScope: the first version found, if any, is then used.
When defining a value, however (such as using value = 'foo'), it applies it to the current scope, even if a value exists with the same key under a parent scope.
Defining primitives vs defining object properties
When setting a primitive value such as 'value', you're simply defining what value is:
value = 123;
But when defining the property of an object, the object has to be accessed before the property change can be applied to it:
object.value = 123;
The above code looks for object, and applies the change to its value property. If object doesn't exist in the current scope, the application will search up the parent scopes to find object, so it can access it. Then, the change to value is applied to that instance of object. If object doesn't exist at all, the code will throw an error because it is essentially the below:
null.value = 123;
Example
Similar functionality can be seen in vanilla Javascript through prototypal inheritance.
var parent = { primitive: 123, object: { value: 123 } };
var child = Object.create(parent);
console.log(child.primitive); // 123, from parent
console.log(child.object.value); // 123, from parent
child.primitive = 456; // modifies own primitive key
console.log(child.primitive); // 456, from self
console.log(parent.primitive); // still 123
child.object.value = 456; // modifies parent's object's value
console.log(child.object.value); // 456, from parent
console.log(parent.object.value); // 456, since it was modified above
JavaScript objects are dynamic "bags" of properties (referred to as
own properties). JavaScript objects have a link to a prototype object.
When trying to access a property of an object, the property will not
only be sought on the object but on the prototype of the object, the
prototype of the prototype, and so on until either a property with a
matching name is found or the end of the prototype chain is reached.
Read more here
You need to know the prototype inheritance of javascript first.
Then understand how scope works with this very helpful guide.
From what I know, javascript, that is also based on ECMAscript the same as actionscript, does not really pass objects by reference. At least that's what I've read lately. For instance:
function doStuff(myObj){
myObj.name = 'groovy chicken';
myObj = null;
}
var newObj = new Object();
doStuff(newObj);
This is an example I found in a book 'Professional Javascript for web developers'. Although you are passing an object to the function, and adding the name property actually adds the property to your initial object, when you set to null, the object is destroyed in the local scope not in the global scope.
To me, this is still a bit confusing, since the myObj you have, is still pointing the same place as newObj and you can actully add or alter properties. The only difference is that you can not destroy it from the global scope.
So I'm wondering if the same also applies to actionscript, since from what I've read, actionscript 3 does actually pass objects by reference and I've not read anything stating the opposite.
Very few modern programming languages pass by reference (at least by default). In the twisted terminology of "pass by..", you're passing a reference by value. Here's how to think about it:
myObj and newObj are just variables, names for things.
The value of those variables are references to the object
When you call doStuff(), you're binding the name myObj to a new reference to your object (i.e. the reference itself was passed by value)
The reference points to a chunk of memory with some stuff in it, which is what lets you change the name inside of doStuff()
You can see that change by inspecting either variable because both variables contain references to the same object
myObj = null reassigns the variable to nothing, and in the process, it "destroys" the reference, but it doesn't destroy the object.
When the garbage collector notices there are no more references to an object, it will destroy that object
I'll try to help you understand the working of JavaScript's object:
when you say,
var newobj = new Object();
Here, newobj is only a name to the memory location allocated when you created an instance of Object.
When you pass newobj, it takes along the reference to the memory location. Now, myObj in the function is another name to the same memory location.
Adding a method 'name' adds it to the memory location and hence is available to both newobj and myobj.
when you set myobj to null, it removes that named reference and newobj still remains alive with the name property set.
But, I dont have an idea on how this works in actionscript.