问题
I am confused:
why with inline onlick, we have to write onclick="hello()", but in JS, we should write btn.onclick=hello or btn.addEventListener('click',hello);
for regular function, why with inline onlick, "this" refers to window, but with js call, "this" refers to button.
I don't understand last two buttons
according to w3school, In a function, this refers to the global object. https://www.w3schools.com/js/js_this.asp
In regular functions the this keyword represented the object that called the function, which could be the window, the document, a button or whatever. 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>
回答1:
the text hello()
in the inline <button onclick="hello()">
is actually a small javascript program itself — you should never use this, it's an obsolete old fashioned way to make anything work and should be forgotten
instead, the correct way in javascript is like this:
function hello() {}
button.onclick = hello
where hello
is the name of a function (not a javascript program)
as for why this
is the current button? all functions can be called with a different this
you can call the hello
function with a different this
if you want to
hello.call({turkey: true})
that's how you call hello
and provide {turkey: true}
as the this
object
it's standard for html elements to call event handlers with the element as the this
object
cheers 👋 chase
回答2:
about this
values.
Arrow functions capture and always use their lexical
this
value, meaning the one that was in effect when their arrow function expression was evaluated. Evaluation usually occurs when executing an assignment operation or when calculating parameter values for a function call which has arrow functions in its argument list.- Arrow functions cannot be used as constructors.
Non arrow functions called as constructors using new (or super when extending a class) see the object under construction as their
this
value.Bound functions save and use a
this value
supplied as the first argument to the bind method of another function.Bound functions ignore their saved
this
value if called as constructors - but this is rare enough to be considered an edge case and is not generally recommended.Binding an arrow function has no effect on its
this
value but could be used to predefine a set of parameter values.
Functions called using either their call or apply object methods take their
this
value from the (first)thisValue
argument supplied tocall
orapply
, subject to JavaScript mode:In strict mode
null
orundefined
values provided forthisValue
are used as the function'sthis
value. In sloppy mode however,null
orundefined
are replaced bywindow
before making the call.Arrow and bound functions can be called using these methods (e.g. to supply arguments) but use their own recorded
this
value.
Provided none of the preceding rules apply, functions explicitly called as a method of an object use the object as their
this
value.E.G. in a call of form
someObject.methodName( optionalArgumentList)
this
inmethodName
refers tosomeObject
if the method is a regular function.In strict mode, the default value of
this
in an unqualified function call isundefined
. In sloppy mode (dating from when JavaScript was first introduced)this
iswindow
. For demonstration:
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
Code provided as a text string in calls to the global Function constructor, SetTimeout, related timer calls, and event attributes in HTML source, is treated as a "script" in its own right and creates a function that
operates in sloppy mode if strict mode is not invoked by the supplied source code,
operates in strict mode if strict mode is invoked in the source.
While this alters the default
this
value of the function, is is also an edge case because none of these methods of creating a function is recommended when writing maintainable code.The
this
value when evaluating code with eval is outside the scope of this question, but for completeness:Direct calls to
eval
inheritthis
from the calling context unless the evaluated code invokes strict mode - in which casethis
isundefined
during code evaluation.Indirect calls to
eval
usewindow
(i.e. the global object) asthis
even if they invoke strict mode (Ref.)
This is also an edge case since because of its dangers,
eval
should never be used because you can.
Inline event handlers in HTML
Event handler content attributes in an HTML tag of the form
onEventName="text"
are converted into event handler functions by the HTML parser using steps equivalent to
Save the text as the attribute's string value.
Use the JavaScript parser/compiler to create an event handler function from the text by including it in a template of form
function( event) { // include attribute text here as body code }
Save the function as a property of the element under the same name as the attribute. E.G. at this point an element with an
onclick
text attribute will also have anonclick
property which is a function.Add the function to the element's internal event handler map. In practical terms this means actual event handling uses a map of listeners rather than looking for handler functions on the element.
Warning
HTML onEventName attributes predate both standardization of the DOM and the introduction of
addEventListener
:Handlers created by the HTML parser have a legacy scope chain that minimally searches the element the event attribute belongs to, a surrounding
form
element if any, and thedocument
object before reaching the global object when looking up names - which can result in obscure bugs.
question 1
Why with inline onlick, we have to write onclick="hello()", but in JS, we should write btn.onclick=hello or btn.addEventListener('click',hello);
The HTML event handler attribute is used as the body code of a event handler function created by the HTML parser. To call hello
, attribute text must provide the source code to make the call, as in e.g. hello()
.
In JS, setting an onclick
to a function object, or calling addEventListener
with a function as the second parameter, adds the function to a map of handlers associated with the element. If parentheses are placed after the function name, using onclick
as an example:
onclick = myFunction();
the function is called and an attempt is made to use its return value as a handler function - and if the return value is not a function little happens. Most often this is a mistake and not the desired outcome.
question 2
For regular function, why with inline onclick, "this" refers to window, but with js call, "this" refers to button.
Inside the event handler function created from an inline onclick attribute, this
does refer to the button. If you call out to another function with code like hello()
, you are making an unqualified call to it, so the called function uses its default this
value - i.e. window
if the called function operates in sloppy mode.
Following on from "Inline event handlers in HTML", you could pass on this
(referring to the button) and the event
object as a parameter values if you wanted to:
onclick="hello(this, event)"
Handler functions provided in JavaScript go directly into the element's map of event handlers and are called by the event system with the button as their this
value (probably using call
or apply
, since handlers added with addEventListener
aren't maintained as element property values).
question 3
<button onclick="function tes(){console.log(this)}tes()">button>/button>
Creates the event handler function
function onclick(event) {
function tes(){
console.log(this)
}
tes()
}
Strict mode was not invoked in the button tag's event attribute text, so both onclick
and tes
are in sloppy mode. tes
is called without qualification, so it uses and logs its default this
value which is window
.
In regards to "about this values", none of rules 1 - 5 apply, so rule 6 comes into effect.
question 4
<button onclick="console.log(this)">button</button>
creates a handler function
function onclick(event) {
console.log(this)
}
which is called with the button element as its this
value by the event system as it would for any other handler. console.log
is showing the outer HTML for the button in the log. If you change this
to a string, the log will tell you its an HTMLButtonElement element instead:
<button onclick="console.log(this.toString())">button</button>
来源:https://stackoverflow.com/questions/57916622/onclick-and-this-in-javascript