This, call (), apply (), bind () of JavaScript ()

Source: Internet
Author: User
Document directory
  • Complications

To create a scope chain, this keyword is provided for every JavaScript code execution context. In its most common usage,this
Serves as an identity function, providing our neighborhoods a way
Referring to themselves. We can't always rely on that behavior,
However: Depending on how we get into a particle neighborhood,thisMight mean something else entirely. In fact,How we get into the neighborhoodIs itself exactly whatthisGenerally refers to. Pay attention to four special situations:

  • Calling an Object's Method

    In typical object-oriented programming, we need a way to point to and reference the objects we call.thisServes the purpose admirably, providing our objects the ability to examine themselves, and point at their own properties.

     var deep_thought = {<br /> the_answer: 42,<br /> ask_question: function () {<br /> return this.the_answer;<br /> }<br /> };</p><p> var the_meaning = deep_thought.ask_question(); 

    This example builds an object nameddeep_thought, Sets itsthe_answerProperty to 42, and createsask_questionMethod. Whendeep_thought.ask_question()Is executed, JavaScript establishes an execution context for the function call, settingthisTo the object referenced by whatever came before the last ".", in this case:deep_thought. The method can then look in the mirrorthisTo examine its own properties, returning the value stored inthis.the_answer: 42.

  • Constructor

    Likewise, when defining a function to be used as a constructor withnewKeyword,thisCan be used to refer to the object being created. Let's rewrite the example abve to reflect that scenario:

     <mce:script type="text/javascript"><!--<br /> function BigComputer(answer) {<br /> this.the_answer = answer;<br /> this.ask_question = function () {<br /> return this.the_answer;<br /> }<br /> }</p><p> var deep_thought = new BigComputer(42);<br /> var the_meaning = deep_thought.ask_question();</p><p>// --></mce:script>

    Instead of explicitly creatingdeep_thoughtObject, we'll write a function to createBigComputerObjects, andInstantiate deep_thoughtAs an instance variable vianewKeyword. Whennew BigComputer()Is executed, a completely new object is created transparently in the background.BigComputerIs called, and itsthisKeyword is set to reference that new object. The function can set properties and methods onthis, Which is transparently returned at the endBigComputer'S execution.

    Notice, though, thatdeep_thought.the_question()Still works just as it did before. What's going on there? Why doesthisMean something different insidethe_questionThan it does insideBigComputer? Put simply, weEntered BigComputerVianew, SothisMeant "the new object." On the other hand, weEntered the_questionViadeep_thought, So while we're re executing that method,thisMeans "whateverdeep_thoughtRefers ".thisIs not read from the scope chain as other variables are, but instead isResetOn a context by context basis.

  • Function Call

    What if we just call a normal, everyday function without any of this fancy object stuff? What doesthisMean in that scenario?<Mce: script type = "text/javascript"> <! -- <Br/> function test_this () {<br/> return this; <br/>}< br/> var I _wonder_what_this_is = test_this (); </p> <p> // --> </mce: script>

     

    In this case, we weren't provided a contextnew, Nor were we given a context in the form of an object to piggyback off of. Here,thisDefaults to reference the most global thing it can: for web pages, this iswindowObject.

  • Event Handler

    For a more complicated twist on the normal function call, let's say that we're using a function to handleonclickEvent. What doesthisMean when the event triggers our function's execution? Unfortunately, there's not a simple answer to this question.

    If we write the event handler inline,thisRefers to the globalwindowObject:

      <mce:script type="text/javascript"><!--<br /> function click_handler() {<br /> alert(this); // alerts the window object<br /> }</p><p>// --></mce:script> 
     ...
     <button id='thebutton' onclick='click_handler()'>Click me!</button> 

    However, when we add an event handler via JavaScript,this
    Refers to the DOM element that generated the event. (Note: The event
    Handling shown here is short and readable, but otherwise poor. Please
    Use a real addEvent function instead .):

     <script type="text/javascript">
      <mce:script type="text/javascript"><!--<br /> function click_handler() {<br /> alert(this); // alerts the button DOM node<br /> }</p><p> function addhandler() {<br /> document.getElementById('thebutton').onclick = click_handler;<br /> }</p><p> window.onload = addhandler;</p><p>// --></mce:script> 
     ...
     <button id='thebutton'>Click me!</button> 

Complications

Let's run with that last example for a moment longer. What if instead of runningclick_handler, We wanted to askdeep_thoughtA question every time we clicked the button? The code for that seems pretty straightforward; we might try this:

<mce:script type="text/javascript"><!--<br /> function BigComputer(answer) {<br /> this.the_answer = answer;<br /> this.ask_question = function () {<br /> alert(this.the_answer);<br /> }<br /> }</p><p> function addhandler() {<br /> var deep_thought = new BigComputer(42),<br /> the_button = document.getElementById('thebutton');</p><p> the_button.onclick = deep_thought.ask_question;<br /> }</p><p> window.onload = addhandler;<br />// --></mce:script> 

In the above Code, we expect to click the button,Deep_thought.ask_question is executed. We get the returned result."42." But why is the opposite?Undefined? Where is the error??

The problem is simply this: We 've passed off a reference toask_question
Method, which, when executed as an event handler, runs in a different
Context than when it's executed as an object method. In short, the this keyword in ask_question directs to the DOM element node that generates the event, insteadBigComputer object. DOM element node does not existThe_answer attribute, so the returned result isUndefined instead"42 ."setTimeoutExhibits similar behavior, delaying the execution of a function while at the same time moving it out into a global context.

This issue crops up all over the place in our programs, and it's
Terribly difficult problem to debug without keeping careful track
What's going on in all the corners of your program, especially if your
Object has properties thatDoExist on DOM elements orwindowObject.

Manipulating Context .apply()And .call()

We reallyDoWant to be able to askdeep_thoughtA question when we click the button, and more generally, weDoWant to be able to call object methods in their native context when responding to things like events andsetTimeoutCILS. Two little-known JavaScript methods,applyAndcall, Indirectly enable this functionality by allowing us to manually override the default valuethisWhen we execute a function call. Let's lookcallFirst:

<mce:script type="text/javascript"><!--<br /> var first_object = {<br /> num: 42<br /> };<br /> var second_object = {<br /> num: 24<br /> };</p><p> function multiply(mult) {<br /> return this.num * mult;<br /> }</p><p> multiply.call(first_object, 5); // returns 42 * 5<br /> multiply.call(second_object, 5); // returns 24 * 5<br />// --></mce:script> 

In this example, we first define two objects,first_objectAndsecond_object, Each withnumProperty. Then we definemultiplyFunction that accepts a single argument, and returns the product of that argument, andnumProperty of itsthisObject. If we called that function by itself, the answer returned wowould almost certainly beundefined, Since the globalwindowObject doesn' t havenumProperty unless we explicitly set one. We need some way of tellingmultiplyWhat itsthisKeyword ought refer to;callMethod ofmultiplyFunction is exactly what we're re looking.

 The first parameter of the call method defines the direction and object of the this keyword in the execution context of the called method. The remaining parameter of the call method is the parameter of the called method. Therefore, whenMultiply. call (first_object, 5) is executed, The multiply function is called.,5Is the first parameter of the input method,thisRunThe first_object object.Likewise, whenmultiply.call(second_object, 5)Is executed,multiplyFunction is called,5Is passed in as the first argument, andthisKeyword is set to refer to objectsecond_object.

Apply method and The call methods are basically the same.But you can pass parameters to the called function in the form of arrays,
Which can be quite useful when programatically generating function
CILS. Replicating the functionality we just talked about usingapplyIs trivial:

<mce:script type="text/javascript"><!--<br /> ...</p><p> multiply.apply(first_object, [5]); // returns 42 * 5<br /> multiply.apply(second_object, [5]); // returns 24 * 5<br />// --></mce:script> 

applyAndcallAre very useful on their
Own, and well worth keeping around und in your toolkit, but they only get
Us halfway to solving the problem of context shifts for event handlers.
It's easy to think that we cocould solve the problem by simply usingcallTo shift the meaningthisWhen we set up the handler:

function addhandler() {<br /> var deep_thought = new BigComputer(42),<br /> the_button = document.getElementById('thebutton');</p><p> the_button.onclick = deep_thought.ask_question.call(deep_thought);<br />} 

The above code still has problems:Call is to execute the function immediately, so we provide onclickHandler is the execution result of the function rather than the function itself. We need another feature of JavaScript to solve this problem: bind method.

The Beauty .bind()

I'm notHugeFan of the Prototype JavaScript framework, but I am very much impressed with the quality of its code as a whole. In particle, one simple addition it makes toFunctionObject has had a hugely positive impact on my ability to manage the context in which function CILS execute:bindPerforms the same general taskcall, Altering the context in which a function executes. The difference is thatbindReturns a function reference that can be used later, rather than the result of an immediate execution that we getcall.

If we simplifybindFunction a bit to get at
Key concepts, we can insert it into the multiplication example we
Discussed earlier to really dig into how it works; it's quite
Elegant solution:

<mce:script type="text/javascript"><!--<br /> var first_object = {<br /> num: 42<br /> };<br /> var second_object = {<br /> num: 24<br /> };</p><p> function multiply(mult) {<br /> return this.num * mult;<br /> }</p><p> Function.prototype.bind = function(obj) {<br /> var method = this,<br /> temp = function() {<br /> return method.apply(obj, arguments);<br /> };</p><p> return temp;<br /> }</p><p> var first_multiply = multiply.bind(first_object);<br /> first_multiply(5); // returns 42 * 5</p><p> var second_multiply = multiply.bind(second_object);<br /> second_multiply(5); // returns 24 * 5<br />// --></mce:script> 

First, we definefirst_object,second_object, AndmultiplyFunction, just as before. With those taken care of, we move on to creatingbindMethod onFunctionObject'sprototype, Which has the effect of makingbindAvailable for all functions in our program. Whenmultiply.bind(first_object)Is called, JavaScript creates an execution context forbindMethod, settingthisTomultiplyFunction, and setting the first argument,obj, To referencefirst_object. So far, so good.

The real genius of this solution is the creationmethod, Set equalthis(multiplyFunction itself). When the anonymous function is created on the next line,methodIs accessible via its scope chain, as isobj(thisCouldn't be used here, because when the newly created function is executed,thisWill be overwritten by a new, local context). This aliasthisMakes it possible to useapplyTo executemultiplyFunction, passing inobjTo ensure that the context is set correctly. In computer-science-speak,tempIsClosureThat, when returned at the end ofbindCall, can be used in any context whatsoever to executemultiplyIn the contextfirst_object.

This is exactly what we need for the event handler andsetTimeoutScenarios discussed above. The following code solves that problem completely, bindingdeep_thought.ask_questionMethod todeep_thoughtContext, so that it executes correctly whenever the event is triggered:

function addhandler() {<br /> var deep_thought = new BigComputer(42),<br /> the_button = document.getElementById('thebutton');</p><p> the_button.onclick = deep_thought.ask_question.bind(deep_thought);<br />} 

Beautiful.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.