Is "clear" a reserved word in Javascript? - javascript

I just spent a long time figuring out that I shouldn't use clear() as the name of a function in Javascript:
<head>
<script type="text/javascript" src="Array.js"></script>
</head>
<body>
Hello!!!!<br>
<button type="button" onClick="clear()" id="ppp">Shoo!</button><br>
<button type="button" onClick="add()" id="add">Add a few elements</button><br>
<button type="button" onClick="check()" id="check">Check the array</button><br>
<p id="results">Results will appear here.</p>
<script type="text/javascript">
initialize();
</script>
</body>
Here's Array.js:
var results;
function initialize(){
results = document.getElementById("results");
}
function add() {
results.firstChild.data="add";
}
function clear() {
results.firstChild.data = "Hello?";
}
function check() {
results.firstChild.data = "check";
}
Symptoms: Clicking the 'add' and 'check' buttons gives me the result I expect, but clicking the 'clear' button does nothing.
If I rename clear() to clearxyz(), it works fine.
My questions:
Is "clear" a reserved word? I don't see it on the list:
https://developer.mozilla.org/en/JavaScript/Reference/Reserved_Words
Is there a debugging trick I should be using to figure this kind of
thing out in the future? It took me a long time (I'm a noob!) to
figure out that the name of the function was my problem.
Many thanks.
Edit: I'm using Firefox 6.0, and I added a line break to show where Array.js starts.

As the others said, clear is not a reserved keyword. It seems that the called function is document.clear [MDN]. Invoking
console.log(clear === document.clear);
inside the event handler returns true.
DEMO
So it seems, document is in the scope chain of the event handler.... the question now is why.
JavaScript: The Definitive Guide says:
In an event handler as HTML attribute, the Document object is in the scope chain before the Window object (...)
As your method is global, meaning it is a property of the window object, it is not found in the scope chain, as document.clear comes earlier in the scope chain.
I haven't found any specification for this. The guide also says that one should not rely on that, so I assume this is nothing official.
If you have form elements inside a form, then even the corresponding form element will be in the scope chain (not sure whether this holds for all browsers though). This is another reason for confusion.
There are two (not exclusive) ways to avoid such situations:
Don't use inline event handlers. It is considered bad practice as it is mixing logic and presentation. There are other ways to attach event handlers.
Don't pollute the global namespace. Create one object in global scope (with a name you are sure of does not collide with any window or document properties or ids of HTML elements) and assign the functions as properties of this object. Whenever you call a function, you reference it through this object. There also other ways to namespace your code.

No, clear is not a reserved keyword.
The problem is that, since you use an event handler content attribute, your global function window.clear is shadowed by the obsolete document.clear.
This behavior is explained in step 10 of getting the current value of the event handler:
Lexical Environment Scope
If H is an element's event handler, then let Scope be the result of NewObjectEnvironment(document, the global environment).
Otherwise, H is a Window object's event handler: let
Scope be the global environment.
If form owner is not null, let Scope be the result of NewObjectEnvironment(form owner, Scope).
If element is not null, let Scope be the result of NewObjectEnvironment(element, Scope).
Note: NewObjectEnvironment() is defined in ECMAScript edition 5 section 10.2.2.3 NewObjectEnvironment (O, E)
That means that the global scope is shadowed by
The document
The form owner, if any
The element
Therefore, you can
Rename your function.
function clear__() { document.body.style.background = 'green'; }
<button type="button" onclick="clear__()">Click me</button>
This approach is not completely reliable because some browser could implement a non-standard feature which shadows your variables. Or a future spec could introduce that feature (example).
Call your function as a method of the global object.
For example, assuming window is not shadowed, you can use window.clear.
function clear() { document.body.style.background = 'green'; }
<button type="button" onclick="window.clear()">Click me</button>
Avoid event handler content attributes.
Instead, you can use event handler IDL attributes or event listeners.
function clear() { document.body.style.background = 'green'; }
document.querySelector('button').onclick = clear;
<button type="button">Click me</button>
function clear() { document.body.style.background = 'green'; }
document.querySelector('button').addEventListener('click', clear);
<button type="button">Click me</button>

Not according to the MDN.
Edit:
You got me curious, so I threw together this little jsfiddle.
function clear() {
alert("you cleared just fine");
}
$('clear').addEvent('click', clear);
Having a function named clear seems to work just fine.

Good question. I think the problem is a scoping issue - your onClick="clear()" is not going to the clear function you defined, but I'm not sure where it's going. Changing it to window.clear() or a new function that simply calls your clear works.
<body>
Hello!!!!<br>
<button type="button" onClick="clear()" id="ppp">Shoo!</button><br>
<button type="button" onClick="window.clear()" id="ppp">window.clear!</button><br>
<button type="button" onClick="clear2()" id="ppp">clear2!</button><br>
<button type="button" onClick="add()" id="add">Add a few elements</button><br>
<button type="button" onClick="check()" id="check">Check the array</button><br>
<p id="results">Results will appear here.</p>
<script type="text/javascript">
var results;
function initialize(){
results = document.getElementById("results");
}
function add() {
results.firstChild.data="add";
}
function clear() {
results.firstChild.data = "Hello";
}
function clear2() {
clear();
}
function check() {
results.firstChild.data = "check";
}
initialize();
</script>
</body>

Related

How many events are created in the inline event?

Basically I use the addEventListener function to bind events to an element. But you often see that events are created inline. So onclick="fnName(this)" and onkeyup="fnName()" etc.
Questions: Using the example <input onkeyup="fnName(this)" />.
is a new event now created for each letter or does the tag parameter onkeyup initialise the event once?
Which variant needs less computing time? I assume that addEventListener is more perfomanant, isn't it?
New event created on every keyup, you can filter for specific keys in you function using if conditions event.key == "SOME_KEY"
It's Micro-optimization with negligible difference, not much worth. A difference worth mentioning, you can multiple functions on same event using addEventListener while it wouldn't work in inline events.
<button id="btn1">Button 1</button>
<button id="btn2">Button 2</button>
<script>
function function1() {
console.log("Function1")
}
function function2() {
console.log("Function2")
}
function function3() {
console.log("Function3")
}
function function4() {
console.log("Function4")
}
var btn1 = document.getElementById("btn1")
var btn2 = document.getElementById("btn2")
btn1.onclick = function1
btn1.onclick = function2
btn2.addEventListener("click", function3, false)
btn2.addEventListener("click", function4, false)
</script>
Output in console:
Function2
Function3
Function4
Note: Both approaches will create a new event on every keyup, thus not making any difference. The comparison can be drawn only for single/equal number of event(s).
References:
dillionmegida.com/p/inline-events-vs-add-event-listeners
addEventListener vs onclick

I can't clear canvas on my green screen program [duplicate]

I just spent a long time figuring out that I shouldn't use clear() as the name of a function in Javascript:
<head>
<script type="text/javascript" src="Array.js"></script>
</head>
<body>
Hello!!!!<br>
<button type="button" onClick="clear()" id="ppp">Shoo!</button><br>
<button type="button" onClick="add()" id="add">Add a few elements</button><br>
<button type="button" onClick="check()" id="check">Check the array</button><br>
<p id="results">Results will appear here.</p>
<script type="text/javascript">
initialize();
</script>
</body>
Here's Array.js:
var results;
function initialize(){
results = document.getElementById("results");
}
function add() {
results.firstChild.data="add";
}
function clear() {
results.firstChild.data = "Hello?";
}
function check() {
results.firstChild.data = "check";
}
Symptoms: Clicking the 'add' and 'check' buttons gives me the result I expect, but clicking the 'clear' button does nothing.
If I rename clear() to clearxyz(), it works fine.
My questions:
Is "clear" a reserved word? I don't see it on the list:
https://developer.mozilla.org/en/JavaScript/Reference/Reserved_Words
Is there a debugging trick I should be using to figure this kind of
thing out in the future? It took me a long time (I'm a noob!) to
figure out that the name of the function was my problem.
Many thanks.
Edit: I'm using Firefox 6.0, and I added a line break to show where Array.js starts.
As the others said, clear is not a reserved keyword. It seems that the called function is document.clear [MDN]. Invoking
console.log(clear === document.clear);
inside the event handler returns true.
DEMO
So it seems, document is in the scope chain of the event handler.... the question now is why.
JavaScript: The Definitive Guide says:
In an event handler as HTML attribute, the Document object is in the scope chain before the Window object (...)
As your method is global, meaning it is a property of the window object, it is not found in the scope chain, as document.clear comes earlier in the scope chain.
I haven't found any specification for this. The guide also says that one should not rely on that, so I assume this is nothing official.
If you have form elements inside a form, then even the corresponding form element will be in the scope chain (not sure whether this holds for all browsers though). This is another reason for confusion.
There are two (not exclusive) ways to avoid such situations:
Don't use inline event handlers. It is considered bad practice as it is mixing logic and presentation. There are other ways to attach event handlers.
Don't pollute the global namespace. Create one object in global scope (with a name you are sure of does not collide with any window or document properties or ids of HTML elements) and assign the functions as properties of this object. Whenever you call a function, you reference it through this object. There also other ways to namespace your code.
No, clear is not a reserved keyword.
The problem is that, since you use an event handler content attribute, your global function window.clear is shadowed by the obsolete document.clear.
This behavior is explained in step 10 of getting the current value of the event handler:
Lexical Environment Scope
If H is an element's event handler, then let Scope be the result of NewObjectEnvironment(document, the global environment).
Otherwise, H is a Window object's event handler: let
Scope be the global environment.
If form owner is not null, let Scope be the result of NewObjectEnvironment(form owner, Scope).
If element is not null, let Scope be the result of NewObjectEnvironment(element, Scope).
Note: NewObjectEnvironment() is defined in ECMAScript edition 5 section 10.2.2.3 NewObjectEnvironment (O, E)
That means that the global scope is shadowed by
The document
The form owner, if any
The element
Therefore, you can
Rename your function.
function clear__() { document.body.style.background = 'green'; }
<button type="button" onclick="clear__()">Click me</button>
This approach is not completely reliable because some browser could implement a non-standard feature which shadows your variables. Or a future spec could introduce that feature (example).
Call your function as a method of the global object.
For example, assuming window is not shadowed, you can use window.clear.
function clear() { document.body.style.background = 'green'; }
<button type="button" onclick="window.clear()">Click me</button>
Avoid event handler content attributes.
Instead, you can use event handler IDL attributes or event listeners.
function clear() { document.body.style.background = 'green'; }
document.querySelector('button').onclick = clear;
<button type="button">Click me</button>
function clear() { document.body.style.background = 'green'; }
document.querySelector('button').addEventListener('click', clear);
<button type="button">Click me</button>
Not according to the MDN.
Edit:
You got me curious, so I threw together this little jsfiddle.
function clear() {
alert("you cleared just fine");
}
$('clear').addEvent('click', clear);
Having a function named clear seems to work just fine.
Good question. I think the problem is a scoping issue - your onClick="clear()" is not going to the clear function you defined, but I'm not sure where it's going. Changing it to window.clear() or a new function that simply calls your clear works.
<body>
Hello!!!!<br>
<button type="button" onClick="clear()" id="ppp">Shoo!</button><br>
<button type="button" onClick="window.clear()" id="ppp">window.clear!</button><br>
<button type="button" onClick="clear2()" id="ppp">clear2!</button><br>
<button type="button" onClick="add()" id="add">Add a few elements</button><br>
<button type="button" onClick="check()" id="check">Check the array</button><br>
<p id="results">Results will appear here.</p>
<script type="text/javascript">
var results;
function initialize(){
results = document.getElementById("results");
}
function add() {
results.firstChild.data="add";
}
function clear() {
results.firstChild.data = "Hello";
}
function clear2() {
clear();
}
function check() {
results.firstChild.data = "check";
}
initialize();
</script>
</body>

How to bind 'this' to click listener and use the event - es6

I have a multistep form, with 4 frameset. Each one must come in when I press the "Next" button (of course)
My ES6 modular code cointains something like this:
class FormController {
// 1. describe and initiate object
constructor() {
this.nextBtn = $(".next");
this.next_fs;
....
this.events();
}
// EVENTS LISTENER
events(){
this.nextBtn.on("click", this.nextClicked.bind(this));
// other listeners
}
nextClicked() {
this.next_fs = $(this)
.parent()
.next(); // this is the next fieldset
// some actions...
}
// rest of the code
}
My problem is the following:
I need to bind "this" inside nextClicked function to be able tu use all variables and methods like this.next_fs, this.saveData(), etc...
But I also need to know which button has been clicked, and I cannot know that because this is no more "this button", and I cannot pass a variable (let's call it 'e') to trace the e.target.
What's the matter with my code? I know that's something stupid that I'm not seeing.
Thanks!
But I also need to know which button has been clicked, and I cannot know that because "this" is no more "this button", and I cannot pass a variable (let's call it 'e') to trace the e.target
The browser's event triggering code passes that. You just need to read it.
nextClicked(e) {
"...and I cannot pass a variable (let's call it 'e') to trace the e.target"
Actually, you don't need to pass it as variable, because even if you don't pass the e you can get it in nextClicked because browsers do it by default, so it will come as parameter if you declare the function as nextClicked(e){...} and keep the bind as you have.
Or, you can pass parameters after this, such as ...bind(this, this.nextBtn), then the first parameter on nextCliked will be the button.
See below these two possibilities I mentioned:
$(".buttons").on("click", this.nextClicked.bind(this))
function nextClicked(e){
//here your context is the same as when you binded the function, but you have the event
let target = e.target;
console.log(target.id);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="btn-1" class="buttons">click me 1</button>
<button id="btn-2" class="buttons">click me 2</button>
let nextButton = $("#btn-1")[0];
$(".buttons").on("click", this.nextClicked.bind(this, nextButton))
function nextClicked(nextBtn, e) {
//here your context is the same as when you binded the function,
//but you have the button AND the event
console.log("NextButton Id: " + nextBtn.id);
console.log("Clicked button Id: " + e.target.id);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="btn-1" class="buttons">next</button>
<button id="btn-2" class="buttons">previous</button>
You are doing
this.next_fs = $(this)
But, earlier you set this to an instance of FormController
this.nextBtn.on("click", this.nextClicked.bind(this));
so what you are doing is
this.next_fs = $( (FormController)this);
You are expecting jQuery to work with a class instance, instead of the event object.
I strongly discourage you from using $(this) ever in a event handling context. this can change it's meaning as you have shown in your sample by the code breaking.
Always use event.target or event.currentTarget. I prefer currentTarget as it points to the element on which the event was bound, and not a deeper lying element within that element.
so your code should be
nextClicked(e) {
this.next_fs = $(e.currentTarget)
.parent()
.next(); // this is the next fieldset
// some actions...
}

purpose of the "function()" for attaching a function to a eventlistener

Sorry if the question looks stupid, but I have been confused for long time.
I want to alert "viola" when the button is clicked.
The second example below doesn't work as expected because I didn't include "function()"
Intuitively I think the second example should be working since I have attached a function(allert) to the element(button) and eventlistener(onclick).
Therefore I really wondered the purpose of including function(). Thanks.
Example 1
<html>
<button id="clickme">Hello,I'm a button,click me</button>
<script>
var button=document.getElementById("clickme");
clickme.onclick=function() {alert("viola");}
</script>
</html>
Example 2
<html>
<button id="clickme">Hello,I'm a button,click me</button>
<script>
var button=document.getElementById("clickme");
clickme.onclick=alert("viola");
</script>
</html>
clickme.onclick=alert("viola");
doesn't register the function alert(..), but the result of calling that function.
The onclick field expects a function, to be executed later, when the button is clicked. You don't want to execute that function when you're installing the handler.
You could also write:
clickme.onclick=myfunction;
function myfunction() { alert("viola") }
An event listener can only be a function.
alert("viola")
is not a function but actually undefined. That’s because
clickme.onclick=alert("viola");
means “assign the return value of alert(…) to clickme.onclick”. alert("viola") is being called immediately and the result of calling it is assigned.
The wrapper function(){…} actually assigns the function with the alert that is then called later.

eventListener works on variable which is supposed to be inside a function's private scope

Here I have this input button element.A variable declared as btn is assigned a reference to that button using document.getElementById('btn'), but the btn variable is inside a function named create. As far I know functions create private scope which can't be accessed globally, but here I can manage to add eventListener to that variable without even invoking the function. How is this possible?
function create(){
var btn=document.getElementById('btn');
}
btn.addEventListener('click',function(e){
alert('it worked !!');
});
<input type='button' value='button' id='btn'>
If you have an element with an id set, that id will be used as a key on the window-object which means it's globally available in a browser. See https://html.spec.whatwg.org/#named-access-on-the-window-object for more info.
In your case, if you don't name your inner variable btn, then you can't access it.
function create(){
var innerBtn=document.getElementById('btn');
}
innerBtn.addEventListener('click',function(e){
alert('not going to happen !!');
});
<input type='button' value='button' id='btn'>
Also the other way around, even if you don't assign btn in the inner function, it would still be available to you to add your listener.
btn.addEventListener('click',function(e){
alert('it worked !!');
});
<input type='button' value='button' id='btn'>

Categories

Resources