The value of this
in JavaScript does not depend on the object in which the function is created. It is determined during the call .
Any function can have this in itself.
It does not matter whether it is declared in or outside the object.
The value of this
is called the context of the call and will be determined at the time of the function call.
For example: this function is quite acceptable:
alert( this .firstName ); |
This function does not yet know what this
will be. This will become clear when you run the program.
There are several rules by which JavaScript sets this
.
Calling a function with new
When calling a function with new
, the value of this
is the newly created object. We have already discussed this in the section on creating objects.
Call in the context of the object
The most common case is when a function is declared in an object or assigned to it, as in the example below:
When calling a function as an object method , through a dot or square brackets, the function gets this object in this
. In this case, user.sayHi()
assign this = user
.
If the same function is run in the context of different objects, it will receive a different this
:
The value of this
does not depend on how the function was created, it is determined exclusively at the time of the call.
Normal mode call
If the function uses this
- this implies working with the object. But a direct call to func()
technically possible.
As a rule, this situation occurs when an error in development.
In doing so, this
gets the value of window
, a global object .
In the modern standard of language, this behavior is changed, instead of the global object this
will be undefined
.
... But by default browsers behave in the old way.
Explicitly indicating this: apply and call
The function can be called by explicitly specifying the value of this
.
To do this, it has two methods: call
and apply
.
call
method
call
method syntax:
func.call(context, arg1, arg2,...) |
In this case, the func
function is called, the first call
argument becomes its this
, and the rest are passed "as is".
A call to func.call(context, a, b...)
is the same as a normal call to func(a, b...)
, but with an explicitly specified context
.
For example, the function showName
in the example below is called via call
in the context of the user
object:
You can make it more universal by adding arguments:
Here, the getName
function getName
called with the context this = user
and prints user['firstName']
and user['surname']
.
apply
method
The call
method rigidly records the number of arguments, separated by commas:
f.call(context, 1, 2, 3); |
.. But what if we want to call a function with four arguments? But what if the number of arguments is not known in advance, and is determined at runtime?
To solve this problem, there is a method apply
.
Calling a function with func.apply
works like func.call
, but takes an array of arguments instead of a list:
func.call(context, arg1, arg2...) |
func.apply(context, [arg1, arg2 ... ]); |
These two lines work the same way:
getName.call(user, 'firstName' , 'surname' ); |
getName.apply(user, [ 'firstName' , 'surname' ]); |
The apply
method is much more powerful than call
, since you can form an array of arguments dynamically:
2 | args.push( 'firstName' ); |
3 | args.push( 'surname' ); |
5 | func.apply(user, args); |
When specifying the first argument null
or undefined
in call/apply
, the function gets this = window
:
This behavior is corrected in the modern standard (15.3).
If the function works in strict mode, then this
passed "as is":
"Lending method"
With call/apply
you can easily take the method of one object, including the built-in one, and call it in the context of another.
In JavaScript, object methods, even embedded ones, are functions. Therefore, you can copy a function, even a built-in function, from one object to another.
This is called “method borrowing” (in English method borrowing ).
We use this technique to simplify the manipulation of arguments
. As we know, this is not an array, but an ordinary object .. But I would like to call on it array methods.
In line (1)
created an array. It has the [].join(..)
method, but we do not call it, but copy it, like any other property into the arguments
object. In line (2)
launched it, as if he was always there.
Here the join method of the array is copied and called in the context of arguments
. Will something bad happen because arguments
are not an array? Why did he work at all?
The answer to these questions is simple. In accordance with the specification, inside the join
implemented like this:
01 | function join(separator) { |
02 | if (! this .length) return '' ; |
06 | for ( var i = 1; i< this .length; i++) { |
07 | str += separator + this [i]; |
As you can see, this
, numeric indices and the length
property are used. If these properties are there, then everything is fine. And nothing more is needed. Even a regular object fits:
... However, direct copying of the method is not always acceptable.
Imagine for a moment that instead of arguments
, we have an arbitrary object, and we want to call the method [].join
in its context. Copying this method, as we did above, is dangerous: what if an object has its own join
? We will rewrite, and then something will break ..
For a safe call, use apply/call
:
We called the method without copying. Clean, safe.
Making arguments
real Array
JavaScript has a very simple way to make a real array of arguments
. To do this, take the array method: arr.slice (start, end).
According to the standard, it copies a part of the arr
array from start
to end
into a new array. And if start
and end
not specified, it copies the entire array.
Call it in the context of arguments
:
As in the case of join
, such a call is possible because slice
uses only numbered properties and length
from an array. All this is in the arguments
.
Call apply
through apply
With the help of apply
we can make a universal "redirect" call from one function to another.
For example, the function f
calls g
in the same context, with the same arguments:
g.apply( this , arguments); |
The advantage of this approach is that it is completely universal:
- You will not need to change it if new arguments are added to
f
. - If
f
is an object method, then the current context will also be passed. If it isn’t, then this
here seems to have nothing to do with it, but there will be no harm from it either.
Importance: 5
[Open task in new window]
Importance: 3
- Normal function call in the context of the object.
- The same, brackets do not affect anything.
- Here is not just a call to
obj.method()
, but a more complex call of the form (выражение).method()
. Such a call works as if it were split into two lines: In this case, f()
is executed as a normal function, without passing this
. - There is also an expression to the left of the point, the call is similar to two lines.
The specification explains this with a special internal type, the Reference Type.
If more - then obj.go()
consists of two operations:
- First get the property
obj.go
- Then call it as a function.
But where does step 2 get this
? Just for this, the operation of obtaining the obj.go
property returns the value of a special Reference Type
, which in addition to the go
property contains information about obj
. Further, in the second step, calling it with the help of brackets ()
correctly sets this
.
Any other operations, besides the call, turn the Reference Type
into a normal type, in this case, the go
function (so this type is arranged).
Therefore, it turns out that (a = obj.go)
assigns to the variable a
function go
, already without any information about the object obj
.
The situation is similar in case (4)
: the OR operator ||
makes the Reference Type
ordinary function.
[Open task in new window]
Importance: 2
Error !
Try:
And the error message is very strange . In most browsers, this is obj is undefined
.
The point, oddly enough, is not in the declaration of obj
, but in the fact that a semicolon is missing after it.
JavaScript ignores line (obj.go || ..)
before parentheses (obj.go || ..)
and reads this code as:
var obj = { go:... }(obj.go || 0)() |
The interpreter will attempt to evaluate this expression, which denotes a call to the { go: ... }
object as a function with an argument (obj.go || 0)
. In this case, of course, an error will occur.
And what will happen if you add a semicolon?
2 | go: function () { alert( this ); } ); } |
Will everything be alright? What will be the result?
The result is a window
, because calling obj.go || 0
obj.go || 0
similar to the code:
[Open task in new window]
Importance: 5
The call arr[2]()
is a call to the object method obj[method]()
, the role of obj
is arr
, and the role of the method is: 2
.
Therefore, as is the case when calling a function as a method, the function arr[2]
will get this = arr
and output an array:
[Open task in new window]
Total
The value of this
set depending on how the function is called:
- When calling a function as a method
- With a normal call
- In
new
- Explicit indication
func.call(ctx, arg1, arg2, ...) |
Comments
To leave a comment
Scripting client side JavaScript, jqvery, BackBone
Terms: Scripting client side JavaScript, jqvery, BackBone