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}
Related
I have the following problem:
I'm trying to overwrite a function to apply it then with angular ($scope.$apply()), but my this-context doesn't seem to be the right one.
The original function (in another file) looks like the following:
Anno.prototype.switchTo = function(otherAnno) {
if (otherAnno != null) {
this.hideAnno();
return otherAnno.show();
} else {
console.warn("Can't switchTo a null object. Hiding instead.");
return this.hide();
}
};
And then in another file I "overwrite" it like the following:
var switchToFunction = AnnoModule.Anno.prototype.switchTo;
AnnoModule.Anno.prototype.switchTo = function(otherAnno) {
switchToFunction(otherAnno);
$scope.$apply();
};
So actually I save the original function, then redefine the original function to call the original one and then apply the scope.
Now comes the problem: As you can see, the function uses this.hideAnno() in it, but in my redefined function, the context is another one, that's why chrome is throwing an error saying "this.hideAnno() is not a function". But now I'm not sure how I can get the right context. I tried to understand this, but I find JavaScript is so confusing that I really don't get it.
Can somebody help me understand that JavaScript confusion?
When a function is called as a method in js, the this inside of it refers to the object the method belongs to.
On the other hand, when a function is called on its own, this inside of it refers to the global object or undefined in strict mode.
You are extracting (and then calling) a function defined as a method into a standalone function, that's why this doesn't do what you expect it to.
What you need in this case is to call or apply your switchToFunction, setting the value of this to what you need. In other words you set the this of the old method to be the this of the new method you created:
var switchToFunction = AnnoModule.Anno.prototype.switchTo;
AnnoModule.Anno.prototype.switchTo = function(otherAnno, that) {
switchToFunction.call(this, otherAnno); // sets `this` of the old method to be this of the new method you created
$scope.$apply();
};
To understand the problem, I think first we should understand how this keyword works and how it can be tweaked.
In JavaScript the this object inside of any function will be the object on which the method is invoked.
Consider these following example,
var obj1 = {
foo: function() {
console.log(this);
}
};
function bar() {
console.log(this);
}
Now when the methods are invoked we get output like below,
obj1.foo(); // obj1
bar(); // window
Because foo method is invoked on obj1, so this inside of foo method became obj1. Similarly this inside bar method will be window object.
Now, what if I want to invoke the bar method with obj1 as this inside the function. For this JavaScript provides call, apply and bind methods to change the this of function dynamically. Let us see how we can achieve this using call method.
bar.call(obj1); // obj1
Similarly,
obj1.foo.call(window); // window
call method takes an thisArg object as argument which will be this inside the bar function. And if bar function also expects arguments that also can be passed through call method following thisArg. See MDN for information about call.
So the solution for your problem will be,
var switchToFunction = AnnoModule.Anno.prototype.switchTo;
AnnoModule.Anno.prototype.switchTo = function(otherAnno) {
switchToFunction.call(this, otherAnno);
$scope.$apply();
};
Hope this makes it clear for you to understand the problem.
How does one call another object's method in the current method?
Example:
function OjbectA() {}
ObjectA.prototype.doWork = function () {
alert('do work');
}
var objectA = new ObjectA();
function ObjectB() {}
ObjectB.prototype.method = function() {
// How to call Object A's doWork() method
}
Current attempt:
// Call doWork
ObjectA.doWork();
Error: "Type Error: doWork() function is not defined.
Question:
What is the correct way to call the method of another object WITHIN the method. What about scoping?
Does ObjectA have to instantiated to call it's methods?
What about the apply() or call() method? I am confused how they apply in this situation.
Final remarks
I want to thank everyone's input in advance. I have only recently made the dive into javascript's OOP. This seemingly simple question is something that I have been struggling all day and I came on here as a final resort.
What is the correct way to call the method of another object WITHIN the method. What about scoping?
There is no one "correct" way. Presumably you want to be able to call a method of ObjectA instances (i.e. a method of ObjectA.prototype) but have an instance of ObjectB as this, so:
ObjectB.prototype.method = function() {
// How to call Object A's doWork() method
ObjectA.prototype.doWork.call(this);
}
That will call the method and set the instance of ObjectB as this.
Does ObjectA have to instantiated to call it's methods?
If you mean "does and instance of ObjectA have to instantiated to call its methods" then no, as shown above. You can call the method on the constructor's prototype directly.
What about the apply() or call() method? I am confused how they apply in this situation.
See the answer to the first question. Whether to use call or apply depends on the arguments that need to be passed and whether you intend do to any processing on them first.
Additional answers
Could you explain the mechanics of ObjectA.prototype.doWork.call(this) a little more?
It calls the method and sets its this to the supplied object. The rules for how a value is assigned to this are explained in EMCA–2626 §10.4.3.
Would ObjectA.prototype.doWork(this) work just the same way?
No. That calls the function, sets its this to ObjectA.prototype and supplies the value of this from the calling execution context as the first parameter. e.g. if it's global code in a browser, effectively:
ObjectA.prototype.doWork(window);
There is a typo, not ObjectA.doWork(); use objectA.doWork();
There really seems to be some confusion with JavaScript's general OOP model.
Every function has an underlying prototype, which is just an object. You may or may not add anything to it, but if you do, you probably plan to use that function as a constructor. That's what you see happening here:
function ObjectA() {}
ObjectA.prototype.doWork = function () {
alert('do work');
}
var objectA = new ObjectA();
objectA.doWork();
However, in some instances, it might be more appealing to just create a function with some methods directly attached to it, rather than creating instances of it. Generally, these would be static methods as in other languages, or perhaps your function is really just a singleton object. In this case, you would omit the prototype, and just attach directly, like so:
function ObjectA() {}
ObjectA.doWork = function () {
alert('do work');
}
ObjectA.doWork()
Going back to the first example, if you define your function and add methods to its prototype, occasionally you may wish to actually call a function that you have defined in a different function's prototype. call and apply can be used to call any function with the value of this changing to the object which you pass into apply or call.
Remember that you are attaching methods to the prototype, so it may look a little funky, but here's an example:
function ObjectA() {}
ObjectA.prototype.doWork = function () {
console.log(this)
}
var objectA = new ObjectA();
function ObjectB() {}
ObjectB.prototype.method = function() {
ObjectA.prototype.doWork.call(this);
}
var objectB = new ObjectB();
objectB.method()
// -> objectB will be logged to your console, bc
// it became the value of this in ObjectA's doWork method.
It's possible to call it from the prototype directly.
Using apply changes the value of this in the execution of the function to the supplied value, so its essentially forwarding this to be itself in the call.
You could also use call, the difference is just in how it takes its arguments, apply takes an array whereas call takes an argument list.
ObjectB.prototype.method = function() {
ObjectA.prototype.doWork.apply(this);
}
However of course an ObjectB does not necessarily have same properties as an ObjectA so make sure you write the method as generic as possible. In order words use a documented concept rather than internal implementation details.
Example again lies with how Array, it's generically applicable methods are documented as such and states what is required for it to work.
In the case you just want to expose a 'utility function', just put it on the object itself. e.g
ObjectA.doWork = function(obj) {
};
After all I found your typo:
function OjbectA() {}
Should be function ObjectA() {}
That's why you were facing error.
function ObjectA() {}
ObjectA.prototype.doWork = function () {
alert('do work');
}
var objectA = new ObjectA();
function ObjectB() {}
ObjectB.prototype.method = function() {
objectA.doWork()
}
I have the following javascript method:
function 123_test_function(){
}
The function is generated by java and sent to the client. The 123 is the id of the component so it could change. i.e I can have another function called 111_test_function()
I want to pass this function as a reference.
So I need to create the reference
var 123_test_function = function 123_test_function(){
}
In another js file inside an object I have a function that needs to use the 123_test_function reference like so:
useFunction(123_test_function);
The problem I'm having is which the 123 part of the function.
In this object I have a variable(uniqueID) which has the number at the beginning of the function.
I need the function call to be something like:
useFunction(uniqueID+"_test_function");
This doesn't seem to pass a function instead it passes a string.
Am I doing something wrong?
For one, identifiers (such as function names) cannot begin with a digit.
To solve your problem, use an object, like this:
// 1. define an object to hold all your functions
var allFunctions = {};
// 2. store any function with a unique string as the ID
allFunctions['123_test_function'] = function () {
// whatever
};
// 3. call the function
allFunctions['123_test_function']();
allFunctions[uniqueID + '_test_function']();
Objects are associative arrays. They store key/values pairs, so they do exactly what you want here.
Note that functions don't need a name in JavaScript, so I did not use on in step 2.
If the function is defined as global one, it will be a member of global object (window in case of browsers). Hence you can just do window['id_'+uniqueID+'_test_function'] to access your function
useFunction(window['id_'+uniqueID+'_test_function'])
(Identifiers cannot begin with numbers in JavaScript so I added the 'id_' prefix. You can of course change it to your liking.)
function test_function(number){
if(number == 1)
{
return function() {}
}
if(number == 2)
{
return function() {}
}
}
call the function like this
var func = test_function(1)
func();
As a couple of people have correctly pointed out, a function (or indeed variable) name cannot begin with a numeric. Also this syntax is wrong:
var 123_test_function = function 123_test_function(){
}
The correct syntax would be:
var 123_test_function = function() {
};
...although it should also be noted that the effect of this is exactly the same as a "traditional"
function 123_test_function() {
}
...declaration, in the context of the window object - since window is effectively the global scope of a JS environment in a browser, it doesn't matter how you define the functions, they will always be accessible from anywhere. Understanding exactly what each method of declaring a function means in Javascript is important - luckily, Douglas Crockford to the rescue once again...
People have suggested various methods for calling your named functions from the context of a string, which is basically attempting to use "variable variable" syntax, a subject that has been discussed on SO and elsewhere at length. The eval() approach should be avoided wherever possible - if you find yourself needing an eval() chances are you went wrong somewhere a while back. #Tomalak has the right idea with a collection of functions held in an object, but this still needs the slightly messy string approach to reference things that are actually being accessed by a numeric ID. The collection approach has the advantage of not cluttering up the window object with what are likely to be single/zero use members.
But the way I see it, all you actually need here is an indexed array of functions, where all you need is the numeric index in order to access them. I suggest you create your functions like this:
// Do this once at the top of your JS
var test_functions = [];
// Now, for each function you define:
test_functions[123] = function() {
// Do stuff here
};
// And when you need to call the functions:
var funcId = 123;
test_functions[funcId]();
I have an object and it has another inner object. How can I call the parent object from the inner object?
var test = {
init: function () {
var instance = this;
},
call: function() {
this.stop(); // works
},
stop: function() {
this.parseText(); // works
},
parseText: {
load: function ()
{
this.call(); //*** dont work
instance.call(); // work, but what if i have this instance (same name) on another object, would'nt this conflict it?
}
}
};
I'm using an instance, which works fine, but what if I or someone wrote an instance (same name) var in another object, wouldn't it will conflict and overwrite this instance?
Eric's answer gives you a reasonable example of how to do what you want to do, but doesn't really go into why.
In JavaScript, this is set entirely by how a function is called (for now; see below the fold for details), not where the function is defined as it is in some other languages that have the same keyword (Java, C++, C#, ...).
You, the coder, determine what this will be each time you call a function. There are two main ways: By calling the function via an object property (in the same expression), or explicitly using the function's built-in call and apply functions.
Via an object property
Using an object property:
obj.foo(); // or
obj["foo"](); // both work
That does two very distinct things, but which collaborate to set the this value: First, the function reference is found by looking up the foo property of the object obj. Then, the function is called. Because you called it as part of the same overall expression retrieving the property value, the JavaScript engine will set this to obj within the call.
So in your example, test.parseText.load(), within the load call this will be parseText, not test, because that's the object on which load was looked up.
Note that setting-this-via-property-lookup only works when they're done at the same time. This does not work:
var f = obj.foo;
f(); // `this` will not be `obj` within the call
That doesn't work because they weren't done at the same time. The property lookup and function call were separated.
Using call or apply
The second way of setting this is more explicit: All functions have the call and apply properties, which are themselves function references that call the function using information you supply. In both cases, the first argument is the object to use as this during the call. So if we wanted to fix the example above that didn't work, we could do this:
var f = obj.foo;
f.call(obj); // `this` will be `obj` within the call
f.apply(obj); // same
The only difference between call and apply is how you supply function arguments. With call, you supply them as further discrete arguments to the function; with apply, you pass in an array of arguments.
So these all do the same thing:
// 1 - Directly via property
obj.foo("a", "b", "c");
// 2 - Using `call`
f = obj.foo;
f.call(obj, "a", "b", "c");
// 3 - Using `apply`
f = obj.foo;
f.apply(obj, ["a", "b", "c"]); // Note the `[ ... ]`, one array with three elements
You can see how call and apply could work with your existing structure:
test.parseText.load.call(test.parseText);
That calls test.parseText.load, making this = test.parseText within the call.
What Eric did in his answer was to use a closure to make it simpler for you to call parseText with the this value you expect.
Further reading (disclosure: from my blog):
Mythical methods
You must remember this
Closures are not complicated
Up top I said:
In JavaScript, this is set entirely by how a function is called
(for now...
The reason I said "for now" is that in ES6, JavaScript is getting "arrow functions" and unlike other functions, the value of this within an arrow function is set by where they're created, not how they're called: They get this from the context where you create them.
Suppose you were writing code in an object method and wanted to use another method of the object to, I don't know, output information from an array (yes, this is contrived). In ES5, you'd probably do this:
this.output("Entries:");
theArray.forEach(function(entry, index) {
this.output(index + ": " + entry);
}, this);
// ^------- tells `forEach` what to use as `this` during the callback
If you left off the argument, you'd have a bug:
this.output("Entries:");
theArray.forEach(function(entry, index) {
this.output(index + ": " + entry); // <== Bug, `this` is either
// `undefined` (strict) or
// the global object (loose)
});
But since arrow functions inherit this from where they're created rather than getting it based on how they're called, the arrow function version of that doesn't need the second argument:
this.output("Entries:");
theArray.forEach((entry, index) => {
this.output(index + ": " + entry);
});
If all you're worried about is test changing, do it like this:
var test = (function() {
var object = {}
object.call = function() {
this.stop(); // works
};
object.stop = function() {
this.parseText(); // apparently works, even though parseText is not a function
};
object.parseText = {
load: function() {
object.call(); // works
}
};
return object;
})();
If you don't know the name of test, you can use a self-invoking anonymous function to create a wrapper, and refer to the object as shown below.
Note that test is not a reference to a function, but to the return value of the anonymous function. Because the object name (obj) is wrapped inside a function, it cannot be read or modified from outside
The solution below is neat, does not pollute the scope of test, and works like a charm. As mentioned earlier, test refers to the same object as obj. It's however not possible to manipulate variable obj, from outside, so that the code inside the function breaks.
var test = (function(){ //Self-executing function
var obj = {
call: function() {
this.stop(); // works
},
stop: function() {
this.parseText(); // works
},
parseText: {
load: function ()
{
obj.call(); // obj refers to the main object
}
}
};
return obj; //Return the object, which is assigned to `test`.
})(); //Invoke function
Update
It's not possible to reliably refer to self, this, or any reference to the object inside an object, without wrapping it.
Your current solution does not work, see comments in the code below:
var obj = {
init: function(){
var instance = this; //`instance` is declared using `var` inside a function
}, // This variable cannot read from "the outside"
parseText: {
load: function(){
instance.call(); //Does NOT work! instance is not defined
}
}
}
"call" is actually a built-in function on the function object that can be used to call the function specifying what to use for this. How does your code work? It doesn't seem like it should since parseText isn't a function...
Maybe try this:
parseText: function() {
var load = function ()
{
this.call(); //*** should work
};
load.call(this);
}
I have tried to figure this out or search for it on google, i can only find how to create objects, not exactly how functions work. If someone could explain to me how encapsulation works.
function myObject() {
this.variable1 = "tst";
this.function1 = function() {
//Now this function works. A 'this' function to a private function is ok
_PrivateFunction1();
//Here is error one, I cannot seem to call methods within the object
//from.
this.function2();
}
this.function2 = function() {
alert("look! function2!");
}
function _PrivateFunction1() {
//This does work though. I am confused.
_PrivateFunction2();
}
function _PrivateFunction2() {
alert("look! PrivateFunction1");
//this does not work.
alert(this.variable1);
}
}
I think I can explain this better if we go in reverse order. First, we define some functions:
function _PrivateFunction1() {
//This does work though. I am confused.
_PrivateFunction2();
}
function _PrivateFunction2() {
alert("look! PrivateFunction1");
//this does not work.
alert(this.variable1);
}
This is pretty normal stuff. The only thing that's weird is that they appear inside another function, but that's perfectly fine. JavaScript has function scope, which means that all variables defined inside a function are defined in a new scope. They do not trample on the global namespace. And functions are first-class objects in JavaScript, which means they can be used just like other data types. They can be nested, passed to functions, returned from functions, etc.
Then we run into some trouble:
function _PrivateFunction2() {
alert("look! PrivateFunction1");
//this does not work.
alert(this.variable1);
}
}
Functions in JavaScript are always executed in some context which is referred to by the this keyword. When you call a function directly (i.e. like this: functionName()) the context in which that function executes is the global window object. So, inside _PrivateFunction2, this.variable1 is equivalent to window.variable1 which is probably not what you meant.
You probably wanted to refer to the current instance of myobject which is what this refers to outside of _PrivateFunction2. You can preserve access to this in an inner scope by storing a reference to it in another variable:
var _this = this;
function _PrivateFunction2() {
alert("look! PrivateFunction1");
//this does not work.
alert(_this.variable1);
}
There's something subtle here you should notice. _PrivateFunction2 has access to the variables defined in its lexical scope, which is why it can access _this. This will be important later.
Next up:
function _PrivateFunction1() {
//This does work though. I am confused.
_PrivateFunction2();
}
This should be the most normal-looking section to you, I would think. There's nothing strange going on here. Just one regular function calling another one. Don't be confused by the fact that these are nested inside myObject. That changes the scope they're in, but not much else.
Next we define some instance variables and methods:
this.variable1 = "tst";
this.function1 = function() {
//Now this function works. A 'this' function to a private function is ok
_PrivateFunction1();
//Here is error one, I cannot seem to call methods within the object
//from.
this.function2();
}
this.function2 = function() {
alert("look! function2!");
}
Here this really does refer to myObject, assuming -- and it's an important assumption -- that myObject was called with the new operator, like this:
var obj = new myObject();
If it had been called like this:
var obj = myObject();
Then this would refer to the window object, just like it did for the functions we saw earlier. The key takeaway is that the value of this is not fixed. It's determined by the way in which the function is called. There are even ways to set it to an arbitrary object explicitly.
The value of this inside this.function1 will also be the current instance of myObject, because it will most likely be used like this:
var obj = new myObject();
obj.function1();
Writing object.method() sets this to object inside method.
So how is this.function1 able to call _PrivateFunction1()? Just as we saw earlier when saving the value of this for use inside a nested function, _PrivateFunction1() is just another object defined in this.function1's lexical scope, so it is available for its use, just as _this was earlier.
And it's because of closure that these private variables are still alive long after myObject has returned.
Footnote: Because failing to use new when instantiating objects breaks things so spectacularly without warning, it's considered good practice to capitalize the names of functions you intend to be used as a constructor. So myObject should really be MyObject.
You have to save a copy of the actual object like here note the var that = this
Tested in chrome and FF
for encapsulation I would prefer module pattern like
var someMethod = function(){
var i,
length,
// public method
public = function(num1, num2){
return num1+num2;
},
//private method
_private = function(){};
//exposing the public method
return{
public:public
}
};
var callPublic = someMethod();
callPublic.public(20, 30);// call the public method and return 50
now , if you try to call that private method like
callPublic._private();//it will return not a function since its not been exposed
There are lot of other pattern to encapsulate your methods but module pattern is most common. Hope ot will help you how to encapsulate data in javascript.