jsの中の奇妙なthisの針

12386 ワード

この文章は問題をはっきり言えるかもしれない.http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/ :
Understanding JavaScript Function Invocation and「this」
August 11 th、2011
Over the years,I’ve seen a lot of confusion about JavaScript function invocation.In particular,a lot of people have compland that the semantics of`this`in function inctions confusing.
In my opinion,a lot of this confusion is cleared up byundededestanding the coree function invocation prmitive,and then looking aaaaaaaaaah aaaaaaaaaaaaaaaattthethethethethe aaaaaaaaaaaaaaaattttthethererererereisisisisisisisisisisisisisisaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaathethethethethethethethethethethethetheec,but the baic idea is the same.
The Core Primitive
First,let’s look at the core function invocation prmitive,a Function’s コール method[1].The call method is relatively straigh forward.
  • Make an argment list(argList)out of parameters 1 through the end
  • The first parameter is thisValue
  • Invoke the function with this set to thisValue and the argList as its argment list
  • For example:
    function hello(thing) { console.log(this + " says hello " + thing); }  
    hello.call("Yehuda", "world") //=> Yehuda says hello world
    As you can see,we invoked the ハロー method with this set to 「Yehuda」 and a single argment 「world」.This is the core prinmitive of JavaScript function invocation.You can think of all other function cals as desugaring to this prmitive.(to「desugar」is to to to to to to inventient syntax and describe in it of prive of morive.)
    [1]In the ES 5 spec,the コール method is described in terms of another,more low level prmitive,but it’s a very thin wrapper on top of that prmitive,so I’m simplifying a bit here.See the end of this post for more information.
    Simple Function Invocation
    Obviously,invoking functionwith コール all the time would be pretty annoying.JavaScript allows s to invoke functions directly using the parens sntax(hello(world).When we do that,the invocation desugars:
    function hello(thing) { console.log("Hello " + thing); }   // this: hello("world")   // desugars to: hello.call(window, "world");
    This behavior has changed in ECMAScript 5 only when using strict mode[2]:
    // this: hello("world")   // desugars to: hello.call(undefined, "world");
    The shart version is: a function invocation like fn(…args) is the same asfn.call(window[ES 5-strict:undefined],...args)
    Note that this also true about functions declead inline: (function(){}() is the same as(function(){}.call(window[ES 5-strict:undefined].
    [2]Actualy,I lied a bit.The ECMAScript 5 spec says that undefined is(almost)always passed,but that the function being called Shuld change its thisValue to the global object when not in strict mode.This allows street mode calers to avoid breking existing non-strict-mode libries.
    メンバーFunctions
    The next very common way to invoke a method is as a member of an object(person.hello).In this case,the invocation desugars:
    var person = { name: "Brendan Eich", hello: function(thing) { console.log(this + " says hello " + thing); } }   // this: person.hello("world")   // desugars to this: person.hello.call(person, "world");
    Note that it doesn't mater how the ハロー method becompes atached to the object in this form.Remember that we previously defined ハロー a s a standowlone function.Let's see what happens if we atach is to the object dynamically:
    function hello(thing) { console.log(this + " says hello " + thing); }  
    person = { name: "Brendan Eich" } person.hello = hello;  
    person.hello("world") // still desugars to person.hello.call(person, "world")  
    hello("world") // "[object DOMWindow]world"
    Notice that the function doesn't have a persistent notion of its'this'.It is always set cal time based up on the way it invoked by caler.
    Using Function.prototype.bind
    Because it can sometimes be convent to have a reference to a function with a persistent thisvalue、people have historiclyused a simple closure trick to convert a function into one with an unchange ging this:
    var person = { name: "Brendan Eich", hello: function(thing) { console.log(this.name + " says hello " + thing); } }   var boundHello = function(thing) { return person.hello.call(person, thing); }  
    boundHello("world");
    Even though our boundHello call still desugars to boundHello.call(window,「world」)、we turn right around and use our prmitive コール method to change the this value back to what we want it to be.
    We can make this trick general-purpose with a few tweaks:
    var bind = function(func, thisValue) { return function() { return func.apply(thisValue, arguments); } }   var boundHello = bind(person.hello, person); boundHello("world") // "Brendan Eich says hello world"
    In order to understand this,you just need two more pieces of information.First, アーグメンント is an Aray-like object that represents all of the argments passed into a function.Second,the appymethod works exactly like the コール prmitive、except that it Taes an Aray-like offect instead of listing the argments out one at.
    Our ビッド method simply returns a new function.When it is invoked,our new function simply invokes the origginal function that was passed in,setting the orial value as this.It also passes through the argments.
    Because this was a somewhat comon idiom,ES 5 introdced a new method ビッド on all Function object s that implement s this behavior:
    var boundHello = person.hello.bind(person); boundHello("world") // "Brendan Eich says hello world"
    This is most useful when you need a raw function to pass as a calback:
    var person = { name: "Alex Russell", hello: function() { console.log(this.name + " says hello world"); } }  
    $("#some-div").click(person.hello.bind(person));   // when the div is clicked, "Alex Russell says hello world" is printed
    This、of course、somewhat clunky、and TC 39(the comittee that work s on the next version(s)of ECMAScript)contiues to work on a more elegant、still-backwards-comptible solution.
    On jQuery
    Because jQuery makes such heavy use of anonymous calback functions,it uses the calmethod internally to set the this value of those calbacks to a more useful value.For instance、instead of receiving window as this in all event handles(as you would without special intervent)、jQuery invokes コール オンザロックwith the element that set up the event handler as its first parameter.
    This is extremely usful,because the default value of this in onymous calbacks is not particularly useful、but it can give beginers to JavaScript the impression that this is in generala strange、oten mutted concept that is hard to reason about.
    If you understand the baic rules for converting a sugary function call into a desugaredfunc.call(this Value,…args)は、you shuld be able to navigate the not so treacherous waters of the JavaScript this value.
    this-table.png
    PS:I Cheated
    In several places,I simplified the reality a bit from the exact wording of the specification.Probably the most importchat the is the way I caled func.call a「prmitive」.In reality,the spec has a prmitive(internally referred to as) [[Call])that both func.call and [obj.]func() アメリカ.
    However,take a look at the definition of func.call:
  • If IsCallable is false,then throw a TypeErr exception.
  • Let argList be an empty List.
  • If this method was caled with more than one argment then left to right order starting with arg 1 apend each argment as the last element of argList
  • Return the result of caling the[Call]internal method of func,providing thisArg as the this value and argList as the list of argments.
  • As you can see,this definition is esentially a very simple JavaScript langage binding to the prmitive [[カル]] operation.
    If you look at the definition of invoking a function、the first seven steps set up thisValue and argList,and the last step is:"Return the result of caling the[Call]internal method on func,providing this Value as the this value and providing the list argList the argList the argvalues."
    It's esentially identical wording,onece the argList and thisValue have been determined.
    I chated a bit in caling コール a prmitive、but the meaning is esentially the same as had I pulled out the spect the beginning of this artile and quot ted chapter and verse.
    The re are also some additional cases(most notably involving) with)that I didn't cover here.
    This entry was posted on Thursday、August 11 th、2011 at 2:54 am and is filed under JavaScript.You can follow any reponses to this entry through the RSS 2.0 feed.You can skyp to the end and leave a reponse.Pinging is currently not allowed.