How to access an outer member from a nested object literal? - javascript

In the following code, can the x member be accessed from the nested object literal?
var outer = {
x : 0,
inner: {
a : x + 1, // 'x' is undefined.
b : outer.x + 1, // 'outer' is undefined.
c : this.x + 1 // This doesn't produce an error,
} // but outer.inner.c is NaN.
}

In the way you put it - no.
You need two stages construction, this will work:
var outer = { x : 0 };
// outer is constructed at this point.
outer.inner = {
b : outer.x + 1 // 'outer' is defined here.
};

Not in the construct you have there, no.
The main reason being that outer doesn't actually exist yet when you are inside inner.
If you changed the properties of inner to functions you could access outer at runtime, but it would be pretty ugly code.
Consider using new outer(); instead and build an object that way, then you can use this inside inner, but then that is a completely different construct and would look something like
var outer = function() {
this.x = 0;
this.inner = {
a: this.x + 1
};
};
var b = new outer();
console.log(b.inner.a); // 1

I don't think that sort of construct would make sense. I don't think there's anything stopping you from saying
var outer2;
outer2.inner = outer.inner;
In that scenario, how would you distinguish between the two parents?
The way to do it is probably with more of a constructor type function, with a parameter that gets assigned to outer.x and inner.whatever as needed.

You could also use a closure:
var outer = function outer() {
var x = 0;
return {
inner : {
a: x + 1
}
}
};
var b = outer();
console.log('a is ' + b.inner.a);
//a is 1
For a great article on closures check out the javascript garden
http://bonsaiden.github.com/JavaScript-Garden/#closures

Related

JavaScript object related question that what will be the output of below code?

var x = 3;
var one = {
x:2,
two: {
x:1,
three:function(){
return this.x;
}
}
}
var go = one.two.three;
console.log(one.two.three() + "" + go());
Anyone can explain to me why output coming 13 why not 1-undefined?
this keyword has a different binding that can change during runtime, depending on how the function was invoked.
When a function is on an object, and is accessed through that object, it's this context will be that object (unless explicitly bound otherwise, but I'll add notes on that later). This means this.x is referencing the same variable as one.two.x
When you reference that same function into a global variable, the this context becomes the global space (e.g. the window object on browsers, or globalThis in NodeJS). When this happens, this.x is now referencing global variable x.
There are other situations where this context rules are different, such as function closures or class functions.
Functions also have .bind method that returns a new function with an explicitly bound this variable.
e.g:
var x = 3;
var one = {
x:2,
two: {
x:1,
three:function(){
return this.x;
}
}
}
one.two.three = one.two.three.bind(one);
var go = one.two.three;
console.log(one.two.three() + "" + go()); // prints 22
There are also arrow functions, which implicitly have the this context bound to it's lexical scope... e.g:
var x = 3;
var one = {
x:2,
two: {
x:1,
three: () => {
return this.x;
}
}
}
var go = one.two.three;
console.log(one.two.three() + "" + go()); // prints 33
This above example prints 33, because the lexical scope is the global scope, thus this.x is referencing global variable x.
Hope this answers your question without creating more questions.
Further Reading:
this keyword
Interesting. I think it has something to do with scopes.
console.log(one.two.three() + "" + go());
//equals console.log(1 + "" + 3);
will output 13 (String) because:
one.two.three() returns 1
go() returns 3
those numbers are concatenated into String with "" (empty string) in between (instead of - as you may have asked)
Why go() returns 3
var x = 3;
// var go = one.two.three;
// equals
var go = function() {
return this.x
}
The declaration var go = one.two.three; assigns one.two's three method as a function into the variable go in the global scope. The same scope with go, one, and x (with the value 3), that was declared before declaring one and go (var x= 3;).
Based on your whole codes, this.x's this is in the global scope. and this.x is 3. So running go() returns 3.
one.two.three is a global function
→ notice there's no (), so assigning a function to global scope's variable go will make the function's scope global.
→ go function is run under global's scope
Why one.two.three() returns 1
Well, one.two.three is a method inside the object two, which is inside the object one. While the definition looks the same,
function() {
return this.x;
}
when you run three method of two object, return this.x's this refers to the method's parent object (which is two, three's parent object is two).
So,
this.x refers to
two.x which is 1.
Hence, in this case return this.x; outputs 1.
one.two.three() is 1
→ notice the () which means run the function
→ three method is run under two's scope
Addition
This will output 1-undefined because:
y is not defined in the global/one/go scope
I use - as a delimiter in console.log
var one = {
y:2,
two: {
y: 1,
three:function(){
return this.y;
}
}
}
var go = one.two.three;
console.log(one.two.three() + "-" + go());
To assign an object method to a variable, it needs to be bandaged using the bind() function, and if the global variable window is passed to the context, the answer will be 13
*var go = one.two.three.bind(window);*
if the object is one the answer will be 12
*var go = one.two.three.bind(one);*
if the object is two the answer will be 11
*var go = one.two.three.bind(two);*

why does var behave differently in a with statement depending on whether or not the passed object has a property with the same name?

function foo(obj) {
with(obj) {
var x = 2;
}
console.log(x);
}
let o1 = {};
foo(o1); // 2 (x is visible even outside the with statement because of *var*)
function foo2(obj) {
with(obj) {
var x = 2;
}
console.log(x);
}
let o2 = {
x: 1
};
foo2(o2); // undefined (why?)
I'm reading along Kyle Simpson's Scope & Closures book from the YDKJS series and I was able to understand all of the quirks of with statements and how with(obj) { a = 1 } is functionally different from obj.a = 1 despite having been intended as a shorthand for it in cases of long object names and having to constantly reference it. This is because the object's properties are treated as lexically defined identifiers in that scope (a vs obj.a), and that in sloppy mode, one side effect of this is that if the object you pass into a with statement doesn't have a property that you are trying to assign to, a global variable of that name will be created. Still, armed with all this knowledge and more, I don't quite understand why the code above behaves the way it does. Why does foo(o2) log undefined?
The difference in behaviour can be accounted for by this behaviour, described in (for instance) the following note in ECMAScript 2022 Language Specification sect 14.3.2.1:
NOTE: If a VariableDeclaration is nested within a with statement and the BindingIdentifier in the VariableDeclaration is the same as a property name of the binding object of the with statement's object Environment Record, then step 5 will assign value to the property instead of assigning to the VariableEnvironment binding of the Identifier.
In the first case:
function foo(obj) {
with(obj) {
var x = 2;
}
console.log(x);
}
let o1 = {};
foo(o1);
because obj has no x property, the var statement is hoisted to the top of the function and is therefore visible beyond the scope of the with statement.
In the second case:
function foo2(obj) {
with(obj) {
var x = 2;
}
console.log(x);
}
let o2 = {
x: 1
};
foo2(o2);
x exists on obj, so we satisfy the conditions laid out in the quoted note, and therefore the value is assigned to the property and no hoisted variable is created. Now, there's no x outside the scope of the with statement.

Explain the debugging values for javascript closure

I'd like to understand the debugging content during the execution of the following code:
var z = 2;
var SQUAREPLUSOTHER = x => y => ((x*x) + y + z);
var x = 3;
console.log("SQUAREPLUSOTHER", SQUAREPLUSOTHER);
var squareoftwoplusother = (SQUAREPLUSOTHER)(x);
x = 4;
z = 4;
var result = squareoftwoplusother(5);
console.log("result", result);
Now....
At the call of:
console.log("SQUAREPLUSOTHER", SQUAREPLUSOTHER);
the debug shows clearly:
squareoftwoplusother: undefined
SQUAREPLUSOTHER: x=>...
x: 3
z: 2
at the following call of:
var SQUAREPLUSOTHER = x => y => ((x*x) + y + z);
the debug shows:
Local:
x: 3
Closure
z: 2
at the following call of:
x = 4;
z = 4;
the debug shows:
squareoftwoplusother: y=>...
SQUAREPLUSOTHER: x=>...
x: 4
z: 4
at the following call of:
var result = squareoftwoplusother(5);
the debug shows:
result: 18
squareoftwoplusother: y=>...
SQUAREPLUSOTHER: x=>...
Local:
x: 5
Closure
x: 3
Closure
z: 4
and at the final calls the debug shows:
result: 18
squareoftwoplusother: y=>...
SQUAREPLUSOTHER: x=>...
x: 4
z: 4
now the questions:
How many "Closures"? They belongs to? (i.e. how to explain...)
Local:
x: 5
Closure
x: 3
Closure
z: 4
How the scope of the variables is managed in javascript?
How to have a "definitive" idea in terms of "context" or "whatever it be" about the mess of closure :-)?
thanks in advance
Ed
Every time a function is called, a local scope is created for that function. If there is still a reference to that local scope after the function returns, then a closure is created. Once the reference is gone, the closure is also garbage collected.
If you add breakpoints to the first line of every function, you will see that scopes are created that may later become closures.
A great explanation is given here http://dmitrysoshnikov.com/ecmascript/javascript-the-core/#activation-object
I'll add some braces to your code to make that easier and I'll add self calling function to add a level of closures.
(() => {
var z = 2;
var SQUAREPLUSOTHER = (x) => {
debugger;
return (y) => {
debugger;
return (x * x) + y + z;
}
};
var x = 3;
console.log("SQUAREPLUSOTHER", SQUAREPLUSOTHER);
var squareoftwoplusother = (SQUAREPLUSOTHER)(x);
x = 4;
z = 4;
var result = squareoftwoplusother(5);
console.log("result", result);
debugger
})()
The screenshots below are from Chrome DevTools which minimizes the closures, that is, it only maintains references to what is needed. Back in the days, the entire closure was always available and you could prove it because it showed up in the closures pane of debuggers. See Javascript closures performance for further details
Scope
There are just three different scopes in your code. One is the global scope all variables you declare in and the other two are here:
var SQUAREPLUSOTHER = x => y => ((x*x) + y + z);
There are two function scopes, one containing the variable x and the other function scope containing the variable y. It might be easier to see if you replace the arrow function with functions:
// global scope
function SQUAREPLUSOTHER(x) {
// function scope containing x
return function(y) {
// function scope containing y
return (x*x) + y + z;
};
}
How scoping works is actually quite simple:
Every { starts a new scope and its counter } closes it, variables declared inside it with let and const (or var but thats slightly more complicated) are part of the scope. If it is the scope of a function, the parameters (e.g. x and y) are part of that scope.
From the code, you can access the all variables that are in the current scope or in its parent scope, if there are multiple with the same name you get the most inner one. Therefore x inside of the SQUAREPLUSOTHER function refers to the variable of the SQUAREPLUSOTHER scope, while for code outside of it x is the global variable and the functions variable can't be accessed.
The Scope of a variable does not change at runtime, you can always directly see which scope a variable belongs tp by looking at the surrounding { .. }.
Now different variables in different scopes have to hold values at runtime, thats where we get to:
the environment record
When you call a function, the JavaScript engine creates a new "EnvironmentRecord" (which is like an internal object) that contains all the variables of the function you call, e.g. in this case:
function test(a) {
let b;
}
Then if you call that function (test(1)) a new environment record gets created that contains a and b. Now the code inside the function gets run, and every variable is looked up in it. If there are two functions nested into another, calling the inner function will create an environment record that holds a reference to the outer one:
function test(a) {
function test2(b) {
}
test2(5);
}
Now calling test(1) will create an record where a is 1. If the engine then executes the second call (test2(5)) it creates another record containing b being 5, and that holds a reference to the record containing a. Now if you use a inside test2, the engine will look it up in the current environment record, won't find it, and then look it up in the parent where it finds a being 1.
closure
Usually those records get deleted when the execution reaches the }, however if there is another record that got the current record as a parent, it won't get deleted. It will exist until all child records got deleted, then it will also remove the parent. This behaviour (variables live longer because they can be accessed from an inner functions body) is called a closure.

How does one modify a global variable that is used as an argument [duplicate]

How do I pass variables by reference in JavaScript?
I have three variables that I want to perform several operations to, so I want to put them in a for loop and perform the operations to each one.
Pseudocode:
myArray = new Array(var1, var2, var3);
for (var x = 0; x < myArray.length; x++){
// Do stuff to the array
makePretty(myArray[x]);
}
// Now do stuff to the updated variables
What is the best way to do this?
There is no "pass by reference" available in JavaScript. You can pass an object (which is to say, you can pass-by-value a reference to an object) and then have a function modify the object contents:
function alterObject(obj) {
obj.foo = "goodbye";
}
var myObj = { foo: "hello world" };
alterObject(myObj);
alert(myObj.foo); // "goodbye" instead of "hello world"
You can iterate over the properties of an array with a numeric index and modify each cell of the array, if you want.
var arr = [1, 2, 3];
for (var i = 0; i < arr.length; i++) {
arr[i] = arr[i] + 1;
}
It's important to note that "pass-by-reference" is a very specific term. It does not mean simply that it's possible to pass a reference to a modifiable object. Instead, it means that it's possible to pass a simple variable in such a way as to allow a function to modify that value in the calling context. So:
function swap(a, b) {
var tmp = a;
a = b;
b = tmp; //assign tmp to b
}
var x = 1, y = 2;
swap(x, y);
alert("x is " + x + ", y is " + y); // "x is 1, y is 2"
In a language like C++, it's possible to do that because that language does (sort-of) have pass-by-reference.
edit — this recently (March 2015) blew up on Reddit again over a blog post similar to mine mentioned below, though in this case about Java. It occurred to me while reading the back-and-forth in the Reddit comments that a big part of the confusion stems from the unfortunate collision involving the word "reference". The terminology "pass by reference" and "pass by value" predates the concept of having "objects" to work with in programming languages. It's really not about objects at all; it's about function parameters, and specifically how function parameters are "connected" (or not) to the calling environment. In particular, note that in a true pass-by-reference language — one that does involve objects — one would still have the ability to modify object contents, and it would look pretty much exactly like it does in JavaScript. However, one would also be able to modify the object reference in the calling environment, and that's the key thing that you can't do in JavaScript. A pass-by-reference language would pass not the reference itself, but a reference to the reference.
edit — here is a blog post on the topic. (Note the comment to that post that explains that C++ doesn't really have pass-by-reference. That is true. What C++ does have, however, is the ability to create references to plain variables, either explicitly at the point of function invocation to create a pointer, or implicitly when calling functions whose argument type signature calls for that to be done. Those are the key things JavaScript doesn't support.)
Primitive type variables like strings and numbers are always passed by value.
Arrays and Objects are passed by reference or by value based on these conditions:
if you are setting the value of an object or array it is Pass by Value.
object1 = { prop: "car" };
array1 = [1,2,3];
if you are changing a property value of an object or array then it is Pass by Reference.
object1.prop = "car";
array1[0] = 9;
Code
function passVar(obj1, obj2, num) {
obj1.prop = "laptop"; // will CHANGE original
obj2 = { prop: "computer" }; //will NOT affect original
num = num + 1; // will NOT affect original
}
var object1 = {
prop: "car"
};
var object2 = {
prop: "bike"
};
var number1 = 10;
passVar(object1, object2, number1);
console.log(object1); // output: Object { prop: "laptop" }
console.log(object2); // output: Object { prop: "bike" }
console.log(number1); // ouput: 10
Workaround to pass variable like by reference:
var a = 1;
inc = function(variableName) {
window[variableName] += 1;
};
inc('a');
alert(a); // 2
And yup, actually you can do it without access a global variable:
inc = (function () {
var variableName = 0;
var init = function () {
variableName += 1;
alert(variableName);
}
return init;
})();
inc();
Simple Object
function foo(x) {
// Function with other context
// Modify `x` property, increasing the value
x.value++;
}
// Initialize `ref` as object
var ref = {
// The `value` is inside `ref` variable object
// The initial value is `1`
value: 1
};
// Call function with object value
foo(ref);
// Call function with object value again
foo(ref);
console.log(ref.value); // Prints "3"
Custom Object
Object rvar
/**
* Aux function to create by-references variables
*/
function rvar(name, value, context) {
// If `this` is a `rvar` instance
if (this instanceof rvar) {
// Inside `rvar` context...
// Internal object value
this.value = value;
// Object `name` property
Object.defineProperty(this, 'name', { value: name });
// Object `hasValue` property
Object.defineProperty(this, 'hasValue', {
get: function () {
// If the internal object value is not `undefined`
return this.value !== undefined;
}
});
// Copy value constructor for type-check
if ((value !== undefined) && (value !== null)) {
this.constructor = value.constructor;
}
// To String method
this.toString = function () {
// Convert the internal value to string
return this.value + '';
};
} else {
// Outside `rvar` context...
// Initialice `rvar` object
if (!rvar.refs) {
rvar.refs = {};
}
// Initialize context if it is not defined
if (!context) {
context = this;
}
// Store variable
rvar.refs[name] = new rvar(name, value, context);
// Define variable at context
Object.defineProperty(context, name, {
// Getter
get: function () { return rvar.refs[name]; },
// Setter
set: function (v) { rvar.refs[name].value = v; },
// Can be overrided?
configurable: true
});
// Return object reference
return context[name];
}
}
// Variable Declaration
// Declare `test_ref` variable
rvar('test_ref_1');
// Assign value `5`
test_ref_1 = 5;
// Or
test_ref_1.value = 5;
// Or declare and initialize with `5`:
rvar('test_ref_2', 5);
// ------------------------------
// Test Code
// Test Function
function Fn1(v) { v.value = 100; }
// Test
function test(fn) { console.log(fn.toString()); console.info(fn()); }
// Declare
rvar('test_ref_number');
// First assign
test_ref_number = 5;
test(() => test_ref_number.value === 5);
// Call function with reference
Fn1(test_ref_number);
test(() => test_ref_number.value === 100);
// Increase value
test_ref_number++;
test(() => test_ref_number.value === 101);
// Update value
test_ref_number = test_ref_number - 10;
test(() => test_ref_number.value === 91);
Yet another approach to pass any (local, primitive) variables by reference is by wrapping variable with closure "on the fly" by eval. This also works with "use strict". (Note: be aware that eval is not friendly to JavaScript optimizers, and also missing quotes around variable name may cause unpredictive results)
"use strict"
// Return text that will reference variable by name (by capturing that variable to closure)
function byRef(varName){
return "({get value(){return "+varName+";}, set value(v){"+varName+"=v;}})";
}
// Demo
// Assign argument by reference
function modifyArgument(argRef, multiplier){
argRef.value = argRef.value * multiplier;
}
(function(){
var x = 10;
alert("x before: " + x);
modifyArgument(eval(byRef("x")), 42);
alert("x after: " + x);
})()
Live sample: https://jsfiddle.net/t3k4403w/
There's actually a pretty sollution:
function updateArray(context, targetName, callback) {
context[targetName] = context[targetName].map(callback);
}
var myArray = ['a', 'b', 'c'];
updateArray(this, 'myArray', item => {return '_' + item});
console.log(myArray); //(3) ["_a", "_b", "_c"]
I personally dislike the "pass by reference" functionality offered by various programming languages. Perhaps that's because I am just discovering the concepts of functional programming, but I always get goosebumps when I see functions that cause side effects (like manipulating parameters passed by reference). I personally strongly embrace the "single responsibility" principle.
IMHO, a function should return just one result/value using the return keyword. Instead of modifying a parameter/argument, I would just return the modified parameter/argument value and leave any desired reassignments up to the calling code.
But sometimes (hopefully very rarely), it is necessary to return two or more result values from the same function. In that case, I would opt to include all those resulting values in a single structure or object. Again, processing any reassignments should be up to the calling code.
Example:
Suppose passing parameters would be supported by using a special keyword like 'ref' in the argument list. My code might look something like this:
//The Function
function doSomething(ref value) {
value = "Bar";
}
//The Calling Code
var value = "Foo";
doSomething(value);
console.log(value); //Bar
Instead, I would actually prefer to do something like this:
//The Function
function doSomething(value) {
value = "Bar";
return value;
}
//The Calling Code:
var value = "Foo";
value = doSomething(value); //Reassignment
console.log(value); //Bar
When I would need to write a function that returns multiple values, I would not use parameters passed by reference either. So I would avoid code like this:
//The Function
function doSomething(ref value) {
value = "Bar";
//Do other work
var otherValue = "Something else";
return otherValue;
}
//The Calling Code
var value = "Foo";
var otherValue = doSomething(value);
console.log(value); //Bar
console.log(otherValue); //Something else
Instead, I would actually prefer to return both new values inside an object, like this:
//The Function
function doSomething(value) {
value = "Bar";
//Do more work
var otherValue = "Something else";
return {
value: value,
otherValue: otherValue
};
}
//The Calling Code:
var value = "Foo";
var result = doSomething(value);
value = result.value; //Reassignment
console.log(value); //Bar
console.log(result.otherValue);
These code examples are quite simplified, but it roughly demonstrates how I personally would handle such stuff. It helps me to keep various responsibilities in the correct place.
Happy coding. :)
I've been playing around with syntax to do this sort of thing, but it requires some helpers that are a little unusual. It starts with not using 'var' at all, but a simple 'DECLARE' helper that creates a local variable and defines a scope for it via an anonymous callback. By controlling how variables are declared, we can choose to wrap them into objects so that they can always be passed by reference, essentially. This is similar to one of the Eduardo Cuomo's answer above, but the solution below does not require using strings as variable identifiers. Here's some minimal code to show the concept.
function Wrapper(val){
this.VAL = val;
}
Wrapper.prototype.toString = function(){
return this.VAL.toString();
}
function DECLARE(val, callback){
var valWrapped = new Wrapper(val);
callback(valWrapped);
}
function INC(ref){
if(ref && ref.hasOwnProperty('VAL')){
ref.VAL++;
}
else{
ref++;//or maybe throw here instead?
}
return ref;
}
DECLARE(5, function(five){ //consider this line the same as 'let five = 5'
console.log("five is now " + five);
INC(five); // increment
console.log("five is incremented to " + five);
});
Actually it is really easy. The problem is understanding that once passing classic arguments, you are scoped into another, read-only zone.
The solution is to pass the arguments using JavaScript's object-oriented design. It is the same as putting the arguments in a global/scoped variable, but better...
function action(){
/* Process this.arg, modification allowed */
}
action.arg = [["empty-array"], "some string", 0x100, "last argument"];
action();
You can also promise stuff up to enjoy the well-known chain:
Here is the whole thing, with promise-like structure
function action(){
/* Process this.arg, modification allowed */
this.arg = ["a", "b"];
}
action.setArg = function(){this.arg = arguments; return this;}
action.setArg(["empty-array"], "some string", 0x100, "last argument")()
Or better yet...
action.setArg(["empty-array"],"some string",0x100,"last argument").call()
JavaScript can modify array items inside a function (it is passed as a reference to the object/array).
function makeAllPretty(items) {
for (var x = 0; x < myArray.length; x++){
// Do stuff to the array
items[x] = makePretty(items[x]);
}
}
myArray = new Array(var1, var2, var3);
makeAllPretty(myArray);
Here's another example:
function inc(items) {
for (let i=0; i < items.length; i++) {
items[i]++;
}
}
let values = [1,2,3];
inc(values);
console.log(values);
// Prints [2,3,4]
Putting aside the pass-by-reference discussion, those still looking for a solution to the stated question could use:
const myArray = new Array(var1, var2, var3);
myArray.forEach(var => var = makePretty(var));
As we don't have javascript pass by reference functionality, the only way to do this is to make the function return the value and let the caller assign it:
So
"makePretty(myArray[x]);"
should be
"myArray[x] = makePretty(myArray[x]);"
This is in case you need assignment inside the function, if only mutation is necessary, then passing the object and mutating it should be enough
I know exactly what you mean. The same thing in Swift will be no problem. The bottom line is use let, not var.
The fact that primitives are passed by value, but the fact that the value of var i at the point of iteration is not copied into the anonymous function is quite surprising to say the least.
for (let i = 0; i < boxArray.length; i++) {
boxArray[i].onclick = function() { console.log(i) }; // Correctly prints the index
}
If you want to pass variables by reference, a better way to do that is by passing your arguments in an object and then start changing the value by using window:
window["varName"] = value;
Example:
// Variables with first values
var x = 1, b = 0, f = 15;
function asByReference (
argumentHasVars = {}, // Passing variables in object
newValues = []) // Pass new values in array
{
let VarsNames = [];
// Getting variables names one by one
for(let name in argumentHasVars)
VarsNames.push(name);
// Accessing variables by using window one by one
for(let i = 0; i < VarsNames.length; i += 1)
window[VarsNames[i]] = newValues[i]; // Set new value
}
console.log(x, b, f); // Output with first values
asByReference({x, b, f}, [5, 5, 5]); // Passing as by reference
console.log(x, b, f); // Output after changing values
I like to solve the lack of by reference in JavaScript like this example shows.
The essence of this is that you don't try to create a by reference. You instead use the return functionality and make it able to return multiple values. So there isn't any need to insert your values in arrays or objects.
var x = "First";
var y = "Second";
var z = "Third";
log('Before call:',x,y,z);
with (myFunc(x, y, z)) {x = a; y = b; z = c;} // <-- Way to call it
log('After call :',x,y,z);
function myFunc(a, b, c) {
a = "Changed first parameter";
b = "Changed second parameter";
c = "Changed third parameter";
return {a:a, b:b, c:c}; // <-- Return multiple values
}
function log(txt,p1,p2,p3) {
document.getElementById('msg').innerHTML += txt + '<br>' + p1 + '<br>' + p2 + '<br>' + p3 + '<br><br>'
}
<div id='msg'></div>
Using Destructuring here is an example where I have 3 variables, and on each I do the multiple operations:
If value is less than 0 then change to 0,
If greater than 255 then change to 1,
Otherwise dived the number by 255 to convert from a range of 0-255 to a range of 0-1.
let a = 52.4, b = -25.1, c = 534.5;
[a, b, c] = [a, b, c].map(n => n < 0 ? 0 : n > 255 ? 1 : n / 255);
console.log(a, b, c); // 0.20549019607843136 0 1

Pass variables by reference in JavaScript

How do I pass variables by reference in JavaScript?
I have three variables that I want to perform several operations to, so I want to put them in a for loop and perform the operations to each one.
Pseudocode:
myArray = new Array(var1, var2, var3);
for (var x = 0; x < myArray.length; x++){
// Do stuff to the array
makePretty(myArray[x]);
}
// Now do stuff to the updated variables
What is the best way to do this?
There is no "pass by reference" available in JavaScript. You can pass an object (which is to say, you can pass-by-value a reference to an object) and then have a function modify the object contents:
function alterObject(obj) {
obj.foo = "goodbye";
}
var myObj = { foo: "hello world" };
alterObject(myObj);
alert(myObj.foo); // "goodbye" instead of "hello world"
You can iterate over the properties of an array with a numeric index and modify each cell of the array, if you want.
var arr = [1, 2, 3];
for (var i = 0; i < arr.length; i++) {
arr[i] = arr[i] + 1;
}
It's important to note that "pass-by-reference" is a very specific term. It does not mean simply that it's possible to pass a reference to a modifiable object. Instead, it means that it's possible to pass a simple variable in such a way as to allow a function to modify that value in the calling context. So:
function swap(a, b) {
var tmp = a;
a = b;
b = tmp; //assign tmp to b
}
var x = 1, y = 2;
swap(x, y);
alert("x is " + x + ", y is " + y); // "x is 1, y is 2"
In a language like C++, it's possible to do that because that language does (sort-of) have pass-by-reference.
edit — this recently (March 2015) blew up on Reddit again over a blog post similar to mine mentioned below, though in this case about Java. It occurred to me while reading the back-and-forth in the Reddit comments that a big part of the confusion stems from the unfortunate collision involving the word "reference". The terminology "pass by reference" and "pass by value" predates the concept of having "objects" to work with in programming languages. It's really not about objects at all; it's about function parameters, and specifically how function parameters are "connected" (or not) to the calling environment. In particular, note that in a true pass-by-reference language — one that does involve objects — one would still have the ability to modify object contents, and it would look pretty much exactly like it does in JavaScript. However, one would also be able to modify the object reference in the calling environment, and that's the key thing that you can't do in JavaScript. A pass-by-reference language would pass not the reference itself, but a reference to the reference.
edit — here is a blog post on the topic. (Note the comment to that post that explains that C++ doesn't really have pass-by-reference. That is true. What C++ does have, however, is the ability to create references to plain variables, either explicitly at the point of function invocation to create a pointer, or implicitly when calling functions whose argument type signature calls for that to be done. Those are the key things JavaScript doesn't support.)
Primitive type variables like strings and numbers are always passed by value.
Arrays and Objects are passed by reference or by value based on these conditions:
if you are setting the value of an object or array it is Pass by Value.
object1 = { prop: "car" };
array1 = [1,2,3];
if you are changing a property value of an object or array then it is Pass by Reference.
object1.prop = "car";
array1[0] = 9;
Code
function passVar(obj1, obj2, num) {
obj1.prop = "laptop"; // will CHANGE original
obj2 = { prop: "computer" }; //will NOT affect original
num = num + 1; // will NOT affect original
}
var object1 = {
prop: "car"
};
var object2 = {
prop: "bike"
};
var number1 = 10;
passVar(object1, object2, number1);
console.log(object1); // output: Object { prop: "laptop" }
console.log(object2); // output: Object { prop: "bike" }
console.log(number1); // ouput: 10
Workaround to pass variable like by reference:
var a = 1;
inc = function(variableName) {
window[variableName] += 1;
};
inc('a');
alert(a); // 2
And yup, actually you can do it without access a global variable:
inc = (function () {
var variableName = 0;
var init = function () {
variableName += 1;
alert(variableName);
}
return init;
})();
inc();
Simple Object
function foo(x) {
// Function with other context
// Modify `x` property, increasing the value
x.value++;
}
// Initialize `ref` as object
var ref = {
// The `value` is inside `ref` variable object
// The initial value is `1`
value: 1
};
// Call function with object value
foo(ref);
// Call function with object value again
foo(ref);
console.log(ref.value); // Prints "3"
Custom Object
Object rvar
/**
* Aux function to create by-references variables
*/
function rvar(name, value, context) {
// If `this` is a `rvar` instance
if (this instanceof rvar) {
// Inside `rvar` context...
// Internal object value
this.value = value;
// Object `name` property
Object.defineProperty(this, 'name', { value: name });
// Object `hasValue` property
Object.defineProperty(this, 'hasValue', {
get: function () {
// If the internal object value is not `undefined`
return this.value !== undefined;
}
});
// Copy value constructor for type-check
if ((value !== undefined) && (value !== null)) {
this.constructor = value.constructor;
}
// To String method
this.toString = function () {
// Convert the internal value to string
return this.value + '';
};
} else {
// Outside `rvar` context...
// Initialice `rvar` object
if (!rvar.refs) {
rvar.refs = {};
}
// Initialize context if it is not defined
if (!context) {
context = this;
}
// Store variable
rvar.refs[name] = new rvar(name, value, context);
// Define variable at context
Object.defineProperty(context, name, {
// Getter
get: function () { return rvar.refs[name]; },
// Setter
set: function (v) { rvar.refs[name].value = v; },
// Can be overrided?
configurable: true
});
// Return object reference
return context[name];
}
}
// Variable Declaration
// Declare `test_ref` variable
rvar('test_ref_1');
// Assign value `5`
test_ref_1 = 5;
// Or
test_ref_1.value = 5;
// Or declare and initialize with `5`:
rvar('test_ref_2', 5);
// ------------------------------
// Test Code
// Test Function
function Fn1(v) { v.value = 100; }
// Test
function test(fn) { console.log(fn.toString()); console.info(fn()); }
// Declare
rvar('test_ref_number');
// First assign
test_ref_number = 5;
test(() => test_ref_number.value === 5);
// Call function with reference
Fn1(test_ref_number);
test(() => test_ref_number.value === 100);
// Increase value
test_ref_number++;
test(() => test_ref_number.value === 101);
// Update value
test_ref_number = test_ref_number - 10;
test(() => test_ref_number.value === 91);
Yet another approach to pass any (local, primitive) variables by reference is by wrapping variable with closure "on the fly" by eval. This also works with "use strict". (Note: be aware that eval is not friendly to JavaScript optimizers, and also missing quotes around variable name may cause unpredictive results)
"use strict"
// Return text that will reference variable by name (by capturing that variable to closure)
function byRef(varName){
return "({get value(){return "+varName+";}, set value(v){"+varName+"=v;}})";
}
// Demo
// Assign argument by reference
function modifyArgument(argRef, multiplier){
argRef.value = argRef.value * multiplier;
}
(function(){
var x = 10;
alert("x before: " + x);
modifyArgument(eval(byRef("x")), 42);
alert("x after: " + x);
})()
Live sample: https://jsfiddle.net/t3k4403w/
There's actually a pretty sollution:
function updateArray(context, targetName, callback) {
context[targetName] = context[targetName].map(callback);
}
var myArray = ['a', 'b', 'c'];
updateArray(this, 'myArray', item => {return '_' + item});
console.log(myArray); //(3) ["_a", "_b", "_c"]
I personally dislike the "pass by reference" functionality offered by various programming languages. Perhaps that's because I am just discovering the concepts of functional programming, but I always get goosebumps when I see functions that cause side effects (like manipulating parameters passed by reference). I personally strongly embrace the "single responsibility" principle.
IMHO, a function should return just one result/value using the return keyword. Instead of modifying a parameter/argument, I would just return the modified parameter/argument value and leave any desired reassignments up to the calling code.
But sometimes (hopefully very rarely), it is necessary to return two or more result values from the same function. In that case, I would opt to include all those resulting values in a single structure or object. Again, processing any reassignments should be up to the calling code.
Example:
Suppose passing parameters would be supported by using a special keyword like 'ref' in the argument list. My code might look something like this:
//The Function
function doSomething(ref value) {
value = "Bar";
}
//The Calling Code
var value = "Foo";
doSomething(value);
console.log(value); //Bar
Instead, I would actually prefer to do something like this:
//The Function
function doSomething(value) {
value = "Bar";
return value;
}
//The Calling Code:
var value = "Foo";
value = doSomething(value); //Reassignment
console.log(value); //Bar
When I would need to write a function that returns multiple values, I would not use parameters passed by reference either. So I would avoid code like this:
//The Function
function doSomething(ref value) {
value = "Bar";
//Do other work
var otherValue = "Something else";
return otherValue;
}
//The Calling Code
var value = "Foo";
var otherValue = doSomething(value);
console.log(value); //Bar
console.log(otherValue); //Something else
Instead, I would actually prefer to return both new values inside an object, like this:
//The Function
function doSomething(value) {
value = "Bar";
//Do more work
var otherValue = "Something else";
return {
value: value,
otherValue: otherValue
};
}
//The Calling Code:
var value = "Foo";
var result = doSomething(value);
value = result.value; //Reassignment
console.log(value); //Bar
console.log(result.otherValue);
These code examples are quite simplified, but it roughly demonstrates how I personally would handle such stuff. It helps me to keep various responsibilities in the correct place.
Happy coding. :)
I've been playing around with syntax to do this sort of thing, but it requires some helpers that are a little unusual. It starts with not using 'var' at all, but a simple 'DECLARE' helper that creates a local variable and defines a scope for it via an anonymous callback. By controlling how variables are declared, we can choose to wrap them into objects so that they can always be passed by reference, essentially. This is similar to one of the Eduardo Cuomo's answer above, but the solution below does not require using strings as variable identifiers. Here's some minimal code to show the concept.
function Wrapper(val){
this.VAL = val;
}
Wrapper.prototype.toString = function(){
return this.VAL.toString();
}
function DECLARE(val, callback){
var valWrapped = new Wrapper(val);
callback(valWrapped);
}
function INC(ref){
if(ref && ref.hasOwnProperty('VAL')){
ref.VAL++;
}
else{
ref++;//or maybe throw here instead?
}
return ref;
}
DECLARE(5, function(five){ //consider this line the same as 'let five = 5'
console.log("five is now " + five);
INC(five); // increment
console.log("five is incremented to " + five);
});
Actually it is really easy. The problem is understanding that once passing classic arguments, you are scoped into another, read-only zone.
The solution is to pass the arguments using JavaScript's object-oriented design. It is the same as putting the arguments in a global/scoped variable, but better...
function action(){
/* Process this.arg, modification allowed */
}
action.arg = [["empty-array"], "some string", 0x100, "last argument"];
action();
You can also promise stuff up to enjoy the well-known chain:
Here is the whole thing, with promise-like structure
function action(){
/* Process this.arg, modification allowed */
this.arg = ["a", "b"];
}
action.setArg = function(){this.arg = arguments; return this;}
action.setArg(["empty-array"], "some string", 0x100, "last argument")()
Or better yet...
action.setArg(["empty-array"],"some string",0x100,"last argument").call()
JavaScript can modify array items inside a function (it is passed as a reference to the object/array).
function makeAllPretty(items) {
for (var x = 0; x < myArray.length; x++){
// Do stuff to the array
items[x] = makePretty(items[x]);
}
}
myArray = new Array(var1, var2, var3);
makeAllPretty(myArray);
Here's another example:
function inc(items) {
for (let i=0; i < items.length; i++) {
items[i]++;
}
}
let values = [1,2,3];
inc(values);
console.log(values);
// Prints [2,3,4]
Putting aside the pass-by-reference discussion, those still looking for a solution to the stated question could use:
const myArray = new Array(var1, var2, var3);
myArray.forEach(var => var = makePretty(var));
As we don't have javascript pass by reference functionality, the only way to do this is to make the function return the value and let the caller assign it:
So
"makePretty(myArray[x]);"
should be
"myArray[x] = makePretty(myArray[x]);"
This is in case you need assignment inside the function, if only mutation is necessary, then passing the object and mutating it should be enough
I know exactly what you mean. The same thing in Swift will be no problem. The bottom line is use let, not var.
The fact that primitives are passed by value, but the fact that the value of var i at the point of iteration is not copied into the anonymous function is quite surprising to say the least.
for (let i = 0; i < boxArray.length; i++) {
boxArray[i].onclick = function() { console.log(i) }; // Correctly prints the index
}
If you want to pass variables by reference, a better way to do that is by passing your arguments in an object and then start changing the value by using window:
window["varName"] = value;
Example:
// Variables with first values
var x = 1, b = 0, f = 15;
function asByReference (
argumentHasVars = {}, // Passing variables in object
newValues = []) // Pass new values in array
{
let VarsNames = [];
// Getting variables names one by one
for(let name in argumentHasVars)
VarsNames.push(name);
// Accessing variables by using window one by one
for(let i = 0; i < VarsNames.length; i += 1)
window[VarsNames[i]] = newValues[i]; // Set new value
}
console.log(x, b, f); // Output with first values
asByReference({x, b, f}, [5, 5, 5]); // Passing as by reference
console.log(x, b, f); // Output after changing values
I like to solve the lack of by reference in JavaScript like this example shows.
The essence of this is that you don't try to create a by reference. You instead use the return functionality and make it able to return multiple values. So there isn't any need to insert your values in arrays or objects.
var x = "First";
var y = "Second";
var z = "Third";
log('Before call:',x,y,z);
with (myFunc(x, y, z)) {x = a; y = b; z = c;} // <-- Way to call it
log('After call :',x,y,z);
function myFunc(a, b, c) {
a = "Changed first parameter";
b = "Changed second parameter";
c = "Changed third parameter";
return {a:a, b:b, c:c}; // <-- Return multiple values
}
function log(txt,p1,p2,p3) {
document.getElementById('msg').innerHTML += txt + '<br>' + p1 + '<br>' + p2 + '<br>' + p3 + '<br><br>'
}
<div id='msg'></div>
Using Destructuring here is an example where I have 3 variables, and on each I do the multiple operations:
If value is less than 0 then change to 0,
If greater than 255 then change to 1,
Otherwise dived the number by 255 to convert from a range of 0-255 to a range of 0-1.
let a = 52.4, b = -25.1, c = 534.5;
[a, b, c] = [a, b, c].map(n => n < 0 ? 0 : n > 255 ? 1 : n / 255);
console.log(a, b, c); // 0.20549019607843136 0 1

Categories