9

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

Javascript 可以使用:和.设置上下文(即 set this) 。bindcallapply

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

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

谁/什么实际上依附于 this自身object

PS 使用 jQuery 时:

  $("#myInput").bind(function (){...})

( ,或)有一个内部实现bindcallapply

那么当我使用 jQuery 时,谁在做呢?

4

7 回答 7

8

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

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

来源

这究竟是如何发生的,我们不知道。这是一个实现细节。

我们所知道的是,W3C 定义的语义是以某种方式实现的,但是浏览器的哪个部分执行该操作以及如何执行该操作,这取决于浏览器开发人员,他们可以按照他们认为合适的方式实现它。

于 2012-10-04T08:08:20.947 回答
2

总结所有讨论:

  • 一般来说,当被调用时,它是绑定thiso函数调用内部的JavaScript o.x()
  • 但是,有一些调用函数的替代方法(如f.apply()f.call())可以改变这种行为。
  • onclick是一种特殊情况,用于调用它的方法是未知的,并且取决于 DOM 实现。
于 2012-10-04T08:55:20.037 回答
1

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

简而言之,函数执行的上下文与创建的上下文相同(再次:在您的示例中作为 DOM 元素的方法),除非对函数对象的引用分配给另一个对象,或者当使用or & co在另一个上下文中调用该函数对象时。当然,还有比这更多的东西:正如我在上面所暗示的,函数本身就是对象,据说与它们的“所有者”松散耦合。好吧,实际上他们没有这样的所有者,每次调用函数时,都会确定其上下文:callapply

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(){}时,我们看到该元素仅拥有对在某个范围内声明的函数表达式的引用(全局,命名空间对象,无关紧要)。当 click 事件触发时,该引用将用于调用处理程序,从而将对该元素的引用分配给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

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

我确实希望这能消除我在函数所有权方面造成的任何混淆,以及 JS 中的上下文是如何确定的。

于 2012-10-04T08:11:12.847 回答
1

说它是 DOM 的答案是错误的。

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

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

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

如果你想从实现的角度来考虑它,可以这样想:每当你调用一个方法时,你首先告诉一个实例你想调用一个带有 N 个参数的方法。此实例调用该方法,但将其自身添加到上下文中,如“this”。

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

请记住,实例拥有该方法。当您执行“document.getElementById('something')”时,调用会返回一个对象(它恰好是一个 HTMLElement 对象,它是 DOM 的一部分,但这与 JS 与 DOM 交互的方式是巧合的),然后您正在分配作为属性单击的功能。

然后,每当您调用该方法时,JavaScript 引擎默认传递该实例,就像它传递其他变量一样(如参数也无需您执行任何操作即可生成,也是由实现 ECMAScript 标准的 JS 引擎完成的)。

我建议检查第 63 页:

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

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

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

于 2012-10-04T08:17:02.077 回答
0

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

以此为例:

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

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

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

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

于 2012-10-04T08:12:33.897 回答
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
于 2012-10-04T08:13:25.800 回答
0

出于说明目的,尽管实现可能不同,但请考虑以下函数

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

作为

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 函数时,浏览器将“秘密”这个参数设置为调用函数。在下面的示例中,这是 b,因此“Tom”被打印到控制台。

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

更多信息在这里

于 2012-10-04T08:17:13.520 回答