JavaScript如何为事件处理程序分配上下文?

时间:2012-10-04 07:58:55

标签: javascript jquery

阅读相关问题后#1#2 我仍然没有找到以下问题的答案:

Javascript可以设置上下文(即设置this):bindcallapply

但是当我写一个事件处理程序时:

document.getElementById('myInput').onclick = function ()
                                                   {
                                                      alert(this.value)
                                                   }

<{em> this

P.S。使用jQuery的时候:

object

$("#myInput").bind(function (){...}) bindcall)的内部实现

所以当我使用jQuery时,谁在做呢?

7 个答案:

答案 0 :(得分:8)

为什么,DOM / JavaScript当然应该由W3C以这种方式工作。

  

事件处理程序在特定对象(当前事件目标)的 context 中调用,并随事件对象本身提供。

Source

究竟是怎么回事,我们不知道。这是一个实现细节。

我们所知道的是,W3C定义的语义是以某种方式实现的,但是浏览器的哪个部分实现了这个以及如何,这取决于浏览器开发人员,他们可以按照自己的意愿实施。

答案 1 :(得分:2)

总结所有讨论:

  • 通常,当调用this时,JavaScript会在函数调用中将o绑定到o.x()
  • 但是,有一些替代方法可以调用函数(例如f.apply()f.call())来改变这种行为。
  • onclick是一种特殊情况,用于调用它的方法是未知的,取决于DOM的实现。

答案 2 :(得分:1)

在您的示例中,onclick处理程序非常简单:DOM元素对象,您将onclick属性定义为函数。该函数有效地成为DOMElement / object的一个方法。
当单击该对象时,该函数被调用为该元素的方法,因此这指向其所有者元素。

简单地说,函数执行的上下文与创建的上下文相同(再次:在您的示例中作为DOM元素的方法),除非对函数 object <的引用/ em>被分配给另一个对象,或者在使用callapply&amp;的另一个上下文中调用该函数 object 时当然,除此之外还有更多内容:正如我在上面暗示的那样,函数本身就是对象,据说松散耦合到“owner” 。好吧,实际上他们并没有这样的拥有者,每次调用一个函数时,都会确定其上下文:

var foo = someObject.someFunction;//reference to method
someObject.someFunction();//this === someObject, context is the object preceding the function
foo();//implies [window].foo(); ==> this is window, except for strict mode

正如@wroniasty指出的那样,我谈论所有权可能会有些混乱。问题是,函数是对象,它们不属于任何东西。为对象分配方法时,所有拥有的对象都是对给定函数对象的引用。当通过该引用调用该函数时,this将指向拥有调用引用的对象。
当我们将它应用于elem.onclick = function(){}时,我们看到元素只有拥有对在某个范围内声明的函数表达式的引用(global,namespace-object,doesn'无所谓)。触发click事件时,将使用 reference 来调用处理程序,从而将对元素的引用分配给this。澄清:

document.getElementById('foo').onclick = (function()
{//This function returns the actual handler
    var that = this;//closure var
    console.log(this);//logs window object
    //defined in global context
    return function(e)//actual handler
    {
        console.log(this === that);//false
        console.log(this);//elem
        console.log(that);//window
    };
})();//IIFE

因此处理程序是在全局上下文中声明的,并且处理程序可以使用that访问它使用onclick声明的上下文,这要归功于闭包(但这是另一个故事)。关键是,事件使用元素foo的{​​{1}}属性引用处理程序。该属性是对函数对象的引用,因此函数对象将其上下文设置为调用的任何对象。

我希望这可以解决我对函数的所有权造成的任何混淆,也许可以确定JS中的上下文是如何确定的。

答案 3 :(得分:1)

答案是说DOM是错误的。

这是JavaScript本身的一部分,作为一种语言。 DOM只是名称表示“文档对象模型”的东西,它就是如何使用JavaScript表示HTML进行操作。与DOM相关的对象遵循标准指定的行为,但这是通过使用JS实现的。这是JS引擎,它与正在使用的任何布局引擎(Gecko,Trident,WebKit,Presto等)进行通信。因此,如果WebKit检测到一个事件,它会将其传递给JS引擎,因为DOM规范指示它可以由JS程序员操纵(这就是为什么你甚至会问这个问题,因为你可以使用它)。 / p>

换句话说,如果你是用JavaScript编写的东西,唯一能理解如何读取和执行的引擎就是JS引擎。该引擎(v8,SpiderMonkey / Jugger / Trace)将从布局引擎接收数据并使用它,以便您可以与它进行交互。同样,另一方面,每当您运行影响布局的代码时,布局引擎都会检测到更改,并且它将更改布局以便用户察觉到更改:即使JS代码可能已启动此更改,是负责布局的布局引擎。

将函数分配给对象时,“this”是什么,只是函数所属的位置。因此,如果您将一个函数分配给对象a的实例,那么只要您在其中使用“this”,所述函数就会引用该函数。

如果您想在实施术语中考虑它,请以这种方式考虑它: 无论何时调用方法,都要首先告诉实例要调用具有N个参数的方法。此实例调用该方法,但将其自身添加到上下文中,如“this”。

在Python中,通过将所有实例方法的第一个参数作为实例本身来更明确地完成。这里是相同的,但实例是隐式传递而不是显式传递。

请记住,实例拥有该方法。当你执行“document.getElementById('something')”时,调用会返回一个对象(碰巧是一个属于DOM的HTMLElement对象,但这与JS与DOM交互的方式一致),然后你要分配该功能作为属性点击。

然后,每当你调用该方法时,JavaScript引擎默认传递实例,就像它传递其他变量一样(如同参数也是在没有你做任何事情的情况下生成的,也是由实现ECMAScript标准的JS引擎完成的)。

我建议检查第63页:

“this关键字计算为当前执行上下文的ThisBinding的值。”

但最重要的是,第68页“函数调用”

http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf

答案 4 :(得分:0)

这实际上与已经提到的DOM无关,但是当你在一个对象中调用一个函数时,JavaScript是如何设计的。

以此为例:

var myObject = {
    id: 1,
    onclick: null
}

myObject.onclick = function() {
    console.log(this.id);
}

调用myObject.onclick()会将1记录到控制台,这意味着myObject是其上下文。

由于onclick也是对象的属性,因此this将是父对象,在您的情况下为HTMLElement

答案 5 :(得分:0)

http://dmitrysoshnikov.com/ecmascript/chapter-3-this/#this-value-in-the-function-code

基本上,它是由JavaScript内部人员完成的。

上下文是调用函数的对象,例如

elem.onclick();  // elem === this

然而:

func = elem.onclick;
func() // global === this

答案 6 :(得分:0)

为了便于说明,尽管实现可能不同,但请考虑以下函数

 function f() { alert(this.name); } 

as

function f(this) { alert(this.name); } 

想象一下这个作为一个秘密参数,您可以使用bind,apply和call覆盖它,但通常会被浏览器设置为调用对象。

实施例

var a = {},
    b = {};

a.name = "John";
b.name = "Tom";

// "this" param added secretly
function printName( ) { 
    console.log( this.name ) 
};

a.printName = printName     
b.printName = printName;

当调用printName函数时,浏览器会将“secret” this 参数设置为调用函数。在下面的示例中,这是b,因此“Tom”将打印到控制台。

printName( ); // global context assumed so this === window
b.printName( ); // this === b and outputs "Tom"
printName.call( a ); //this === a and outputs "John"

更多信息here