Related
I just came across an interesting situation in JavaScript. I have a class with a method that defines several objects using object-literal notation. Inside those objects, the this pointer is being used. From the behavior of the program, I have deduced that the this pointer is referring to the class on which the method was invoked, and not the object being created by the literal.
This seems arbitrary, though it is the way I would expect it to work. Is this defined behavior? Is it cross-browser safe? Is there any reasoning underlying why it is the way it is beyond "the spec says so" (for instance, is it a consequence of some broader design decision/philosophy)? Pared-down code example:
// inside class definition, itself an object literal, we have this function:
onRender: function() {
this.menuItems = this.menuItems.concat([
{
text: 'Group by Module',
rptletdiv: this
},
{
text: 'Group by Status',
rptletdiv: this
}]);
// etc
}
Cannibalized from another post of mine, here's more than you ever wanted to know about this.
Before I start, here's the most important thing to keep in mind about Javascript, and to repeat to yourself when it doesn't make sense. Javascript does not have classes (ES6 class is syntactic sugar). If something looks like a class, it's a clever trick. Javascript has objects and functions. (that's not 100% accurate, functions are just objects, but it can sometimes be helpful to think of them as separate things)
The this variable is attached to functions. Whenever you invoke a function, this is given a certain value, depending on how you invoke the function. This is often called the invocation pattern.
There are four ways to invoke functions in javascript. You can invoke the function as a method, as a function, as a constructor, and with apply.
As a Method
A method is a function that's attached to an object
var foo = {};
foo.someMethod = function(){
alert(this);
}
When invoked as a method, this will be bound to the object the function/method is a part of. In this example, this will be bound to foo.
As A Function
If you have a stand alone function, the this variable will be bound to the "global" object, almost always the window object in the context of a browser.
var foo = function(){
alert(this);
}
foo();
This may be what's tripping you up, but don't feel bad. Many people consider this a bad design decision. Since a callback is invoked as a function and not as a method, that's why you're seeing what appears to be inconsistent behavior.
Many people get around the problem by doing something like, um, this
var foo = {};
foo.someMethod = function (){
var that=this;
function bar(){
alert(that);
}
}
You define a variable that which points to this. Closure (a topic all its own) keeps that around, so if you call bar as a callback, it still has a reference.
NOTE: In use strict mode if used as function, this is not bound to global. (It is undefined).
As a Constructor
You can also invoke a function as a constructor. Based on the naming convention you're using (TestObject) this also may be what you're doing and is what's tripping you up.
You invoke a function as a Constructor with the new keyword.
function Foo(){
this.confusing = 'hell yeah';
}
var myObject = new Foo();
When invoked as a constructor, a new Object will be created, and this will be bound to that object. Again, if you have inner functions and they're used as callbacks, you'll be invoking them as functions, and this will be bound to the global object. Use that var that = this trick/pattern.
Some people think the constructor/new keyword was a bone thrown to Java/traditional OOP programmers as a way to create something similar to classes.
With the Apply Method
Finally, every function has a method (yes, functions are objects in Javascript) named "apply". Apply lets you determine what the value of this will be, and also lets you pass in an array of arguments. Here's a useless example.
function foo(a,b){
alert(a);
alert(b);
alert(this);
}
var args = ['ah','be'];
foo.apply('omg',args);
Function calls
Functions are just a type of Object.
All Function objects have call and apply methods which execute the Function object they're called on.
When called, the first argument to these methods specifies the object which will be referenced by the this keyword during execution of the Function - if it's null or undefined, the global object, window, is used for this.
Thus, calling a Function...
whereAmI = "window";
function foo()
{
return "this is " + this.whereAmI + " with " + arguments.length + " + arguments";
}
...with parentheses - foo() - is equivalent to foo.call(undefined) or foo.apply(undefined), which is effectively the same as foo.call(window) or foo.apply(window).
>>> foo()
"this is window with 0 arguments"
>>> foo.call()
"this is window with 0 arguments"
Additional arguments to call are passed as the arguments to the function call, whereas a single additional argument to apply can specify the arguments for the function call as an Array-like object.
Thus, foo(1, 2, 3) is equivalent to foo.call(null, 1, 2, 3) or foo.apply(null, [1, 2, 3]).
>>> foo(1, 2, 3)
"this is window with 3 arguments"
>>> foo.apply(null, [1, 2, 3])
"this is window with 3 arguments"
If a function is a property of an object...
var obj =
{
whereAmI: "obj",
foo: foo
};
...accessing a reference to the Function via the object and calling it with parentheses - obj.foo() - is equivalent to foo.call(obj) or foo.apply(obj).
However, functions held as properties of objects are not "bound" to those objects. As you can see in the definition of obj above, since Functions are just a type of Object, they can be referenced (and thus can be passed by reference to a Function call or returned by reference from a Function call). When a reference to a Function is passed, no additional information about where it was passed from is carried with it, which is why the following happens:
>>> baz = obj.foo;
>>> baz();
"this is window with 0 arguments"
The call to our Function reference, baz, doesn't provide any context for the call, so it's effectively the same as baz.call(undefined), so this ends up referencing window. If we want baz to know that it belongs to obj, we need to somehow provide that information when baz is called, which is where the first argument to call or apply and closures come into play.
Scope chains
function bind(func, context)
{
return function()
{
func.apply(context, arguments);
};
}
When a Function is executed, it creates a new scope and has a reference to any enclosing scope. When the anonymous function is created in the above example, it has a reference to the scope it was created in, which is bind's scope. This is known as a "closure."
[global scope (window)] - whereAmI, foo, obj, baz
|
[bind scope] - func, context
|
[anonymous scope]
When you attempt to access a variable this "scope chain" is walked to find a variable with the given name - if the current scope doesn't contain the variable, you look at the next scope in the chain, and so on until you reach the global scope. When the anonymous function is returned and bind finishes executing, the anonymous function still has a reference to bind's scope, so bind's scope doesn't "go away".
Given all the above you should now be able to understand how scope works in the following example, and why the technique for passing a function around "pre-bound" with a particular value of this it will have when it is called works:
>>> baz = bind(obj.foo, obj);
>>> baz(1, 2);
"this is obj with 2 arguments"
Is this defined behavior? Is it
cross-browser safe?
Yes. And yes.
Is there any reasoning underlying why
it is the way it is...
The meaning of this is pretty simple to deduce:
If this is used inside a constructor function, and the function was invoked with the new keyword, this refers to the object that will be created. this will continue to mean the object even in public methods.
If this is used anywhere else, including nested protected functions, it refers to the global scope (which in the case of the browser is the window object).
The second case is obviously a design flaw, but it's pretty easy to work around it by using closures.
In this case the inner this is bound to the global object instead of to the this variable of the outer function.
It's the way the language is designed.
See "JavaScript: The Good Parts" by Douglas Crockford for a good explanation.
I found a nice tutorial about the ECMAScript this
A this value is a special object which is related with the execution
context. Therefore, it may be named as a context object (i.e. an
object in which context the execution context is activated).
Any object may be used as this value of the context.
a this value is a property of the execution context, but not a
property of the variable object.
This feature is very important, because in contrary to variables, this value never participates in identifier resolution process. I.e. when accessing this in a code, its value is taken directly from the execution context and without any scope chain lookup. The value of this is determinate only once when entering the context.
In the global context, a this value is the global object itself (that means, this value here equals to variable object)
In case of a function context, this value in every single function call may be different
Reference Javascript-the-core and Chapter-3-this
All the answers here are very helpful but I still had a hard time to figure out what this point to in my case, which involved object destructuring. So I would like to add one more answer using a simplified version of my code,
let testThis = {
x: 12,
y: 20,
add({ a, b, c }) {
let d = a + b + c()
console.log(d)
},
test() {
//the result is NaN
this.add({
a: this.x,
b: this.y,
c: () => {
//this here is testThis, NOT the object literal here
return this.a + this.b
},
})
},
test2() {
//64 as expected
this.add({
a: this.x,
b: this.y,
c: () => {
return this.x + this.y
},
})
},
test3() {
//NaN
this.add({
a: this.x,
b: this.y,
c: function () {
//this here is the global object
return this.x + this.y
},
})
},
}
As here explained Javascript - destructuring object - 'this' set to global or undefined, instead of object it actually has nothing to do with object destructuring but how c() is called, but it is not easy to see through it here.
MDN says "arrow function expressions are best suited for non-method functions" but arrow function works here.
this in JS:
There are 3 types of functions where this has a different meaning. They are best explained via example:
Constructor
// In a constructor function this refers to newly created object
// Every function can be a constructor function in JavaScript e.g.
function Dog(color){
this.color = color;
}
// constructor functions are invoked by putting new in front of the function call
const myDog = new Dog('red');
// logs Dog has color red
console.log('Dog has color ' + myDog.color);
Normal function or method
// Browswer example:
console.log(this === window) // true
function myFn(){
console.log(this === window)
}
myFn(); // logs true
// The value of this depends on the context object.
// In this case the context from where the function is called is global.
// For the global context in the browser the context object is window.
const myObj = {fn: myFn}
myObj.fn() // logs false
// In this case the context from where the function is called is myObj.
// Therefore, false is logged.
myObj.fn2 = function myFn(){
console.log(this === myObj)
}
myObj.fn2() // logs true
// In this case the context from where the function is called is myObj.
// Therefore, true is logged.
Event listener
Inside the function of an event handler this will refer to the DOM element which detected the event. See this question: Using this inside an event handler
Good Morning everyone,
So I have a rather confusing question so I will try to be as clear as possible and keep it just as concise.
Assume that I have a function basicFunction. basicFunction has two arguments of funcWithParams and callback.
basicFunction(funcWithParams, callback){
.
.
.
// do stuff here
}
funcwIthParams is exactly what it says, a function either with or with out arguments, argument callback is a function that triggers when the initial part of basicFunction is completed.
With all that being said above, here is my question. Is it possible when passing a function with parameter to grab the function name itself, and each individual argument that was passed with it, and the value of each passed argument? I know for sure you can get a function name as a string, but I'm not exactly sure about the arguments and the values for each.
I have been researching this like crazy for the last three days, and I'm sure there is a way, but I have yet to find an answer.
Example
function basicFunction(funcWithParams, callback){
// create a loop to go through and log each of the parameters in the first argument's function
}
function somethingElse(param1, param2, param3){
}
function callbackFunction(){
alert("I did stuff");
}
basicFunction(somethingElse(param1, param2, param3), callbackFunction);
I think you're probably looking for something usually called partial application or currying (after the mathematician Haskell Curry).
JavaScript doesn't have pure currying (built in; it's easy to add), but does have Function#bind, which lets you create a function based on another function that, when called, will call the original function with a specific this value and with any arguments you give. If you don't care about this, just use null. As that's clear as mud, let's have an example:
function foo(a, b) {
snippet.log(a + ", " + b);
}
foo(1, 2); // "1, 2"
// Create curried version
var bar = foo.bind(null, 100);
// Call curried version
bar(200); // "100, 200"
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
There, we "curried" the value 100 for the argument a when creating bar from foo.
So in your example, you'd do this:
basicFunction(somethingElse.bind(null, param1, param2, param3), callbackFunction);
Re your comment:
This is almost what I'm trying to do, but instead what I'm looking at is something like bar(foo(1,2), 100);, and from this getting the results of "foo" as a string, and the values of 1 and 2.
If you do bar(foo(1,2),100), foo gets called with the arguments 1 and 2, and then its return value is passed into bar along with 100. By the time bar is called, there is no information passed to it that in any way refers back to foo, 1, or 2. Exactly the way x = foo(1, 2) sets the return value of foo on x, again without anything continuing to refer back to foo (or 1 or 2) from x.
If you want access to the args, then the only thing that comes to mind is to pass an object with the function and its arguments, like this:
bar({f: foo, args: [1, 2]}, 100);
Then, in bar:
function bar(finfo, additionalArg) {
console.log(finfo.f.name); // "foo", probably, see caveats
console.log(finfo.args[0]); // 1
console.log(finfo.args[1]); // 2
// calling it
finfo.f.apply(null, finfo.args);
}
Function#apply calls the function you call it on, using the first argument you give it as the this value for the call, and then using the arguments you give it as an array as the individual arguments to pass the function.
Live Example:
function foo(a, b) {
snippet.log("foo called with " + a + " and " + b);
}
function bar(finfo, additionalArg) {
console.log(finfo.f.name); // "foo", probably, see caveats
console.log(finfo.args[0]); // 1
console.log(finfo.args[1]); // 2
// calling it
snippet.log("bar calling finfo.f via apply");
finfo.f.apply(null, finfo.args);
}
snippet.log("Calling bar");
bar({f: foo, args: [1, 2]}, 100);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Caveats:
Function#name was commonly provided by browsers, but wasn't part of the spec until June of this year when ECMAScript 6th Edition (ES6) came out. So you may find the odd browser that doesn't support it. If so, you may have to do the horrible toString thing to figure out the function's name.
Not all functions have names. ES6 gives many formerly-anonymous functions names, but it's still possible to create anonymous functions, and not all browsers will support the various ways ES6 infers function names (for instance, from expressions like var f = function() { };).
The only truly guaranteed way to provide a name for foo is to do it manually when creating the function:
function foo() {
//...
}
foo.name = "foo";
Soon that won't be true, but it is in today's world.
If you're working with an instance of a class, you may need to worry about context. In this case, it makes sense to bind. For instance:
function Sum() {
this._total = 0;
this.addTen = this.add.bind(this, 10);
}
Sum.prototype.add = function(amount) {
this._total += amount;
return this;
};
Sum.prototype.toString = function() {
return '' + this._total;
};
var sum = new Sum();
sum.addTen().addTen();
console.info(sum);
// 20
However, outside of an instance, there is usually no need for context and the more appropriate form of currying may be to create a factory function, like so:
function createAdder(amount1) {
return function AddTo(amount2) {
return amount1 + amount2;
};
}
var addTenTo = createAdder(10);
var fifty = addTenTo(40);
console.info(fifty);
// 50
This usually comes down to implementation details and preference. There are good uses and arguments for both methods.
I'm very new to JS and I have been playing around with Jasmine.
In Jasmine, I can see a method called spyOn, which does inspect/spy the functions.
How does this works in js? Coming from Java background is it a proxy? How to write one?
You can find the precise implementation on GitHub, but here is a simplified explanation:
function mySpy(obj, methodName) {
// remember the original method
var originalMethod = obj[methodName];
// ... then replace it with a method that ...
obj[methodName] = function () {
// ... does whatever additional thing it wants to do ...
console.log(methodName + " called, first argument: " + arguments[0]);
// ... and then calls the original method with the same arguments,
// and returns the result.
return originalMethod.apply(this, arguments);
};
}
Now you can do this:
var o = {
inc: function (x) { return x + 1; }
};
mySpy(o, "inc");
console.log(o.inc(13));
This will output
inc called, first argument: 13
14
Three important things for you to know, coming from a Java background, are
In JavaScript, it is not a problem to change an object's methods after the fact, dynamically. Calling someObj.someMethod = someOtherFunction is perfectly valid. (To be 100% precise, you may not actually be overwriting the original method, because it may be somewhere up the prototype chain, instead of on the object itself. That's an advanced topic though, and not very important here. Also, Java's distinction beween methods and class members doesn't apply to JavaScript.)
The special "variable" arguments inside a function contains whatever arguments the function was called with. In Java terms, imagine that someMethod(Foo x1, Bar x2) always has an implicit second signature of the type someMethod(Object... arguments), meaning you could always use x1 and arguments[0] interchangeably.
obj.someName and obj["someName"] are entirely equivalent in JavaScript. Because of this, you can easily access/change an object's properties using the property name as a string, something that in Java you would have to use reflection for.
I come across this code in jsGarden, and I cannot figure the meaning to chain call and apply together. Both will execute the function with a given context object, why it could be chained?
function Foo() {}
Foo.prototype.method = function(a, b, c) {
console.log(this, a, b, c);
};
// Create an unbound version of "method"
// It takes the parameters: this, arg1, arg2...argN
Foo.method = function() {
// Result: Foo.prototype.method.call(this, arg1, arg2... argN)
Function.call.apply(Foo.prototype.method, arguments);
};
It's making a call to call via apply; that is, it's using call to call a function ("method"), and it's using apply to make the call because it's got the arguments in the form of an (almost) array.
So to take it apart:
Function.call
That's a reference to the call() function available on all Function instances, inherited from the Function prototype.
Function.call.apply
That's a reference, via the reference to the call function, to apply. Because apply is referenced via the call object, when the call to apply is made the this value will be a reference to the call function.
Function.call.apply(Foo.prototype.method, arguments);
So we're invoking the call function via apply, and passing Foo.prototype.method to be the this value, and the arguments to "Foo.mmethod" as the arguments.
I think it's basically the same effect as this:
Foo.method = function() {
var obj = arguments[0], args = [].slice.call(arguments, 1);
Foo.prototype.method.apply(obj, args);
}
but I'll have to try it to make sure. edit Yes that seems to be it. So I can summarize the point of that trick as being a way to invoke apply() when the desired this value is the first element of the array holding the parameters. In other words, usually when you call apply() you've got the desired this object reference, and you've got the parameters (in an array). Here, however, since the idea is that you pass in the desired this as a parameter, then it needs to be separated out in order for a call to apply to be made. Personally I would do it as in my "translation" because it's a little less mind-bending (to me), but I suppose one could get used to it. Not a common situation, in my experience.
I think the code should be like this:
function Foo() {}
Foo.prototype.method = function(a, b, c) {
console.log(this, a, b, c);
};
Foo.method = function() {
//Notice this line:
Function.apply.call(Foo.prototype.method, this, arguments);
};
then
Foo.method(1,2,3) => function Foo() {} 1 2 3
Other examples:
Function.apply.call(Array,this,[1,2]) => [1, 2]
Function.call.apply(Array,this,[1,2]) => [window]
Function.call.call(Array,this,[1,2]) => [[1, 2]]
apply does take an array as the second argument, call takes single parameters.
// lets take call,
var callfn = Function.prototype.call;
// an ordinary function from elsewhere
var method = Foo.prototype.method;
// and apply the arguments object on it:
callfn.apply(method, arguments);
So, the first arguments item will be the this value of the method, and the subsequent will fill the single parameters.
The result is a static function method on the Foo constructor, that takes a Foo instance (or something similiar) as the first argument and applies the prototype method on it. A possible usecase were to define a Object.hasOwnProperty function, which is normally only available as Object.prototype.hasOwnProperty.
Ultimately, it makes the invocation of the method one "prototype" and one "call" shorter if you need to apply it on objects that a) don't inherit it or b) overwrite it.
Person.prototype.fullname = function(joiner, options) {
options = options || { order: "western" };
var first = options.order === "western" ? this.first : this.last;
var last = options.order === "western" ? this.last : this.first;
return first + (joiner || " ") + last;
};
// Create an unbound version of "fullname", usable on any object with 'first'
// and 'last' properties passed as the first argument. This wrapper will
// not need to change if fullname changes in number or order of arguments.
Person.fullname = function() {
// Result: Person.prototype.fullname.call(this, joiner, ..., argN);
return Function.call.apply(Person.prototype.fullname, arguments);
};
The Code from Javascript Garden.
Notice that it state the Function.call.apply(Person.prototype.fullname, arguments);
will become this:
Person.prototype.fullname.call(this, joiner, ..., argN);
It means the apply() function will be excuated first, then the call() function will be execuated.
Pattern: The right most call() / apply() will get execuated first
So right most apply() will get executed first
The context of the apply() becomes the caller of the call() function, so now Person.prototype,fullname.call()
apply()can only take one single array of parameters, so apply() provides arguments to the call() function, so now Person.prototype,fullname.call(arguments)
Examples from #foxiris
1st One:
Function.apply.call(Array,this,[1,2])
The right most call() will get execuated first
The context of call() becomes the caller of the apply() ,so now Array.apply()
The call() can accept multiple arugments, so it can provide this and [1, 2] to apply(), so now Array.apply(this, [1, 2]);, which will output [1, 2]
2nd One:
Function.call.apply(Array,this,[1,2])
The right most apply() will get execuated first
The context of apply() becomes the caller of the call() ,so nowArray.call()
The apply() can only take one single array parameter, so it can only provide this to call(), so now Array.call(this);, output is [].
3rd One:
Function.call.call(Array,this,[1,2])
The right most call() will get execuated first
The context of call()(right most one) becomes the caller of call()(the second to the right), so now Array.call()
The call() can take multiple parameters, so it can provide this and [1, 2] to another call(), so now Array.call(this, [1, 2]);, output is [[1, 2]].
The book Learning JavaScript defines anonymous functions as follows...
Functions are objects. As such, you can create them - just like a String or Array or other type - by using a constructor and assigning the function to a variable. In the following code, a new function is created using the Function constructor, with the function body and argument passed in as arguments:
var sayHi = new Function("toWhom", "alert('Hi' + toWhom);");
This type of function is often referred to as an anonymous function because the function itself isn't directly declared or named.
Is this the correct definition of an "anonymous function" in JavaScript? If not, what is an anonymous function, and is there any difference between an anonymous function and a function literal?
Function expressions and function declarations
Since you are interested in functions, here is some important stuff to know.
var abc = function() { ... } is known as a function expression. The variable will be assigned that anonymous function at execution time, though its variable declaration will be hoisted to the top of the current execution context (scope).
However, a function expression can be given a name too, so that it can be called within its body to make it recursive. Keep in mind IE has some issues with this. When you assign it a name, it is most definitely not an anonymous function.
A function such as function abc() { ... } is known as a function declaration. Its definition is hoisted to the top of its scope. Its name is available within it and its parent's scope.
Further Reading.
Your Example
It is an anonymous function, but assigned to the variable sayHi.
As Šime Vidas mentions, a new Function object is instantiated with the new operator, and the arguments and function body are passed in as strings. The resulting object is assigned to sayHi.
The real world use of creating a function using this method is rare (though it may be just to help show that functions are objects). I also believe passing its arguments list and function body as a string will invoke an eval() type function, which is rarely good when a much better construct is available.
Also, functions created with Function do not form a closure.
I would only use this method if for some reason I needed to create a Function with its arguments and/or body only available to me as a string.
In the real world, you'd do...
var sayHi = function(toWhom) {
alert('Hi' + toWhom);
};
Also refer to comments by Felix and Šime for good discussion and further clarification.
I think a broader and more accepted definition of an anonymous function is a function that is created without a name.
An anonymous function is simply a function with no name.
function(a, b){
return a + b;
}
The above code would be useless as it has no name to which you could call it with. So they are usually assigned to a variable.
var func = function(a, b){
return a + b;
}
This is helpful because you can pass an anonymous function to another function or method without having to create the function before hand, as demonstrated below.
function bob(a){
alert(a());
}
bob(function(){
return 10*10;
})
This:
new Function("toWhom", "alert('Hi' + toWhom);")
and this:
function(toWhom) { alert('Hi' + toWhom); }
are two expressions that produce the same result - they return a new anonymous function object.
The second expression (and only the second expression) is called a function expression. You may also call it a function literal (although we could argue that a function declaration is also a function literal).
function foo(){
alert("i'm foo, nice to meet you!");
}
var bar = function(){
alert("I am an anonymous function assigned to the variable \"bar\"");
}