What is the cost of '$(this)'?
In the jQuery tag info this warning appears:
Well... that is true only for string selectors, which get parsed with regex to find out what they are:The jQuery function $() is expensive. Calling it repeatedly is extremely inefficient.
quickExpr = /^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/
Then if the string is a selector (other than id
), jQuery traverses the DOM to find a match with its expensive find
function:} else if ( !context || context.jquery ) {
return ( context || rootjQuery ).find( selector );
}
So yes it's expensive, but that is only true for selectors!If we pass a DOMElement
, the only action jQuery does is saving the DOMElement parameter as the context of the newly created jQuery object and setting the length of the context to 1:
// Handle $(DOMElement)
if ( selector.nodeType ) {
this.context = this[0] = selector; // Selector here is a DOMElement
this.length = 1;
return this;
}
I did some tests with jsPerf, and I found that indeed caching the jQuery object has only a little effect:In Chrome it's only 7% slower. (In IE it's a little bit more significant: 12%.)
Update variable to show total cost
You cannot perform math on string. In the switch case, you were setting like cost = "$10.00"
. You were then doing cost *= 0.8
which would result in NaN
, since you were multiplying a string.
You can set cost to a Number, perform all operations and add "$" and ".00" after it.
It will be costElement.value
and not just costElement = ...
(also, it was out of if condition, which resulted in costElement
being undefined
.)
(Note: I have changed input[type="submit"]
to input[type="button"]
in HTML for demo purposes, to prevent submission.)
'use strict';
function calculate() {
//declares a variable named 'cost' to store the total cost:
var cost;
// lookup the type and years input elements with DOM getElementById()
var type = document.getElementById("type");
var years = document.getElementById("years");
// Convert the year to a number()), i'm not sure if this is working or not
if (years && years.value) {
years = parseInt(years.value, 10);
}
// Check for valid data:
if (type && type.value && years && (years > 0)) {
// Add a switch statement to determine the base cost using the value of "type"
switch (type.value) {
case 'basic':
cost = 10;
break;
case 'premium':
cost = 15;
break;
case 'gold':
cost = 20;
break;
case 'platinum':
cost = 25;
break;
}
// Update cost by multiplying number of years
cost = cost * years;
// Discount multiple years
if (years > 1) {
cost *= 0.80; // 80%
}
cost = "$" + cost + ".00";
let costElement = document.getElementById('cost');
//update the value property of 'costElement' to the calculated cost
costElement.value = cost; //You can also use type.value + cost
}
// Return false to prevent submission:
return false;
}
function init() {
document.getElementById('submit').onclick = calculate; //replace with document.getElementById('theForm').onsubmit = calculate;
}
window.onload = init;
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Membership Form</title>
<link rel="stylesheet" href="css/form.css">
</head>
<body>
<form action="" method="post" id="theForm">
<script src="js/membership.js"></script>
<fieldset>
<legend>Create Your Membership</legend>
<p>Complete this form to calculate your membership. There's a 20% discount if you enroll for more than one year!</p>
<div><label for="type">Type</label>
<select name="type" id="type" required>
<option value="basic">Basic - $10.00</option>
<option value="premium">Premium - $15.00</option>
<option value="gold">Gold - $20.00</option>
<option value="platinum">Platinum - $25.00</option>
</select>
</div>
<div><label for="years">Years</label><input type="number" name="years" id="years" min="1" required></div>
<div><label for="cost">Cost</label><input type="text" name="cost" id="cost" disabled></div>
<input type="button" value="Calculate" id="submit">
</fieldset>
</form>
</body>
</html>
Update the value property of 'costElement' to the calculated cost
I'm not sure what you're trying to accomplish with this line:
var years = document.getElementById('years');
...followed by this line?
var years = parseInt("1996");
First of all, why is this a calendar year instead of a number of years (surely you aren't pricing a membership that will last for nearly two millennia)?
Anyway, this line simply sticks the value "1996" into the variable years
, it does not update the element with an id
of years
to 1996. Same problem here:
var costElement = type + years;
The variable costElement
has already be declared, and this line replaces its previous value (which in the element in the HTML document) with type + years
. And type + years
doesn't make a lot of sense, since you want to multiply, not add.
Then you got this mysterious bit:
// Discount multiple years:
if (years > 1) {
cost *= .20; // 20%
}
cost
has never been defined, so what's cost
becoming 20% of? Besides, I'm pretty sure you want to take 20% off the final price, not make the final price 20% of the original cost -- because that would be an 80% discount!This should be more like:
var cost = 1;
// Discount multiple years:
if (years > 1) {
cost = 0.80; // 20% off
}
Further, you need some way to turn the value ('basic', 'premium', etc.) into a numeric value for calculation. You could just add to your switch
statement for that, but you already have text
, and stripping off the leading $
will do to get a number, so you can do this:var price = parseFloat(text.substr(1));
Now you can get the total cost like this (notice you don't need to, and shouldn't, put var
in front again):
cost *= price * years;
Then, with some appropriate formatting, you can display value this way:
costElement.value = '$' + cost.toFixed(2);
I don't know if that fixes everything, and there are also better ways to display a value than using a disabled input field (like setting the innerText
property of a <span>
), but hopefully this can get you on the right track.
Cost of calling a function or not in Javascript
It Just Doesn't Matter (although the first method avoids some work so it should faster, but by an amount which is probably less than statistical noise).
What really matters is which method best represents the logic. Rule of thumb is that every statement in a function should be on about the same level of abstraction. Is the conditional expression more or less abstract than the function call?
Related Topics
How to Stop Intense JavaScript Loop from Freezing the Browser
Why Is Window (And Unsafewindow) Not the Same from a Userscript as from a <Script> Tag
Why Does JavaScript's Regex.Exec() Not Always Return the Same Value
Access Properties of the Parent with a Handlebars 'Each' Loop
JavaScript String Array to Object
Bootstrap: Open Another Modal in Modal
Uncaught Typeerror: Cannot Use 'In' Operator to Search for 'Length' In
Find the Exact Height and Width of the Viewport in a Cross-Browser Way (No Prototype/Jquery)
How to Export Socket.Io into Other Modules in Nodejs
How to Invoke "Click" Event Programmatically in D3
How to Load All Files in a Directory Using Webpack Without Require Statements
Get the Current Year in JavaScript
I Can't Reference an Image in Next.Js