How can i retrieve the reference to object containing a function from an input in the form objectReference["functionName"].
Example:
function aaa(param) {
var objectReference = /*..???...*/;
var functionName = /*...???..*/;
// Now expected result is that objectReference contains
// a reference to myObject, and functionName contains a
// string with name of function (implemented in myObject),
// so I can invoke it with objectReference[functionName]()
// after some manipulation.
}
var myObject = new SomeFunction();
aaa(myObject["myFunction"]);
Thank you
You can't do either of the things you've listed. There are two separate things here:
Getting the myObject value
Getting the name of the property that that object uses to refer to the function
The value passed into aaa in your code is just a reference to the function. The reference to the object is not passed into aaa, nor is any information about what property the object used to refer to the function. Neither can be inferred or derived from the function reference itself. (The function may have a name, which could on modern JavaScript engines be access via its name property, but that may well be different from the name of the property that the object used to refer to it.)
In order to do this, you have to pass them separately, either as discrete arguments:
aaa(myObject, "myFunction");
or as an object
aaa({obj: myObject, prop: "myFunction"});
In the latter case, aaa might look like
function aaa(info) {
// Use info.obj and info.prop here
// The call would be
info.obj[info.prop]();
}
Another option, if you don't really need the object reference except for the purposes of making the call, is to use Function#bind:
aaa(myObject["myFunction"].bind(myObject));
aaa will receive a function reference that, when called, will call the original function with this referring to myObject. So aaa can't actually get the object reference, but it can still make the call.
Related
I created a normal JavaScript object, like this:
let obj = {
name : "something",
print() {
console.log(this.name);
}
}
let res = obj.print()
console.log(res);
In this example obj has a name and a simple method. I am calling the method from the outside. After that I log the return value to the console, which is undefined.
I don't understand what is happening behind the scenes within the object. Please explain to me the creation and execution phase for this code.
Behind the scenes, the JavaScript interpreter creates an object in memory and refers to it through obj. When you call obj.print(), it refers to the same object and calls the method defined.
In the method, this refers to the object itself (obj), and is set by the JS interpreter as an implicit reference.
At last, you forgot to return the value from print(). So, nothing is assigned to res. Refer to the following example, as it prints the value of res correctly, when a value is returned from the function.
let obj = {
name: "something",
print() {
console.log(this.name);
return this.name;
}
}
let res = obj.print()
console.log(res);
I am going to write about the "behind the scenes" that you are asking for. Unfortunately this might confuse you, instead of making things clearer as JavaScript is quite a "different" language on its own.
In JavaScript a function is an object. Sometimes even called a first-class object. It has everything an object has (attributes and methods) and in addition can further more be invoked. Don't believe me? See for yourself:
function abracadabra()
{
return "this is magic";
}
console.log(abracadabra.name);
console.log(abracadabra.call());
Now a method is simply another function to which an attribute of an object is referring to. Let's take your example:
let obj = {
name : "something",
print() {
console.log(this.name);
}
}
Here obj is defined as an object with two attributes. A value type and a function. When you call the obj.print() function the following happens:
The function is called.
The so-called function context this is set to the object that the method is called upon. You can use this to access other attributes of the same object.
What exactly is this? As said it is the so-called function context that can refer to four different objects depending on how a function is called.
The function is called as a function. e.g. abracadabra() => this is referring to the global context, to which it is always referring by default.
The global context is dependent on the environment JavaScript is executed in. Remember JavaScript can not only run in a browser. It can also be used as a server-side scripting language. In the browser the global context is the current browser window. Don't believe me? See for yourself:
// We are not in any method, still "this" is available:
console.log(this.toString());
The function is called as a method. e.g. obj.print() => this is referring to the object the method is invoked on. I described this above.
The function is called as a constructor. e.g. new abracadabra() => A new empty object is created and this is referring to it. Now the function should extend the empty object with attributes.
The function is called using its apply or call methods => this is referring to whatever you pass as the very first argument of these methods.
So to sum it up: It can get tricky to really understand how these things work in JavaScript. This is because basically there are only objects and functions in the language. Methods look like methods, but are in reality only functions as well.
To get a really good in depth understanding I can recommend the book Secrets of the JavaScript Ninja.
I have a following function
self._eventLogger({
name: 'SeekerCredentialingIntroPageView'
});
this.lastBGCRequestStatus(self._eventLogger.name);
I am not able to access name outside of self._eventLogger() function. lastBGCRequestStatus() function accepts one parameter and I want to pass my name variable as a parameter.
I've tried following solutions:
this.lastBGCRequestStatus(self._eventLogger.name);
this.lastBGCRequestStatus(self._eventLogger['name']);
with no luck.
Can somebody please suggest me any other way to do this?
You can do something like this:
var myName = 'SeekerCredentialingIntroPageView';
self._eventLogger({name: myName});
this.lastBGCRequestStatus(myName);
I am not able to access 'name' outside of self._eventLogger() function
Well...no, because you're passing an object into it and not keeping a reference to that object, and name is a property on that object. Passing an argument into a function doesn't modify the function (unless of course the function's code does that).
If you want to use the object after passing it to the function, keep a reference to it:
var event = {
name: 'SeekerCredentialingIntroPageView'
};
self._eventLogger(event);
this.lastBGCRequestStatus(event.name);
Side note: As of ES2015 (aka "ES6"), functions have a built-in name property. Support remains a bit spotty, but with your original code, you could easily have ended up passing "_eventLogger" into lastBGCRequestStatus. :-)
You could try this:
var obj = { name: 'SeekerCredentialingIntroPageView' };
self._eventLogger(obj);
this.lastBGCRequestStatus(obj.name);
In the _eventLogger you pass an object that you create at this moment. So you can't access it's properties later, since the only who would be informed about the object's reference would be the function you passed a copy of it.
I'm just wondering if I can make some of my helper functions(for stuff like benching, logging and caching) a bit neater. Right now I'm doing this
function doSomethingToMethodsObject(object, methodname) {
//do things to object and object[methodname]
}
so I can use it like this
var myObject = function() {
this.myString = "hello";
this.myMethod = function() { return this.myString; }.bind(this);
doSomethingToMethodsObject(this, "myMethod");
}
but it would be better if I could call it like this
doSomethingToMethodsObject(this.myMethod);
and then break down the function reference to this and "myMethod" inside doSomethingToMethodsObject.
So is there a way to figure out what objects a function belongs to?
So is there a way to figure out what objects a function belongs to?
A function does not belong to only a single object. There can be lots of references to that same function on lots of different objects. So, no you can't specifically figure out what object a function belongs to by purely looking at the function.
In fact, why you pass this.myMethod as an argument, there is no connection whatsoever to the this part that is passed. It just gets a reference to the function and passes that.
You can use .bind() to pass a bound reference to the function, but that only lets you call the method in the context of the right object - it doesn't allow you to separate out the object from the method. If you need both object and method separately in your function, then you will need to find some way to make them both separately accessible inside the function - the most obvious way to do that is just pass them both as arguments.
Depending upon the specific context (which you don't really share very much of), sometimes you can use parent scoped variables like var self = this; to maintain a reference to this that can be accessed by child functions, but I'm not sure that applies to what you're doing.
Here are some options:
doSomethingToMethodsObject(this, this.myMethod);
doSomethingToMethodsObject({obj: this, method: this.myMethod});
When you use this.myMethod, JS creates a reference whose base is this and whose referenced name is "myMethod".
However, when you use it as an argument, JS resolves the reference into the property value. Therefore, in doSomethingToMethodsObject, it's too late to get the base.
The only way to obtain the base of this.myMethod is when myMethod is an accessor property with a getter which redirects to the underlying object value. Then you can use this inside the getter, and store it in a property of the underlying value.
For example:
var obj = {
_myMethod: function(arg) { /* Underlying function */
return {thisArg: this, arg: arg};
},
get myMethod() { /* Stores reference parts and redirects */
return Object.assign(this._myMethod, {
refBase: this,
refName: "_myMethod"
});
}
};
function doSomethingToMethodsObject(value) {
return value.call(
value.refBase,
value === value.refBase[value.refName]
);
}
obj.myMethod(123); // {thisArg: obj, arg: 123}
doSomethingToMethodsObject(obj.myMethod); // {thisArg: obj, arg: true}
When a variable refers to an object the value is a reference to the object (Referred from: Javascript by reference vs. by value )
function fun1(obj) {
obj.first = 1; //it affects the object ->obj
}
var myObj1 = {first: 0};
fun1(myObj1); //sending the object to the function
console.log(myObj1.first); // 1
But I would like to change the variable from an object, for example
function fun2(obj) {
obj = 1; }
var myObj2 = {first: 0};
fun2(myObj2.first);
console.log(myObj2.first);
Is there any way to achieve this?
Is there any way to achieve this?
Not directly. All you can do is pass an object and have the function modify a property on it, as in your first example. JavaScript does not have pass-by-reference, just pass-by-value. (The value may be an object reference, of course, but it's still a value.) There's no way in JavaScript to directly modify the variable/property you're passing into the function, because what the function receives is a copy of the value of that variable/property, not a reference to that variable/property.
Just to be clear about something: In your first code block, you said you were "sending the object to the function." That's incorrect. You send a reference to the object to the function.
This is the key thing to understand: Variables, properties, and function arguments (collectively, "variables") contain values, and those values are copied when you use assignment or when you pass them into functions. The value that refers to an object is called an object reference, because the value isn't the object, it's a reference to (pointer to) the object elsewhere in memory. The reference is copied when you pass it into a function, the object is not.
Don't confuse the "reference" in "object reference" with the "reference" in "pass-by-reference," they're completely different things. (In pass-by-reference, the reference is to the variable, not an object. JavaScript doesn't have pass-by-reference.)
I'm reading that in JavaScript, a common point of confusion arises because variables of primitives are passed by value, and variables of objects are passed by reference, while in function arguments, both primitives and references are passed by value.
In the course of my tinkering, I've made up the following code, but am having trouble wrapping my head around it.
> function setName2(obj) {
... obj.name="matt";
... obj = new Object();
... obj.name="obama";
... }
If I set
var person = new Object();
person.name = "michelle";
Then run
> setName2(person);
I get
> person.name;
'matt'
Which makes sense because the new object created is a pointer to a local object, hence not affecting the property of the global 'person'.
However, what if I first set
var obj = new Object();
obj.name = "michelle";
Then run
> setName2(obj);
?
I get the same outcome. Does this mean that the compiler recognizes the two variables of the same name (obj global and obj local) as references to different locations within the heap, each having some different pointer association, or is there a different explanation for this phenomenon?
JavaScript does not have pass-by-reference; everything is passed by value. However, some values are themselves references to objects. This distinction (pass-by-reference vs. is-a-reference) leads to much confusion.
An example to clear things up:
function f(o) { ... }
var obj = { foo: 42 };
f(obj);
No matter what you do in f, obj will always refer to the same object because the argument is not passed by reference. However the value obj, which is copied into o, is itself a reference to an object. This is why any property changes made to o inside the function will be visible on obj after it returns.
while in function arguments, both primitives and references are passed by value.
This is not true. There is nothing special about function arguments.
function setName2(obj) {
This accepts a reference to an object as an argument.
obj.name="matt";
This modifies the name property of the object that reference points to.
obj = new Object();
This replaces the reference to the original object with a reference to a new object.
obj.name="obama";
This modifies the name property of the new object. The original object is unchanged.
The confusion comes from the fact that "passed by reference" is misinterpreted by people or used in a wrong sense.
Parameters are passed by value. This means that changing the value inside the method doesn't change the original value.
In case of primitives, the value of a primitive is its value.
In case of objects, the value of an object is a reference to it. You can access and change object's content but you can't change the value of the reference itself.
In other programming languages, like C++ or C#, "passing by reference" means that you pass:
- a reference to a primitive type
- a reference to a reference to an object
In such case, not only the content of an object can be changed but also a reference itself can be changed.
There is NO passing by reference in Javascript.
Javascript uses pass-by-value.
The confusion is that objects are hold by reference variables (kind of pointers). In fact most common languages (java, javascript, etc.) do not have a real pass-by-reference behaviour. Another way to understand this could be pass-reference-by-value, although, formally, there is not such a thing.
That means when you pass an object as a parameter, you are actually passing a reference to the object by-value.
function setName2(obj) {
...
}
setName2(person);
here the contents of person (a reference, or "pointer" if you like) is copied by-value to a new local variable: obj.
obj and person are different variables that hold a reference to the same object.
So, doing obj = new Object(); makes obj to point to the new object. But person is unaffected since it is still a completely different variable.
I don't know where you read that, but it's absolutely not true. Objects are passed by reference, full stop. Whether or not it's a function parameter is completely irrelevant.