What is "multiple variable assignment" really called? - javascript

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.

Related

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

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.

How do you store activation records with complex lexical scopes and returning functions as results and such?

I have read in several places such as here about "Access Links" and "The Display Method" for looking up non-local variables. However, none seem to touch on the complicated situation like in JavaScript where you can have functions inside of functions, and return those functions from functions, all the while keeping alive the "internal scope" of those functions.
Here is a complicated nested function.
let m = foo()
m()
m()
function foo() {
let x = 10
function bar() {
let y = 2 ** x
function hello() {
let z = 30
function another() {
// PLACE_2
let q = x + y + z
function nested() {
q += (17 * x) - (3 * z)
// PLACE_1
console.log(q)
console.log(w)
}
return nested
}
// PLACE_3
let w = another()
return w
}
return hello
}
// PLACE_4
let a = bar()
let nested = a() // hello returns another
nested()
nested()
return nested
}
At PLACE_1, we are using variables x/z/q, but not y/a/nested. Basically we create all these lingering objects in the scope tree.
How does an activation record with "Access Links" or "Display Method" work in a situation like this? I am used to having functions call other functions, but not keep the environment of past functions around. How do these work in a complex system like this with scopes lingering?
I am trying to implement a compiler and am currently stuck on how to actually implement the Activation Records. I can do it where the activation records are a simple parent/child relationship based on calling order, but I don't see how to make it work with a situation like this. I want to have a sort of variable lookup mechanism, but I don't know what needs to be stored in a situation like this.
Reading something like this doesn't give any insight into real-world situations like this, how it's modeled under the hood.
Displays can only be used if the semantics of the language don't allow non-local variables to outlive their original scope, since the display is basically an efficient eay to find an activation record on the stack. If you want to implement true closures, you'll need to use a different mechanism which involves heap-allocation of enclosed variables. (Unless you can prove that the enclosed variable never escapes. That's often the case, but it can be hard to prove.)
AUUI, Javascript retains the entire activation record of the function call which created the closed variable. But that's dependent on the semantics of the language, and unnecessarily keeping active links to other variables in the activation record prevents them from being garbage collected in a timely manner. It should only be necessary to keep links to the variables actually being enclosed.
Note that there are two distinct cases (again, this depends on language semantics). In the simple case, the captured variable is immutable (although it might contain a mutable value). In that case, you can capture the value by adding it as a data member in the closure. (The closure object itself needs to be heap-allocated but you don't need to do that until the closure is actually created, which might never happen.)
In the more complicated case, the variable itself is mutable and potentially mutated by the inner function [Note 1]. In that case, the variable itself must be "boxed"; that is, enclosed in a container which is used as a handle for the variable. But the mutation might happen before the variable's scope terminates, in which case the change needs to be visible in that scope. If the variable is boxed, the outer function needs to be aware of that because access to the variable is indirect. So boxing the variable onto the heap is a cost which must be paid before it is known to be necessary (depending on the quality of the escape analysis).
That's where the Lua implementation is interesting, at least. It manages to avoid heap-allocating the box in many cases, but there is an additional cost when it does so. That seems to work out well for Lua use cases but I don't know whether it would be a good solution in your case.
Notes:
There's a very common case where a variable is mutable because its value cannot conveniently be computed in a single initialisation expression, but all mutations occur before the variable is captured. Such a variable can be treated as though it were immutable (or as though it was computed and then made the value of a different variable with the same name). That case is fairly easy to detect. (There are also variables whose last mutation is after capture but before the first invocation of a capturing function. Those can also usually be detected.) These variables can be captured as though they were constant, just putting the value into the closure.
Informal surveys indicate that the vast majority of captured variables are either constant or constant-after-capture, which could considerably reduce the need for heap-allocated boxes.

Changing array member within local scope changes member in global scope

Why does JavaScript treat the scope of an array differently than it does the scope of other variables? Typically, if one passes a variable in a global scope into a function as a parameter, it is then local and changing it within the function does not change the value of the global variable. For example:
var globalInt = 1;
function test1(x){
x = x + 1
}
test1(globalInt);
console.log(globalInt); //globalInt is still 1
However, it appears the same does not apply when passing an array of values.
var globalArray = ["TEST"];
function test(x){
x[0] = x[0].toLowerCase()
}
test(globalArray);
//globalArray is now ["test"] instead of ["TEST"]
console.log(globalArray[0]);
This happens for me when I test in Chrome, but I have not tested it in other browsers so far. Why does this happen and does it happen in other browsers?
This is simply because an array (which is an Object) are passed by reference while primitives are not. Note that technically it is passed by value but in this case that value is a reference, thanks Esteban
A object is automatically passed by reference, without the need to specifically state it
If you pass an object (i.e. a non-primitive value, such as Array or a user-defined object) as a parameter and the function changes the object's properties, that change is visible outside the function, as shown in the following example:
MDN Link
Yes... JavaScript objects and arrays (which are objects) are passed by reference. But you should remember to read the method signature explicitly because some array methods don't alter the original array but return a new one. Read the MDN documentation carefully about the method in question. Array.prototype.map() would actually leave the original array intact and return a brand new array which you'd need to set to assign to a variable.

Accessing parent scope value with standard method

Today I wondered after some strange behavior of angularjs. I used console.log to log $scope, there were no key attached to scope named val1, but when I use console.log($scope.val1) its returning value as a object. After digging out the reason, I found that it was accessing parent scope as there is no kay named val1 in $scope. Now my question is that,
Which is good practice? Can you please justify?
Using $scope.$parent.val1
Using $scope.val1
You should generally never use $scope.$parent and instead rely on Javascripts prototypal inheritance. By accessing the parent directly, you run the risk of the code breaking if you move the directive/controller a step up in the scope hierarchy, and the data is now on $scope.$parent.$parent instead.
Instead, never write to properties directly on the scope but to objects on the scope object instead.
Say you do:
$scope.$parent.value = 'x';
Then you do:
console.log($scope.value);
That'll print x to the console. If you then do:
$scope.value = 'y';
You're not modifying the value property on the parent scope, but introducing a new property on the child scope. So $scope.$parent.value will still contain x.
To get around that, you do:
$scope.$parent.data = {value: 'x'};
console.log($scope.data.value); // prints x
$scope.data.value = 'y';
console.log($scope.data.value); // prints y
console.log($scope.$parent.data.value); // also prints y
The reason this works is that instead of creating a new value property on the child scope, it first needs to lookup the data property. And that's not on the child scope, so it goes up the prototype chain ($parent) to find the data object. The data object is found on the parent, and the value property is set on that object instead.
It depends on the type of val1, in case it is a primitive, you will have to access it explicitly via $scope.$parent.
In case it is an object, you can take advantage of the prototypal inheritance that exists between parent and child scope in Angular and just reference it regularly, as I am sure you are aware of, objects are passed by reference, so any change to the object will change it on the parent scope.
More info here

Do closures in Javascript get a reference to the full outer function or do they only get references to the variables they actually use?

Just out of curiosity, do closures in JavaScript get a reference to the whole "outer environment", or is the returned function analyzed to see which variables in the outer scope it references and then only gets references to those?
Theoretically, a nested function in JavaScript has access to all variables in all containing scopes. When an identifier is encountered, it is resolved against the scope chain, which is a list that includes objects whose properties are variables and function parameters of each containing execution context (i.e. enclosing function), innermost first, plus the global object at the end. A function object drags its scope chain around with it wherever it goes.
However, these Variable objects and the scope chain are only specification constructs and are not accessible directly, so implementations are free to make whatever optimizations they like, including analyzing function code and only exposing variables that are accessed by a function and any functions nested within it, so long as the specification always appears to be satisfied. However, it's best to assume that if you have an enormous object that is accessible via a closure to a function, that enormous object is going to stick around at least until that function is garbage collected.
If you want further information about this, read the ECMAScript specification. A good starting point would be section 10.1.4: http://bclary.com/2004/11/07/#a-10.1.4. This is not the current version of the specification but is the baseline for what all current major browsers implement.
The answer is "yes and no". When a function "leaks" out of a function activation, the entire context is preserved*. However, as there's no way to refer to the context itself, the code of a function cannot "investigate" the context(s). Thus:
function leaker() {
var i = 100, j = "hello there";
return function() {
i = i - 1;
return i == 0;
}
}
The returned function can only ever refer to "i". The variable "j" may stick around, but there's no way for code in that returned function to "find" it.
* I write that the context is preserved, which I believe to be true, but technically that's the business of the interpreter/runtime.

Categories