javascript constructor with optional parameters - javascript

I am learning Javascript now and coming from the background of Java. In Java we have overloaded constructors wherein, at compile time, the compiler will decide which version of constructor to be called.
In case of Javascript, we can have only one constructor. In this case, if the constructor has 3 arguments, how to pass only the third parameter.
Ex:
class Addition {
constructor(a,b,c){
console.log(a+B+c);
}
}
Addition obj = new Addition(null, 40, null);
//or
Addition onj2 = new Addition(undefined, undefined, 45);
Is there a better way to do this in Javascript?

You may use EcmaScript's parameter destructuring with default values to achieve that. Additionally, you need to use const (or let, or var) keyword to create variables.
class Addition {
constructor({a = 0, b = 0, c = 0}) {
console.log(a + b + c);
}
}
const obj = new Addition({a: null, b: 40, c: null});
const onj2 = new Addition({c: 45});

There is no possibility of overloading in JS, but you can work with Object destructuring. They can even be complex and refer to other default parameters, like:
function rangeMessage({from=1, to=from+1, message=(counter) => `Hello ${counter}`}={}) {
for(from; from <= to; from++) {
console.log(message(from));
}
}
rangeMessage({from: 10, to: 20});
rangeMessage({to: 10, message:(counter) => `Bye ${counter}`})
rangeMessage()
function sumABC({a=null, b=null, c=null}={}) {
let result = 0;
if(a) result += a;
if(b) result += b;
if(c) result += c;
return result;
}
console.log(sumABC());
console.log(sumABC({a:10}));
console.log(sumABC({b:5}));
console.log(sumABC({b: 10, c: 5}));
The {} = {} part does the same as the other destructuring assignments - if no object was passed in, assume an empty object (which is then filled by the object destructuring statements from the left side).

I hope this solved you question :D
class Addition {
constructor(a=null,b=null,c=null){
console.log(a+b+c);
}
}
var obj = new Addition(null, 40, null);
var onj2 = new Addition(undefined, undefined, 45);

Related

How to get access to function args [duplicate]

In PHP there is func_num_args and func_get_args, is there something similar for JavaScript?
For modern Javascript or Typescript:
class Foo {
reallyCoolMethodISwear(...args) { return args.length; }
}
function reallyCoolFunction(i, ...args) { return args[i]; }
const allHailTheLambda = (...args) => {
return args.constructor == Array;
};
const x = new Foo().reallyCoolMethodISwear(0, 1, 2, 3, 4);
const y = reallyCoolFunction(3, 0, 1, 2, 3, 4, 5, 6);
const z = allHailTheLambda(43110, "world");
console.log(x, y, z); // 5 3 true
For ancient Javascript:
Use arguments. You can access it like an array. Use arguments.length for the number of arguments.
The arguments is an array-like object (not an actual array). Example function...
function testArguments () // <-- notice no arguments specified
{
console.log(arguments); // outputs the arguments to the console
var htmlOutput = "";
for (var i=0; i < arguments.length; i++) {
htmlOutput += '<li>' + arguments[i] + '</li>';
}
document.write('<ul>' + htmlOutput + '</ul>');
}
Try it out...
testArguments("This", "is", "a", "test"); // outputs ["This","is","a","test"]
testArguments(1,2,3,4,5,6,7,8,9); // outputs [1,2,3,4,5,6,7,8,9]
The full details: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments
ES6 allows a construct where a function argument is specified with a "..." notation such as
function testArgs (...args) {
// Where you can test picking the first element
console.log(args[0]);
}
The arguments object is where the functions arguments are stored.
The arguments object acts and looks like an array, it basically is, it just doesn't have the methods that arrays do, for example:
Array.forEach(callback[, thisArg]);
Array.map(callback[, thisArg])
Array.filter(callback[, thisArg]);
Array.slice(begin[, end])
Array.indexOf(searchElement[, fromIndex])
I think the best way to convert a arguments object to a real Array is like so:
argumentsArray = [].slice.apply(arguments);
That will make it an array;
reusable:
function ArgumentsToArray(args) {
return [].slice.apply(args);
}
(function() {
args = ArgumentsToArray(arguments);
args.forEach(function(value) {
console.log('value ===', value);
});
})('name', 1, {}, 'two', 3)
result:
> value === name
> value === 1
> value === Object {}
> value === two
> value === 3
You can also convert it to an array if you prefer. If Array generics are available:
var args = Array.slice(arguments)
Otherwise:
var args = Array.prototype.slice.call(arguments);
from Mozilla MDN:
You should not slice on arguments because it prevents optimizations in
JavaScript engines (V8 for example).
As many other pointed out, arguments contains all the arguments passed to a function.
If you want to call another function with the same args, use apply
Example:
var is_debug = true;
var debug = function() {
if (is_debug) {
console.log.apply(console, arguments);
}
}
debug("message", "another argument")
Similar answer to Gunnar, with more complete example:
You can even transparently return the whole thing:
function dumpArguments(...args) {
for (var i = 0; i < args.length; i++)
console.log(args[i]);
return args;
}
dumpArguments("foo", "bar", true, 42, ["yes", "no"], { 'banana': true });
Output:
foo
bar
true
42
["yes","no"]
{"banana":true}
https://codepen.io/fnocke/pen/mmoxOr?editors=0010
Yes if you have no idea that how many arguments are possible at the time of function declaration then you can declare the function with no parameters and can access all variables by arguments array which are passed at the time of function calling.
In ES6 you can do something like this:
function foo(...args)
{
let [a,b,...c] = args;
console.log(a,b,c);
}
foo(1, null,"x",true, undefined);
Hope this helps:
function x(...args) {
console.log( {...[...args] } );
}
x({a:1,b:2}, 'test');
Output:
{ '0': { a: 1, b: 2 }, '1': 'test' }
Hope this could be the helpful code:
function lazyLoadIcons(){
for(let i = 0; i < arguments.length; i++) {
var elements = document.querySelectorAll(arguments[i]);
elements.forEach(function(item){
item.classList.add('loaded');
});
}
}
lazyLoadIcons('.simple-2col', '.ftr-blue-ad', '.btm-numb');
~ Rahul Daksh
In ES6, use Array.from:
function foo()
{
foo.bar = Array.from(arguments);
foo.baz = foo.bar.join();
}
foo(1,2,3,4,5,6,7);
foo.bar // Array [1, 2, 3, 4, 5, 6, 7]
foo.baz // "1,2,3,4,5,6,7"
For non-ES6 code, use JSON.stringify and JSON.parse:
function foo()
{
foo.bar = JSON.stringify(arguments);
foo.baz = JSON.parse(foo.bar);
}
/* Atomic Data */
foo(1,2,3,4,5,6,7);
foo.bar // "{"0":1,"1":2,"2":3,"3":4,"4":5,"5":6,"6":7}"
foo.baz // [object Object]
/* Structured Data */
foo({1:2},[3,4],/5,6/,Date())
foo.bar //"{"0":{"1":2},"1":[3,4],"2":{},"3":"Tue Dec 17 2013 16:25:44 GMT-0800 (Pacific Standard Time)"}"
foo.baz // [object Object]
If preservation is needed instead of stringification, use the internal structured cloning algorithm.
If DOM nodes are passed, use XMLSerializer as in an unrelated question.
with (new XMLSerializer()) {serializeToString(document.documentElement) }
If running as a bookmarklet, you may need to wrap the each structured data argument in an Error constructor for JSON.stringify to work properly.
References
Structure Clone CommonJS Module
JS Object Clone
MDN: Array.from()

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

Why the strange duplication in Javascript instance objects?

While using Javascript for some fun, I ran into a morass of difficulties surrounding classes and objects. I thought I got that it is not Java, nor c++. Finally, I took my problems into a smallish example to study this.
Running the example produces output:
>>>>>> keys aprop,bprep,cprep,dprop,bprop,cprop.
I expected output:
>>>>>> keys aprop,bprep,cprep,dprop.
If duplication, why are not aprop and dprop also duplicated? I had thought that by using getOwnPropertyNames I prevented prototype keys. Is there a way to fix this short of comparing each key to eliminate duplicates?
<script>
var objList = [];
class TestObj {
constructor(aprop, bprop, cprop) {
this.aprop = aprop;
this.bprep = bprop;
this.cprep = cprop;
this.dprop = 0;
}
getAprop() { return aprop; }
getBprop() { return bprop; }
getCprop() { return cprop; }
getDprop() { return dprop; }
setAprop(arg) { aprop = arg; }
setBprop(arg) { bprop = arg; }
setCprop(arg) { cprop = arg; }
setDprop(arg) { dprop = arg; }
}
function create() {
putList();
var t1 = objList[1];
alert("fromlist "+t1);
var keys = Object.getOwnPropertyNames(t1);
console.log(">>>>>> keys "+keys);
}
function putList() {
onlist(1, "one" [1]);
onlist(2, "two", [2, 2]);
onlist(3, "three", [3, 3, 3]);
}
function onlist(a, b, c) {
var item = new TestObj();
item.aprop = a;
item.bprop = b;
item.cprop = c;
objList.push(item);
}
create();
</script>
I hope this is actually your question. Anyway, here goes:
First, a minimal example:
function Foo() {
this.bar = 0;
}
Object.keys(new Foo)
The result of this expression is ["bar"] instead of [] because setting properties in a constructor is no different from setting them anywhere else. They’re not on the prototype just by virtue of being in a constructor. This would work:
function Foo() {}
Foo.prototype.bar = 0;
Object.keys(new Foo)
Now bar is on the prototype, and Object.keys, which only lists own property names, returns [] for a Foo instance. This isn’t usually what you want, though; assigning to bar on an instance will still create a new own property, and if it were mutable, then mutating it would affect all instances of Foo.
Is there a way to fix this short of comparing each key to eliminate duplicates?
Don’t loop over properties in the first place.
… and on the off-chance you really mean “duplicates”, note that you spelled them differently: “bprep” and “cprep” vs. “bprop” and “cprop”.

Number Objects Passed Into Functions by Reference

I was reading somewhere that when we pass an object into a function "...JavaScript always uses the Object by reference when it passes as argument..." What I think this implies is (correct me if I'm wrong) is that if the function was to modify the object in some way, it would change the original defined object. I tried illustrating this with some code and it does do what I think it does but when I try the example in the blog post with a Number obj, it doesn't change the original value in that object. Please see my jsbin: https://jsbin.com/wociro/edit?js,console,output
console.clear();
/**myobject Object**/
function myobject() {
this.value = 5;
}
var o = new myobject();
console.log("Original value of o: " + o.value); // o.value = 5
function objectchanger(fnc) {
fnc.value = 6;
}
objectchanger(o);
console.log("New value of o: " + o.value); // o.value is now equal to 6
/*Number Object*/
var num2 = new Number(2);
console.log("Original value of num2: " + num2);
function numberChanger(fnc) {
return fnc + 1;
}
console.log("num2 after running numberChanger: " + numberChanger(num2));
console.log("New value of num2: " + num2); //looks the same
Am I missing something?
Number objects are still objects. So their value is a reference, and if a function alters a property of an object passed as an argument, that object will be affected outside the function.
function changer(obj) {
obj.foo = 'bar';
}
var num = new Number(123);
console.log(num.foo); // undefined
changer(num);
console.log(num.foo); // 'bar'
However, the value wrapped inside the number object is not stored as a property. It's stored as a [[NumberData]] internal slot. ECMAScript provides no way to alter that slot, so you can't change the number.
Your attempt of fnc+1 unwraps the number object to get its [[NumberData]], and adds 1 to that. But the result is just discarded, it's not stored back in the [[NumberData]] slot of fnc.
If you want to be able to achieve something analogous to changing the [[NumberData]], you can
function MyNumber(num) {
this.__number__ = +num;
}
MyNumber.prototype = Object.create(Number.prototype);
Object.getOwnPropertyNames(Number.prototype).forEach(function(prop) {
var desc = Object.getOwnPropertyDescriptor(Number.prototype, prop);
if(desc && desc.value && typeof desc.value == 'function') {
var native = desc.value;
desc.value = function() {
return native.apply(this.__number__, arguments);
};
Object.defineProperty(MyNumber.prototype, prop, desc);
}
});
var num = new MyNumber(123);
console.log(+num, num+'', num.toFixed(2)); // 123, "123", "123.00"
num.__number__ = 456;
console.log(+num, num+'', num.toFixed(2)); // 456, "456", "456.00"
I actually had a lot issues when I started getting into the object side of JavaScript myself. Best way I can explain is by these examples.
Objects link.
var obj = {a: 5};
var b = obj.a;
b = 2;
// obj.a: 2
// b: 2
This will link to the object value I believe. So if you change b it will also change obj.a.
HTML DOM object link with odd behavior
var x = document.getElementById("some_div_id");
x.innerHTML = "example"; // this works
var x = document.getElementById("some_div_id").innerHTML;
x = "example"; // this doesn't, it thinks that it's document.getElementById("some_div_id");
Took me time to figure what was wrong when I first did the second DOM method.
Variables are not linked but copied.
var a = 5;
var b = a;
b = 2;
// a: 5
// b: 2
As you can see, this doesn't link the value but creates a new one based from it.
Deep copying from objects trick.
function deepCopy(objValue) {
return JSON.parse(JSON.stringify(objValue));
}
var obj = {a: 5};
var b = deepCopy(obj.a);
b = 2;
// obj.a: 5
// b: 2
This was a trick given to me some time back when I had issues wanting a object value being stored in a variable and edited but without it being linked to the object value. After a while I found I never needed it after improving my coding skills.
Also last note. I read somewhere in clean JavaScript coding that you shouldn't need to use the new object method unless it's a Date() object or or simulated class, or you may run into typeof and value check issues with ===.
Can't be certain if this is error free but hope this helps explains better.
In Javascript, objects refer to an array, indicated by [] or an object {}. You can verify the type of the variable by using typeof. These are passed by reference.
typeof [2, 5, 3] //object
typeof { a: 10} // object
If you pass the object literal to a function and modify the value of the property 'a', it would result in the value being modified.

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