【问题标题】:"onclick" and "this" in javascriptjavascript中的“onclick”和“this”
【发布时间】:2019-09-13 02:31:42
【问题描述】:

我很困惑:

  • 为什么用内联onlick,我们必须写onclick="hello()",但是在JS中,我们应该写btn.onclick=hello或者btn.addEventListener('click',hello);

  • 对于常规函数,为什么用inline onlick,“this”是指窗口,而用js调用,“this”是指按钮。

  • 我不明白最后两个按钮

根据 w3school,在函数中,this 指的是全局对象。 https://www.w3schools.com/js/js_this.asp

在常规函数中,this 关键字表示调用函数的对象,可以是窗口、文档、按钮或其他任何东西。 https://www.w3schools.com/js/js_arrow_function.asp

const arrayBtn = document.querySelector(".arrowFunc");
const regBtn = document.querySelector(".regFunc");
hello = () => console.log("i am arrow function" + this);
function hiii(){
  console.log("i am regular function" + this);
}
arrayBtn.addEventListener("click", hello);
regBtn.addEventListener("click", hiii);
<button onclick="hello()">This calls an arrow function with an inline onclick</button>
<button class="arrowFunc">This calls an arrow function with event listener</button>
<button onclick="hiii()">This calls an regular function with an inline onclick</button>
<button class="regFunc">This calls an regular function with event listener</button>
<button onclick="function tes(){console.log(this)}tes()">button</button>
<button onclick="console.log(this)">button</button>
[Log] i am arrow function[object Window] <br>
[Log] i am arrow function[object Window] <br>
[Log] i am regular function[object Window] <br>
[Log] i am regular function[object HTMLButtonElement] <br>
[Log] Window {document: #document, window: Window, NaN: NaN, nalert: function, obj: {name: "my_obj"}, …} <br>
[Log] <button onclick="console.log(this)">button</button>

【问题讨论】:

  • 即使做了多年的开发人员,我也对此感到困惑!
  • 另外,尝试链接 MDN 而不是 W3Schools 作为来源。它更正式。
  • 了解什么?您已经写了如何解释 this 上下文。 this,在常规函数中,在对象的方法 (function) 内,指的是对象,在事件的情况下是元素。所以分配给Element的onclick的函数就是方法,按钮就是Object。箭头函数内的this 的作用域直到您的最后一个作用域,如果不在类或构造函数内,则为全局。请注意,构造函数是一个函数。它只有在调用new 时才成为对象。

标签: javascript html onclick this onclicklistener


【解决方案1】:

关于this 值。

  1. 箭头函数捕获并始终使用它们的词法this 值,这意味着在评估它们的arrow function expression 时有效的值。评估通常发生在执行赋值操作或计算参数列表中包含箭头函数的函数调用的参数值时。

    • 箭头函数不能用作构造函数。
  2. 使用new(或在扩展类时使用super)作为构造函数调用的非箭头函数将正在构造的对象视为它们的this值。

  3. 绑定函数保存并使用作为第一个参数提供给另一个函数的bind methodthis value

    • 如果调用构造函数,绑定函数会忽略其保存的 this 值 - 但这种情况非常罕见,足以被视为边缘情况,并且是 not generally recommended

    • 绑定箭头函数对其this 值没有影响,但可用于预定义一组参数值。

  4. 使用它们的callapply 对象方法调用的函数从提供给callapply 的(第一个)thisValue 参数获取它们的this 值,受JavaScript 模式约束:

    • 在严格模式下,为thisValue 提供的nullundefined 值用作函数的this 值。但是,在 sloppy mode 中,nullundefined 在拨打电话之前会被 window 替换。

    • 可以使用这些方法调用箭头和绑定函数(例如提供参数),但使用它们自己记录的 this 值。

  5. 如果上述规则均不适用,作为对象方法显式调用的函数将使用对象作为其this 值。

    例如在形式的调用中

    someObject.methodName( optionalArgumentList)
    

    如果方法是常规函数,methodName 中的this 指的是someObject

  6. 在严格模式下,非限定函数调用中this的默认值为undefined。在草率模式下(从首次引入 JavaScript 开始)thiswindow。演示:

function a () {
    "use strict";
    console.log("in strict mode functions the default this is ", this);
};
let b = function() {
    console.log("but in non strict mode,  the default this is ",
        this === window ? "window" : this
    );
}

a(); // undefined
b(); // window
  1. 在调用全局 Function constructorSetTimeout、相关计时器调用和 HTML 源代码中的事件属性时作为文本字符串提供的代码本身被视为“脚本”并创建 一个函数

    • 如果提供的源代码没有调用严格模式,则以草率模式运行,

    • 如果在源中调用了严格模式,则以严格模式运行。

    虽然这会改变函数的 默认 this 值,但这也是一种极端情况,因为在编写可维护代码时,不推荐使用这些创建函数的方法。

  2. 使用eval 评估代码时的this 值不在此问题的范围内,但为了完整性:

    • 直接调用 eval 从调用上下文继承 this,除非评估的代码调用严格模式 - 在这种情况下,this 在代码评估期间是 undefined

    • eval 的间接调用使用window(即全局对象)作为this 即使它们调用严格模式 (Ref.)

    这也是一个边缘情况,因为它很危险,eval 应该是never be used because you can


HTML 中的内联事件处理程序

表单的 HTML 标记中的事件处理程序内容属性

    onEventName="text"

HTML 解析器使用相当于

的步骤转换为事件处理函数
  1. 将文本保存为属性的字符串值。

  2. 使用 JavaScript 解析器/编译器通过将文本包含在表单模板中来从文本创建事件处理函数

    function( event) {
          // include attribute text here as body code
    }
    
  3. 将函数保存为与属性同名的元素的属性。例如。此时,具有onclick 文本属性的元素也将具有onclick 属性,这是一个函数。

  4. 将函数添加到元素的内部event handler map. 实际上,这意味着实际的事件处理使用侦听器映射,而不是在元素上查找处理函数。

警告

  • HTML onEventName 属性早于 DOM 的标准化和 addEventListener 的引入:

    由 HTML 解析器创建的处理程序有一个遗留作用域链,它最少搜索事件属性所属的元素、周围的 form 元素(如果有)以及在查找名称时到达全局对象之前的 document 对象 -这可能会导致obscure bugs


问题 1

为什么用内联onlick,我们要写onclick="hello()",但是在JS中,我们应该写btn.onclick=hello或者btn.addEventListener('click',hello);

HTML 事件处理程序属性用作由 HTML 解析器创建的事件处理程序函数的主体代码。要调用hello,属性文本必须提供进行调用的源代码,例如hello().

在 JS 中,将 onclick 设置为函数对象,或使用函数作为第二个参数调用 addEventListener,将函数添加到与元素关联的处理程序映射中。如果函数名后面加括号,以onclick为例:

  onclick = myFunction();

该函数被调用并尝试将其返回值用作处理函数 - 如果返回值不是函数,则很少发生。大多数情况下,这是一个错误,而不是预期的结果。


问题 2

对于常规函数,为什么用inline onclick,“this”是指窗口,而用js调用,“this”是指按钮。

在从内联 onclick 属性创建的事件处理函数中,this 确实指的是按钮。如果您使用 hello() 之类的代码调用另一个函数,则您正在对它进行不合格的调用,因此被调用函数使用其默认的 this 值 - 即,如果被调用函数在草率模式下运行,则使用 window

从“HTML 中的内联事件处理程序”开始,您可以传递this(指按钮)和event 对象作为参数值,如果您想:

onclick="hello(this, event)"

JavaScript 中提供的处理程序函数直接进入元素的事件处理程序映射,并由事件系统调用,并将按钮作为其this 值(可能使用callapply,因为使用@987654404 添加的处理程序@ 不作为元素属性值维护)。


问题 3

&lt;button onclick="function tes(){console.log(this)}tes()"&gt;button&gt;/button&gt;

创建事件处理函数

function onclick(event) {
    function tes(){
        console.log(this)
    }
    tes()
}

按钮标签的事件属性文本中没有调用严格模式,因此onclicktes 都处于草率模式。 tes 被无条件调用,因此它使用并记录其默认的this 值,即window

关于“关于此值”,规则 1-5 均不适用,因此规则 6 生效。


问题 4

&lt;button onclick="console.log(this)"&gt;button&lt;/button&gt;

创建一个处理函数

function onclick(event) {
    console.log(this)
}

由事件系统调用按钮元素作为其this 值,就像对任何其他处理程序一样。 console.log 在日志中显示按钮的外部 HTML。如果您将 this 更改为字符串,日志将告诉您它是一个 HTMLButtonElement 元素:

&lt;button onclick="console.log(this.toString())"&gt;button&lt;/button&gt;

【讨论】:

    【解决方案2】:

    内联&lt;button onclick="hello()"&gt; 中的文本hello() 实际上是一个小的JavaScript 程序本身——你不应该使用它;这是一种过时的老式方法,可以让任何事情都发挥作用,应该被遗忘。

    相反,JavaScript 中的正确方式是这样的:

    function hello(){}
    
    button.addEventListener("click", hello);
    

    其中hello 是函数的名称(不是 JavaScript 程序)。

    至于为什么this是当前按钮?可以使用不同的this 调用所有函数。

    如果您愿意,可以使用不同的this 调用hello 函数。

    hello.call({ turkey: true });
    

    这就是您调用hello 并提供{ turkey: true } 作为this 对象的方式。

    HTML 元素以 this 对象的形式调用事件处理程序是 HTML 元素的标准。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-24
      • 2017-02-23
      • 2013-05-28
      • 1970-01-01
      • 1970-01-01
      • 2011-06-16
      相关资源
      最近更新 更多