Related
I used C++ before and I realized that pointers were very helpful. Is there anything in javascript that acts like a pointer? Does javascript have pointers? I like to use pointers when I want to use something like:
var a = 1;
var b = "a";
document.getElementById(/* value pointed by b */).innerHTML="Pointers";
I know that this is an extremely simple example and I could just use a, but there are several more complex examples where I would find pointers very useful. Any ideas?
No, JS doesn't have pointers.
Objects are passed around by passing a copy of a reference. The programmer cannot access any C-like "value" representing the address of an object.
Within a function, one may change the contents of a passed object via that reference, but you cannot modify the reference that the caller had because your reference is only a copy:
var foo = {'bar': 1};
function tryToMungeReference(obj) {
obj = {'bar': 2}; // won't change caller's object
}
function mungeContents(obj) {
obj.bar = 2; // changes _contents_ of caller's object
}
tryToMungeReference(foo);
foo.bar === 1; // true - foo still references original object
mungeContents(foo);
foo.bar === 2; // true - object referenced by foo has been modified
You bet there are pointers in JavaScript; objects are pointers.
//this will make object1 point to the memory location that object2 is pointing at
object1 = object2;
//this will make object2 point to the memory location that object1 is pointing at
function myfunc(object2){}
myfunc(object1);
If a memory location is no longer pointed at, the data there will be lost.
Unlike in C, you can't see the actual address of the pointer nor the actual value of the pointer, you can only dereference it (get the value at the address it points to.)
I just did a bizarre thing that works out, too.
Instead of passing a pointer, pass a function that fills its argument into the target variable.
var myTarget;
class dial{
constructor(target){
this.target = target;
this.target(99);
}
}
var myDial = new dial((v)=>{myTarget = v;});
This may look a little wicked, but works just fine. In this example I created a generic dial, which can be assigned any target in form of this little function "(v)=>{target = v}". No idea how well it would do in terms of performance, but it acts beautifully.
due to the nature of JS that passes objects by value (if referenced object is changed completely) or by reference (if field of the referenced object is changed) it is not possible to completely replace a referenced object.
However, let's use what is available: replacing single fields of referenced objects. By doing that, the following function allows to achieve what you are asking for:
function replaceReferencedObj(refObj, newObj) {
let keysR = Object.keys(refObj);
let keysN = Object.keys(newObj);
for (let i = 0; i < keysR.length; i++) {
delete refObj[keysR[i]];
}
for (let i = 0; i < keysN.length; i++) {
refObj[keysN[i]] = newObj[keysN[i]];
}
}
For the example given by user3015682 you would use this function as following:
replaceReferencedObj(foo, {'bar': 2})
Assigning by reference and arrays.
let pizza = [4,4,4];
let kebab = pizza; // both variables are references to shared value
kebab.push(4);
console.log(kebab); //[4,4,4,4]
console.log(pizza); //[4,4,4,4]
Since original value isn't modified no new reference is created.
kebab = [6,6,6,6]; // value is reassigned
console.log(kebab); //[6,6,6,6]
console.log(pizza); //[4,4,4,4]
When the compound value in a variable is reassigned, a new reference is created.
Technically JS doesn't have pointers, but I discovered a way to imitate their behavior ;)
var car = {
make: 'Tesla',
nav: {
lat: undefined,
lng: undefined
}
};
var coords: {
center: {
get lat() { return car.nav.lat; }, // pointer LOL
get lng() { return car.nav.lng; } // pointer LOL
}
};
car.nav.lat = 555;
car.nav.lng = 777;
console.log('*** coords: ', coords.center.lat); // 555
console.log('*** coords: ', coords.center.lng); // 777
I am looking for a way to modify an object that was defined by a literal without passing it into another function.
example:
let o = {a:1,b:2}
console.log(o.a===3)
i thought when i define an object using a literal the the Object constructor would be called, so i did override Object.prototype.constructor but it only gets called when i do new Object({a:1,b:2})
question in simpler terms can anyone make a=3 without passing the object o to a function or a proxy or using o.a=3 or with keyword, where o is defined using an object literal?
Just do o.a=3; and console log o:
let o = {a:1,b:2};
o.a=3;
console.log(o);
Currently you are doing o.a===3 which will return Boolean value instead of overwriting the value of property a.
You also cannot do o.a=3 inside console.log() because o.a=3 will return the assigned value which is 3 but it will still change the property a of o to 3.
let o = {
a: 1,
b: 2
};
//won't print o but changes o.a to 3
console.log(o.a = 3);
It's simply not possible.
There is no constructor of an object literal.
You can create objects in different ways:
via an object literal or
via a constructor function or
via Object.create
Also, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer
question in simpler terms can anyone make a=3 without passing the object o to a function or a proxy?
o.a = 3;
I am looking for a way to modify an object that was defined by a literal without passing it into another function.
Thats impossible, cause if it would be possible you could break every piece of javascript. And that would be terrible.
Oh wait, this is JS...
with({ get o() { return { a: 3 }; }, set o(v) {} }) {
o = {a:1,b:2};
console.log(o.a===3) // true
}
What you want to achieve could be done if o.a holds a reference to the variable a - which unfortunately only works the way you'd like for variables that are passed by reference. Primitive types like String, Number and Boolean though, are passed by value.
Check the examples below:
var a = 1;
var o = { a: a };
a = 2;
console.log(o.a, a);
It also doesn't help to use an Object constructor like new Number() because that does return a reference to an object (which is passed by reference as you'd need), but assigning a new value to it reading the value still returns a primitive (which is, again, passed by value):
var a = new Number(1);
var o = { a: a.valueOf() };
a = Number(2);
console.log(o.a, a);
If you pass something that is naturally passed by reference, your expectation is fulfilled:
var a = [ 1 ]
var o = { a: a }
a[0] = 2
console.log(o.a[0])
I used C++ before and I realized that pointers were very helpful. Is there anything in javascript that acts like a pointer? Does javascript have pointers? I like to use pointers when I want to use something like:
var a = 1;
var b = "a";
document.getElementById(/* value pointed by b */).innerHTML="Pointers";
I know that this is an extremely simple example and I could just use a, but there are several more complex examples where I would find pointers very useful. Any ideas?
No, JS doesn't have pointers.
Objects are passed around by passing a copy of a reference. The programmer cannot access any C-like "value" representing the address of an object.
Within a function, one may change the contents of a passed object via that reference, but you cannot modify the reference that the caller had because your reference is only a copy:
var foo = {'bar': 1};
function tryToMungeReference(obj) {
obj = {'bar': 2}; // won't change caller's object
}
function mungeContents(obj) {
obj.bar = 2; // changes _contents_ of caller's object
}
tryToMungeReference(foo);
foo.bar === 1; // true - foo still references original object
mungeContents(foo);
foo.bar === 2; // true - object referenced by foo has been modified
You bet there are pointers in JavaScript; objects are pointers.
//this will make object1 point to the memory location that object2 is pointing at
object1 = object2;
//this will make object2 point to the memory location that object1 is pointing at
function myfunc(object2){}
myfunc(object1);
If a memory location is no longer pointed at, the data there will be lost.
Unlike in C, you can't see the actual address of the pointer nor the actual value of the pointer, you can only dereference it (get the value at the address it points to.)
I just did a bizarre thing that works out, too.
Instead of passing a pointer, pass a function that fills its argument into the target variable.
var myTarget;
class dial{
constructor(target){
this.target = target;
this.target(99);
}
}
var myDial = new dial((v)=>{myTarget = v;});
This may look a little wicked, but works just fine. In this example I created a generic dial, which can be assigned any target in form of this little function "(v)=>{target = v}". No idea how well it would do in terms of performance, but it acts beautifully.
due to the nature of JS that passes objects by value (if referenced object is changed completely) or by reference (if field of the referenced object is changed) it is not possible to completely replace a referenced object.
However, let's use what is available: replacing single fields of referenced objects. By doing that, the following function allows to achieve what you are asking for:
function replaceReferencedObj(refObj, newObj) {
let keysR = Object.keys(refObj);
let keysN = Object.keys(newObj);
for (let i = 0; i < keysR.length; i++) {
delete refObj[keysR[i]];
}
for (let i = 0; i < keysN.length; i++) {
refObj[keysN[i]] = newObj[keysN[i]];
}
}
For the example given by user3015682 you would use this function as following:
replaceReferencedObj(foo, {'bar': 2})
Assigning by reference and arrays.
let pizza = [4,4,4];
let kebab = pizza; // both variables are references to shared value
kebab.push(4);
console.log(kebab); //[4,4,4,4]
console.log(pizza); //[4,4,4,4]
Since original value isn't modified no new reference is created.
kebab = [6,6,6,6]; // value is reassigned
console.log(kebab); //[6,6,6,6]
console.log(pizza); //[4,4,4,4]
When the compound value in a variable is reassigned, a new reference is created.
Technically JS doesn't have pointers, but I discovered a way to imitate their behavior ;)
var car = {
make: 'Tesla',
nav: {
lat: undefined,
lng: undefined
}
};
var coords: {
center: {
get lat() { return car.nav.lat; }, // pointer LOL
get lng() { return car.nav.lng; } // pointer LOL
}
};
car.nav.lat = 555;
car.nav.lng = 777;
console.log('*** coords: ', coords.center.lat); // 555
console.log('*** coords: ', coords.center.lng); // 777
Consider the following:
var obj1 = {"value":"one"};
var obj2 = obj1;
console.log(obj2.value+"\n"); // prints "one"
obj1 = {"value":"two"};
console.log(obj2.value+"\n"); // still prints "one"
I understand the reason for this, in the first two lines, obj1 and obj2 are references which both point to the same object, {"value":"one"}, somewhere in memory. When obj1 is assigned to a different object, {"value":"two"}, obj2 is still pointing to the same object {"value":"one"} in memory.
What I am looking for is a way to coerce the {"value":"one"} object in memory to "redirect" its callers to the {"value":"two"} object. In other words, I am looking for a way to manipulate the {"value":"one"} object so that the obj2 variable would ultimately point to the {"value":"two"} object, without reassigning the obj2 variable:
var obj1 = {"value":"one"};
var obj2 = obj1;
console.log(obj2.value+"\n"); // prints "one"
// ...some code to manipulate the `{"value":"one"}` object in memory
// so that *any* references which originally pointed to the
// `{"value":"one"}` object now point to the `{"value":"two"}`
// object, like a sort of "redirection". This would be done
// without ever explicitly reassigning the references.
console.log(obj2.value+"\n"); // now prints "two"
Is there a way to accomplish this?
The actual application involves some pretty complex Mozilla code which would encumber this thread to try and explain, so I am asking this as a general theory question.
EDIT: CONCLUSION:
"No" is the most correct answer to the actual question, torazaburo's comment below states this well. However I felt that Patrick's answer, using a proxy, comes the closest to accomplishing this, so I accepted his answer. I will add that while proxies are very powerful tools, they are not the same as the actual target object, and there are some limitations.
Check out proxies. You could use the get and set to dynamically reference a base object of your choosing, exposing proxies as the free-floating references you want to implicitly update. Here's an example:
function Proxyable(target) {
this.target = target;
this.proxy = new Proxy(this, Proxyable.handler);
}
Proxyable.prototype.getReference = function () {
return this.proxy;
};
Proxyable.prototype.setReference = function (target) {
this.target = target;
};
Proxyable.handler = {
get: function (proxyable, property) {
return proxyable.target[property];
},
set: function (proxyable, property, value) {
return proxyable.target[property] = value;
}
};
// original object
var original = { value: ['one'] };
// have to create a namespace unfortunately
var nsp = new Proxyable(original);
// reference the ref value of the namespace
var ref1 = nsp.getReference();
var ref2 = nsp.getReference();
// same references (not just values)
console.log(ref1.value === original.value);
console.log(ref2.value === original.value);
// hot-load a replacement object over the original
var replacement = { value: ['two'] };
// into the namespace
nsp.setReference(replacement);
// old references broken
console.log(ref1.value !== original.value);
console.log(ref2.value !== original.value);
// new references in place
console.log(ref1.value === replacement.value);
console.log(ref2.value === replacement.value);
I think this answer will guide you in the best way to handle this behavior. It's not possible to simply redirect an object to another object, but you can simply modify its values so that it matches the object you're trying to change.
You could also define a global object:
var objs = {
1: {value: 'test'}
2: {value: 'test2'}
};
And from there, pass around an object with the value of the key you're trying to mock. Simply change the key, and then refer to the new element.
An example:
var obj = {key: 1};
console.log(objs[obj.key]);
//Outputs: {value: 'test'}
obj.key = 2;
console.log(objs[obj.key]);
//Outputs: {value: 'test2'}
There's no way directly to do what you want. For the very reason you've stated in your question - that's just how variables and values work in javascript.
However, your very own words in your question hints at a way to achieve something that may work. But depending on the code you're dealing with it may not be what you want.
You can simply wrap the object in another reference. So that changing the content of the reference changes the object pointed to by all variables sharing the reference. You may use either of the two reference containers available: objects or arrays:
// This works:
var obj1 = [{value:'one'}];
var obj2 = obj1;
var obj1[0] = {value:'two'};
console.log(obj1[0]); // prints {"value":"two"}
console.log(obj2[0]); // prints {"value":"two"}
Alternatively:
// This also works:
var obj1 = {obj:{value:'one'}};
var obj2 = obj1;
var obj1.obj = {value:'two'};
console.log(obj1.obj); // prints {"value":"two"}
console.log(obj2.obj); // prints {"value":"two"}
This question already has answers here:
Is JavaScript a pass-by-reference or pass-by-value language?
(33 answers)
Closed 3 years ago.
Does JavaScript pass by references or pass by values?
Here is an example from JavaScript: The Good Parts. I am very confused about the my parameter for the rectangle function. It is actually undefined, and redefined inside the function. There are no original reference. If I remove it from the function parameter, the inside area function is not able to access it.
Is it a closure? But no function is returned.
var shape = function (config) {
var that = {};
that.name = config.name || "";
that.area = function () {
return 0;
};
return that;
};
var rectangle = function (config, my) {
my = my || {};
my.l = config.length || 1;
my.w = config.width || 1;
var that = shape(config);
that.area = function () {
return my.l * my.w;
};
return that;
};
myShape = shape({
name: "Unhnown"
});
myRec = rectangle({
name: "Rectangle",
length: 4,
width: 6
});
console.log(myShape.name + " area is " + myShape.area() + " " + myRec.name + " area is " + myRec.area());
Primitives are passed by value, and Objects are passed by "copy of a reference".
Specifically, when you pass an object (or array) you are (invisibly) passing a reference to that object, and it is possible to modify the contents of that object, but if you attempt to overwrite the reference it will not affect the copy of the reference held by the caller - i.e. the reference itself is passed by value:
function replace(ref) {
ref = {}; // this code does _not_ affect the object passed
}
function update(ref) {
ref.key = 'newvalue'; // this code _does_ affect the _contents_ of the object
}
var a = { key: 'value' };
replace(a); // a still has its original value - it's unmodfied
update(a); // the _contents_ of 'a' are changed
Think of it like this:
Whenever you create an object in ECMAscript, this object is formed in a mystique ECMAscript universal place where no man will ever be able to get. All you get back is a reference to that object in this mystique place.
var obj = { };
Even obj is only a reference to the object (which is located in that special wonderful place) and hence, you can only pass this reference around. Effectively, any piece of code which accesses obj will modify the object which is far, far away.
My two cents.... It's irrelevant whether JavaScript passes parameters by reference or value. What really matters is assignment vs. mutation.
I wrote a longer, more detailed explanation in this link.
When you pass anything (whether that be an object or a primitive), all JavaScript does is assign a new variable while inside the function... just like using the equal sign (=).
How that parameter behaves inside the function is exactly the same as it would behave if you just assigned a new variable using the equal sign... Take these simple examples.
var myString = 'Test string 1';
// Assignment - A link to the same place as myString
var sameString = myString;
// If I change sameString, it will not modify myString,
// it just re-assigns it to a whole new string
sameString = 'New string';
console.log(myString); // Logs 'Test string 1';
console.log(sameString); // Logs 'New string';
If I were to pass myString as a parameter to a function, it behaves as if I simply assigned it to a new variable. Now, let's do the same thing, but with a function instead of a simple assignment
function myFunc(sameString) {
// Reassignment... Again, it will not modify myString
sameString = 'New string';
}
var myString = 'Test string 1';
// This behaves the same as if we said sameString = myString
myFunc(myString);
console.log(myString); // Again, logs 'Test string 1';
The only reason that you can modify objects when you pass them to a function is because you are not reassigning... Instead, objects can be changed or mutated.... Again, it works the same way.
var myObject = { name: 'Joe'; }
// Assignment - We simply link to the same object
var sameObject = myObject;
// This time, we can mutate it. So a change to myObject affects sameObject and visa versa
myObject.name = 'Jack';
console.log(sameObject.name); // Logs 'Jack'
sameObject.name = 'Jill';
console.log(myObject.name); // Logs 'Jill'
// If we re-assign it, the link is lost
sameObject = { name: 'Howard' };
console.log(myObject.name); // Logs 'Jill'
If I were to pass myObject as a parameter to a function, it behaves as if I simply assigned it to a new variable. Again, the same thing with the exact same behavior but with a function.
function myFunc(sameObject) {
// We mutate the object, so the myObject gets the change too... just like before.
sameObject.name = 'Jill';
// But, if we re-assign it, the link is lost
sameObject = {
name: 'Howard'
};
}
var myObject = {
name: 'Joe'
};
// This behaves the same as if we said sameObject = myObject;
myFunc(myObject);
console.log(myObject.name); // Logs 'Jill'
Every time you pass a variable to a function, you are "assigning" to whatever the name of the parameter is, just like if you used the equal = sign.
Always remember that the equals sign = means assignment.
And passing a parameter to a function also means assignment.
They are the same and the two variables are connected in exactly the same way.
The only time that modifying a variable affects a different variable is when the underlying object is mutated.
There is no point in making a distinction between objects and primitives, because it works the same exact way as if you didn't have a function and just used the equal sign to assign to a new variable.
Function arguments are passed either by-value or by-sharing, but never ever by reference in JavaScript!
Call-by-Value
Primitive types are passed by-value:
var num = 123, str = "foo";
function f(num, str) {
num += 1;
str += "bar";
console.log("inside of f:", num, str);
}
f(num, str);
console.log("outside of f:", num, str);
Reassignments inside a function scope are not visible in the surrounding scope.
This also applies to Strings, which are a composite data type and yet immutable:
var str = "foo";
function f(str) {
str[0] = "b"; // doesn't work, because strings are immutable
console.log("inside of f:", str);
}
f(str);
console.log("outside of f:", str);
Call-by-Sharing
Objects, that is to say all types that are not primitives, are passed by-sharing. A variable that holds a reference to an object actually holds merely a copy of this reference. If JavaScript would pursue a call-by-reference evaluation strategy, the variable would hold the original reference. This is the crucial difference between by-sharing and by-reference.
What are the practical consequences of this distinction?
var o = {x: "foo"}, p = {y: 123};
function f(o, p) {
o.x = "bar"; // Mutation
p = {x: 456}; // Reassignment
console.log("o inside of f:", o);
console.log("p inside of f:", p);
}
f(o, p);
console.log("o outside of f:", o);
console.log("p outside of f:", p);
Mutating means to modify certain properties of an existing Object. The reference copy that a variable is bound to and that refers to this object remains the same. Mutations are thus visible in the caller's scope.
Reassigning means to replace the reference copy bound to a variable. Since it is only a copy, other variables holding a copy of the same reference remain unaffected. Reassignments are thus not visible in the caller's scope like they would be with a call-by-reference evaluation strategy.
Further information on evaluation strategies in ECMAScript.
As with C, ultimately, everything is passed by value. Unlike C, you can't actually back up and pass the location of a variable, because it doesn't have pointers, just references.
And the references it has are all to objects, not variables. There are several ways of achieving the same result, but they have to be done by hand, not just adding a keyword at either the call or declaration site.
JavaScript is pass by value.
For primitives, primitive's value is passed. For Objects, Object's reference "value" is passed.
Example with Object:
var f1 = function(inputObject){
inputObject.a = 2;
}
var f2 = function(){
var inputObject = {"a": 1};
f1(inputObject);
console.log(inputObject.a);
}
Calling f2 results in printing out "a" value as 2 instead of 1, as the reference is passed and the "a" value in reference is updated.
Example with primitive:
var f1 = function(a){
a = 2;
}
var f2 = function(){
var a = 1;
f1(a);
console.log(a);
}
Calling f2 results in printing out "a" value as 1.
In the interest of creating a simple example that uses const...
const myRef = { foo: 'bar' };
const myVal = true;
function passes(r, v) {
r.foo = 'baz';
v = false;
}
passes(myRef, myVal);
console.log(myRef, myVal); // Object {foo: "baz"} true
In practical terms, Alnitak is correct and makes it easy to understand, but ultimately in JavaScript, everything is passed by value.
What is the "value" of an object? It is the object reference.
When you pass in an object, you get a copy of this value (hence the 'copy of a reference' that Alnitak described). If you change this value, you do not change the original object; you are changing your copy of that reference.
"Global" JavaScript variables are members of the window object. You could access the reference as a member of the window object.
var v = "initialized";
function byref(ref) {
window[ref] = "changed by ref";
}
byref((function(){for(r in window){if(window[r]===v){return(r);}}})());
// It could also be called like... byref('v');
console.log(v); // outputs changed by ref
Note, the above example will not work for variables declared within a function.
Without purisms, I think that the best way to emulate scalar argument by reference in JavaScript is using object, like previous an answer tells.
However, I do a little bit different:
I've made the object assignment inside function call, so one can see the reference parameters near the function call. It increases the source readability.
In function declaration, I put the properties like a comment, for the very same reason: readability.
var r;
funcWithRefScalars(r = {amount:200, message:null} );
console.log(r.amount + " - " + r.message);
function funcWithRefScalars(o) { // o(amount, message)
o.amount *= 1.2;
o.message = "20% increase";
}
In the above example, null indicates clearly an output reference parameter.
The exit:
240 - 20% Increase
On the client-side, console.log should be replaced by alert.
★ ★ ★
Another method that can be even more readable:
var amount, message;
funcWithRefScalars(amount = [200], message = [null] );
console.log(amount[0] + " - " + message[0]);
function funcWithRefScalars(amount, message) { // o(amount, message)
amount[0] *= 1.2;
message[0] = "20% increase";
}
Here you don't even need to create new dummy names, like r above.
I can't see pass-by-reference in the examples where people try to demonstrate such. I only see pass-by-value.
In the case of variables that hold a reference to an object, the reference is the value of those variables, and therefore the reference is passed, which is then pass-by-value.
In a statement like this,
var a = {
b: "foo",
c: "bar"
};
the value of the 'a' is not the Object, but the (so far only) reference to it. In other words, the object is not in the variable a - a reference to it is. I think this is something that seems difficult for programmers who are mainly only familiar with JavaScript. But it is easy for people who know also e.g. Java, C#, and C.
Objects are always pass by reference and primitives by value. Just keep that parameter at the same address for objects.
Here's some code to illustrate what I mean (try it in a JavaScript sandbox such as https://js.do/).
Unfortunately you can't only retain the address of the parameter; you retain all the original member values as well.
a = { key: 'bevmo' };
testRetain(a);
document.write(' after function ');
document.write(a.key);
function testRetain (b)
{
document.write(' arg0 is ');
document.write(arguments[0].key);
b.key = 'passed by reference';
var retain = b; // Retaining the original address of the parameter
// Address of left set to address of right, changes address of parameter
b = {key: 'vons'}; // Right is a new object with a new address
document.write(' arg0 is ');
document.write(arguments[0].key);
// Now retrieve the original address of the parameter for pass by reference
b = retain;
document.write(' arg0 is ');
document.write(arguments[0].key);
}
Result:
arg0 is bevmo arg0 is vons arg0 is passed by reference after function passed by reference
Primitives are passed by value. But in case you only need to read the value of a primitve (and value is not known at the time when function is called) you can pass function which retrieves the value at the moment you need it.
function test(value) {
console.log('retrieve value');
console.log(value());
}
// call the function like this
var value = 1;
test(() => value);