I have got a method which finds a required value in an array.
let result = arrayStart.find(obj => obj.data === `${constValue1}/${constValue2}/${constValue3}`)
Will JavaScript create each time a new string in each iteration, e.g.
`${constValue1}/${constValue2}/${constValue3}`
or will it create only once?
JavaScript is not a compiled language, it is interpreted as it runs. This means that there is no sure-fire way for the engine to know what constValue's are in advance, even if they are declared const. This means that in order to know what the final value of the string is, the interpreter has to re-compute it every time.
Normally I would write such code like this:
const searchTerm = `${constValue1}/${constValue2}/${constValue3}`;
let result = arrayStart.find(obj => obj.data === searchTerm);
However, keep in mind that in terms of performance, this requires scope resolution (the engine needs to find where the value searchTerm is defined), so that takes a tiny bit of time as well.
Also, some smarter code processors (i.e. minimizers) might be able to see that this value never changes and extract it in the same manner, but I would not count on that.
The string will be created each time, think of find as a loop that will loop through each element in an array and on each iteration you are constructing a string. I wouldn't worry too much about it as its not being assigned to any variable you are just using it for equality but if you want to make it better i would create a variable outside the callback passed to find and assign it there and use that variable for equality.
such as:
const newString = `${constValue1}/${constValue2}/${constValue3}`;
let result = arrayStart.find(obj => obj.data === newString)
Related
This question already has answers here:
Benefit of const vs let in TypeScript (or Javascript)
(2 answers)
Closed 1 year ago.
Similar to This Question, what are the advantages of using const inside js for loops instead of let and var for values that change each iteration?
I am not a particular fan of this pattern, but I am interested in learning about the advantages of this pattern.
Background
When I write JavaScript in Visual Studio and type for it suggests the following code block:
for (let index = 0; index < array.length; index++) {
const element = array[index];
}
I personally am not a fan of this pattern as reassigning a value to a const each iteration as it seems to violate the core idea of a constant ( yes, I know the constant technically goes out of scope, but it still feels like a const is being assigned a new value).
I assume there must be many good reasons for this pattern, otherwise why would this stick around as a suggested code block. I have come up with a good reason, but I am still curious about what advantages I am missing.
Reason I came up with
I could see this being useful within a large code block where you either need to ensure no one uses this name or this name is referenced multiple times expecting the same value.
If you're not happy with
for (let index = 0; index < array.length; index++) {
const element = array[index];
}
then you may as well not be happy with most uses of const, like those in most functions, since the values often vary.
function getFullName(first, last) {
const fullName = first + ' ' + last;
return fullName;
}
The purpose of const is to indicate that that particular variable binding, in the scope it's in, will never be reassigned. That's it. In your loop, a new variable environment is created with every iteration, and into each such environment, a const is created. Using let instead here wouldn't make things clearer - on the contrary, using let just because you're inside a loop (or inside a function, like in my example above) would generally indicate a misunderstanding of scope.
const doesn't mean, and no one should take it to imply:
Every time anything anywhere references a variable named <x>, the value will be <y>.
I suggest using const whenever appropriate - that is, whenever a particular variable binding, in the scope that it's in, never gets reassigned. That's all that's needed for it to be valid, that's how the vast majority of professional developers use it, and that's what it's meant to indicate. You don't have to, of course - you can use let instead - but using const will make the code a bit easier to read at a glance when you know the identifier won't get reassigned in the scope it's in.
Avoid var, especially in loops, and especially if there's any chance of any asynchronous code ever being executed - it has unintuitive function scope, not block scope. for (let i = has a new binding for each iteration; for (var i has only a single binding ever - see this famous question. (var also unintuitively creates properties on the global object when on the top level, and will not warn you when you attempt to declare a variable more than once in a given scope, which is usually indicative of a bug. const and let do not have those problems.)
Notes about 'Not a duplicate':
I've been told this is a duplicate of What is the use of Symbol in javascript ECMAScript 6?. Well, it doesn't seem right to me. The code they've given is this:
const door = {};
// library 1
const cake1 = Symbol('cake');
door[cake1] = () => console.log('chocolate');
// library 2
const cake2 = Symbol('cake');
door[cake2] = () => console.log('vanilla');
// your code
door[cake1]();
door[cake2]();
The only thing that makes this work is because cake1 and cake2 are different (unique) names. But the developer has explicitly given these; there is nothing offered by Symbol which helps here.
For example if you change cake1 and cake2 to cake and run it, it will error:
Uncaught SyntaxError: Identifier 'cake' has already been declared
If you're already having to manually come up with unique identifiers then how is Symbol helping?
If you execute this in your console:
Symbol('cake') === Symbol('cake');
It evaluates to false. So they're unique. But in order to actually use them, you're now having to come up with 2 key names (cake1 and cake2) which are unique. This has to be done manually by the developer; there's nothing in Symbol or JavaScript in general which will help with that. You're basically creating a unique identifier using Symbol but then having to assign it manually to...a unique identifier that you've had to come up with as a developer.
With regards to the linked post they cite this as an example which does not use Symbol:
const door = {};
// from library 1
door.cake = () => console.log('chocolate');
// from library 2
door.cake = () => console.log('vanilla');
// your code
door.cake();
They try to claim this is a problem and will only log "vanilla". Well clearly that's because door.cake isn't unique (it's declared twice). The "fix" is as simple as using cake1 and cake2:
door.cake1 = () => console.log('chocolate');
door.cake2 = () => console.log('vanilla');
door.cake1(); // Outputs "chocolate"
door.cake2(); // Outputs "vanilla"
That will now work and log both "chocolate" and "vanilla". In this case Symbol hasn't been used at all, and indeed has no bearing on that working. It's simply a case that the developer has assigned a unique identifier but they have done this manually and without using Symbol.
Original question:
I'm taking a course in JavaScript and the presenter is discussing Symbol.
At the beginning of the video he says:
The thing about Symbol's is that every single one is unique and this makes them very valuable in terms of things like object property identifiers.
However he then goes on to say:
They are not enumerable in for...in loops.
They cannot be used in JSON.stringify. (It results in an empty object).
In the case of point (2) he gives this example:
console.log(JSON.stringify({key: 'prop'})); // object without Symbol
console.log(JSON.stringify({Symbol('sym1'): 'prop'})); // object using Symbol
This logs {"key": "prop"} and {} to the console respectively.
How does any of this make Symbol "valuable" in terms of being unique object keys or identifiers?
In my experience two very common things you'd want to do with an object is enumerate it, or convert the data in them to JSON to send via ajax or some such method.
I can't understand what the purpose of Symbol is at all, but especially why you would want to use them for making object identifiers? Given it will cause things later that you cannot do.
Edit - the following was part of the original question - but is a minor issue in comparison to the actual purpose of Symbol with respect to unique identifiers:
If you needed to send something like {Symbol('sym1'): 'prop'} to a backend via ajax what would you actually need to do in this case?
I replied to your comment in the other question, but since this is open I'll try to elaborate.
You are getting variable names mixed up with Symbols, which are unrelated to one another.
The variable name is just an identifier to reference a value. If I create a variable and then set it to something else, both of those refer to the same value (or in the case of non-primitives in JavaScript, the same reference).
In that case, I can do something like:
const a = Symbol('a');
const b = a;
console.log(a === b); // true
That's because there is only 1 Symbol created and the reference to that Symbol is assigned to both a and b. That isn't what you would use Symbols for.
Symbols are meant to provide unique keys which are not the same as a variable name. Keys are used in objects (or similar). I think the simplicity of the other example may be causing the confusion.
Let us imagine a more complex example. Say I have a program that lets you create an address book of people. I am going to store each person in an object.
const addressBook = {};
const addPerson = ({ name, ...data }) => {
addressBook[name] = data;
};
const listOfPeople = [];
// new user is added in the UI
const newPerson = getPersonFromUserEntry();
listOfPeople.push(newPerson.name);
addPerson(newPerson);
In this case, I would use listOfPeople to display a list and when you click it, it would show the information for that user.
Now, the problem is, since I'm using the person's name, that isn't truly unique. If I have two "Bob Smith"'s added, the second will override the first and clicking the UI from "listOfPeople" will take you to the same one for both.
Now, instead of doing that, lets use a Symbol in the addPerson() and return that and store it in listOfPeople.
const addressBook = {};
const addPerson = ({ name, ...data }) => {
const symbol = Symbol(name);
addressBook[symbol] = data;
return symbol;
};
const listOfPeople = [];
// new user is added in the UI
const newPerson = getPersonFromUserEntry();
listOfPeople.push(addPerson(newPerson));
Now, every entry in listOfPeople is totally unique. If you click the first "Bob Smith" and use that symbol to look him up you'll get the right one. Ditto for the second. They are unique even though the base of the key is the same.
As I mentioned in the other answer, the use-case for Symbol is actually fairly narrow. It is really only when you need to create a key you know will be wholly unique.
Another scenario where you might use it is if you have multiple independent libraries adding code to a common place. For example, the global window object.
If my library exports something to window named "getData" and someone has a library that also exports a "getData" one of us is going to override the other if they are loaded at the same time (whoever is loaded last).
However, if I want to be safer, instead of doing:
window.getData = () => {};
I can instead create a Symbol (whose reference I keep track of) and then call my getData() with the symbol:
window[getDataSymbol]();
I can even export that Symbol to users of my library so they can use that to call it instead.
(Note, all of the above would be fairly poor naming, but again, just an example.)
Also, as someone mentioned in the comments, these Symbols are not for sharing between systems. If I call Symbol('a') that is totally unique to my system. I can't share it with anyone else. If you need to share between systems you have to make sure you are enforcing key uniqueness.
As a very practical example what kind of problem Symbols solve, take angularjs's use of $ and $$:
AngularJS Prefixes $ and $$: To prevent accidental name collisions with your code, AngularJS prefixes names of public objects with $ and names of private objects with $$. Please do not use the $ or $$ prefix in your code.
https://docs.angularjs.org/api
You'll sometimes have to deal with objects that are "yours", but that Angular adds its own $ and $$ prefixed properties to, simply as a necessity for tracking certain states. The $ are meant for public use, but the $$ you're not supposed to touch. If you want to serialise your objects to JSON or such, you need to use Angular's provided functions which strip out the $-prefixed properties, or you need to otherwise be aware of dealing with those properties correctly.
This would be a perfect case for Symbols. Instead of adding public properties to objects which are merely differentiated by a naming convention, Symbols allow you to add truly private properties which only your code can access and which don't interfere with anything else. In practice Angular would define a Symbol once somewhere which it shares across all its modules, e.g.:
export const PRIVATE_PREFIX = Symbol('$$');
Any other module now imports it:
import { PRIVATE_PREFIX } from 'globals';
function foo(userDataObject) {
userDataObject[PRIVATE_PREFIX] = { foo: 'bar' };
}
It can now safely add properties to any and all objects without worrying about name clashes and without having to advise the user about such things, and the user doesn't need to worry about Angular adding any of its own properties since they won't show up anywhere. Only code which has access to the PRIVATE_PREFIX constant can access these properties at all, and if that constant is properly scoped, that's only Angular-related code.
Any other library or code could also add its own Symbol('$$') to the same object, and it would still not clash because they're different symbols. That's the point of Symbols being unique.
(Note that this Angular use is hypothetical, I'm just using its use of $$ as a starting point to illustrate the issue. It doesn't mean Angular actually does this in any way.)
To expand on #samanime's excellent answer, I'd just like to really put emphasis on how Symbols are most commonly used by real developers.
Symbols prevent key name collision on objects.
Let's inspect the following page from MDN on Symbols. Under "Properties", you can see some built-in Symbols. We'll look at the first one, Symbol.iterator.
Imagine for a second that you're designing a language like JavaScript. You've added special syntax like for..of and would like to allow developers to define their own behavior when their special object or class is iterated over using this syntax. Perhaps for..of could check for a special function defined on the object/class, named iterator:
const myObject = {
iterator: function() {
console.log("I'm being iterated over!");
}
};
However, this presents a problem. What if some developer, for whatever reason, happens to name their own function property iterator:
const myObject = {
iterator: function() {
//Iterate over and modify a bunch of data
}
};
Clearly this iterator function is only meant to be called to perform some data manipulation, probably very infrequently. And yet if some consumer of this library were to think myObject is iterable and use for..of on it, JavaScript will go right ahead and call that function, thinking it's supposed to return an iterator.
This is called a name collision and even if you tell every developer very firmly "don't name your object properties iterator unless it returns a proper iterator!", someone is bound to not listen and cause problems.
Even if you don't think just that one example is worthy of this whole Symbol thing, just look at the rest of the list of well-known symbols. replace, match, search, hasInstance, toPrimitive... So many possible collisions! Even if every developer is made to never use these as keys on their objects, you're really restricting the set of usable key names and therefore developer freedom to implement things how they want.
Symbols are the perfect solution for this. Take the above example, but now JavaScript doesn't check for a property named "iterator", but instead for a property with a key exactly equal to the unique Symbol Symbol.iterator. A developer wishing to implement their own iterator function writes it like this:
const myObject = {
[Symbol.iterator]: function() {
console.log("I'm being iterated over!");
}
};
...and a developer wishing to simply not be bothered and use their own property named iterator can do so completely freely without any possible hiccups.
This is a pattern developers of libraries may implement for any unique key they'd like to check for on an object, the same way the JavaScript developers have done it. This way, the problem of name collisions and needing to restrict the valid namespace for properties is completely solved.
Comment from the asker:
The bit which confused me on the linked OP is they've created 2 variables with the names cake1 and cake2. These names are unique and the developer has had to determine them so I didn't understand why they couldn't assign the variable to the same name, as a string (const cake1 = 'cake1'; const cake2 = 'cake2'). This could be used to make 2 unique key names since the strings 'cake1' !== 'cake2'. Also the answer says for Symbol you "can't share it" (e.g. between libraries) so what use is that in terms of avoiding conflict with other libraries or other developers code?
The linked OP I think is misleading - it seems the point was supposed to be that both symbols have the value "cake" and thus you technically have two duplicate property keys with the name "cake" on the object which normally isn't possible. However, in practice the capability for symbols to contain values is not really useful. I understand your confusion there, again, I think it was just another example of avoiding key name collision.
About the libraries, when a library is published, it doesn't publish the value generated for the symbol at runtime, it publishes code which, when added to your project, generates a completely unique symbol different than what the developers of the library had. However, this means nothing to users of the library. The point is that you can't save the value of a symbol, transfer it to another machine, and expect that symbol reference to work when running the same code. To reiterate, a library has code to create a symbol, it doesn't export the generated value of any symbols.
What's the purpose of Symbol in terms of unique object identifiers?
Well,
Symbol( 'description' ) !== Symbol( 'description' )
How does any of this make Symbol "valuable" in terms of being unique object keys or identifiers?
In a visitor pattern or chain of responsibility, some logic may add additional metadata to any object and that's it (imagine some validation OR ORM metadata) attached to objects but that does not persist *.
If you needed to send something like {Symbol('sym1'): 'prop'} to a backend via ajax what would you actually need to do in this case?
If I may assure you, you won't need to do that. you would consider { sym1: 'prop' } instead.
Now, this page even has a note about it
Note: If you are familiar with Ruby's (or another language) that also has a feature called "symbols", please don’t be misguided. JavaScript symbols are different.
As I said, there are useful for runtime metadata and not effective data.
Had troubles choosing title. I am learning js and looking for place to ask questions, most of the time they are simple. Is stackoverflow a good place for that or can you recommend another place (irc or forum)?
Begann to work with functions in js. These lines are given:
function calculateTax(amount){
let result = amount * 0.08;
return result;
}
let tax = calculateTax(100);
console.log(tax);
I ask my self why function needs a local variable "result", why couldn't the parameter be used:
function calculateTax(amount){
amount * 0.08;
return amount;
}
let tax = calculateTax(100);
console.log(tax);
My guess is because the parameter is a placeholder or is a variable needed to safe the multiplication and the 0.08? I think I read that parameters are variables to, is this correct? Is the 100 in the function a parameter too?
I think I waste to much time on such things. My problem is, I am to curious.
Thank you for your time.
Assuming that amount is a number, then either method works. That said, reassigning a paraneter when one doesn't have to is generally considered to be a bit of a code smell - see see no-param-reassign.
In your original code, both amount and result are local variables. (yes, parameters are variables too)
Of course, an alternative to declaring a new variable or reassigning amount is to simply return the result of the calculation immediately:
function calculateTax(amount) {
return amount * 0.08;
}
let tax = calculateTax(100);
console.log(tax);
Primitives are immutable, so changing amount inside the function won't cause any side-effects. If amount wasn't a primitive, then you would have to worry about changing it. For example, if it was an object with a value property, then if you changed that property inside the function, the object that was passed in will be mutated. To illustrate:
function calculateTax(obj) {
obj.amount *= 0.08;
return obj.amount;
}
const item = { amount: 100 };
let tax = calculateTax(item);
console.log(tax);
// item was mutated inside the function:
console.log(item);
The reason for introducing a variable is that in many cases what you want a function to do with a parameter isn't quite as simple as in your example. For example another function might take the parameter, send it wrapped in an object, stringified to JSON to a REST service, await the response from that server, and do some calculations on that, and in the end, return it.
In your case I'd even advocate omitting the extra creation of a variable because what the function does is so trivial.
Glad you're learning JavaScript. For more terse syntax (and up your game), use ES6 arrow function notation as follows
const calculateTax = (amount) => amount * 0.08;
console.log(calculateTax(100));
On a blog I see the following:
for (var key in map) {
if (map.hasOwnProperty(key)) {
var value = map[key];
// right, now we can get some work done
}
}
"Now you see that var key at the top of the for loop? That’s not
declaring a variable, oh no. It’s saying that somewhere else there’s a
variable called key"
Surely this is declaring a variable (if one named key did not previously exist in the scope chain)? What might the author mean by this?
Link: http://dannorth.net/2011/12/19/the-rise-and-rise-of-javascript/
Surely this is declaring a variable (if one named key did not previously exist in the scope chain)?
Yes, it is, within the function that for loop is in. (The variable is not limited to the for loop like it would be in, say, Java. Its scope is the entire function it's in.)
More about var (on my blog): Poor, misunderstood var
What might the author mean by this?
It sounds sarcastic, actually, like the author is trying to make a point by saying the opposite of what they mean.
Edit Since you've posted the link, here's the complete quote:
Now you see that var key at the top of the for loop? That’s not declaring a variable, oh no. It’s saying that somewhere else there’s a variable called key (right at the top of the nearest containing function, it turns out). Oh, and that key variable is visible all through that function, and any functions it contains, not just tucked away in the for loop. Brilliant!
The point he's trying to make there is that the variable isn't just limited to the for loop. But that initial statement is flatly incorrect. I know what he means, but it's not what he said.
Re the first point above, in ES6 JavaScript will be getting a new keyword, let, which would declare something only for the for loop:
// New in ES6, you probably can't use this yet
for (let key in map) {
// ^^^---------------- change is here
if (map.hasOwnProperty(key)) {
let value = map[key];
// ^^^----------------- probably want to change this one, too
// right, now we can get some work done
}
}
Some engines already support it, but you can't use it broadly yet, as many don't. And in theory the ES6 draft spec could change, though I really doubt it will. :-)
That, actually is a full definition of a variable from an iterator value that's fetched at the current iteration of variable map. It's a declaration + initialization.
To understand the notion of iterators you would have to go deeper and look into the underlying interpreter code which supports the value of the key to every iteration of the loop.
Also this: "Now you see that var key at the top of the for loop? That’s not declaring a variable, oh no. It’s saying that somewhere else there’s a variable called key" sounds stupid, doesn't explain anything and creates confusion.
I wouldn't read such articles, because such a statement shows that the author isn't really acquainted with the real world behind JavaScript - that is C/C++ or even assembly, which work at the basic memory level, and use constructs called iterators to support values to loops in case of data structures that are more advanced than simple arrays.
I'm currently reading through this jquery masking plugin to try and understand how it works, and in numerous places the author calls the slice() function passing no arguments to it. For instance here the _buffer variable is slice()d, and _buffer.slice() and _buffer seem to hold the same values.
Is there any reason for doing this, or is the author just making the code more complicated than it should be?
//functionality fn
function unmaskedvalue($input, skipDatepickerCheck) {
var input = $input[0];
if (tests && (skipDatepickerCheck === true || !$input.hasClass('hasDatepicker'))) {
var buffer = _buffer.slice();
checkVal(input, buffer);
return $.map(buffer, function(element, index) {
return isMask(index) && element != getBufferElement(_buffer.slice(), index) ? element : null; }).join('');
}
else {
return input._valueGet();
}
}
The .slice() method makes a (shallow) copy of an array, and takes parameters to indicate which subset of the source array to copy. Calling it with no arguments just copies the entire array. That is:
_buffer.slice();
// is equivalent to
_buffer.slice(0);
// also equivalent to
_buffer.slice(0, _buffer.length);
EDIT: Isn't the start index mandatory? Yes. And no. Sort of. JavaScript references (like MDN) usually say that .slice() requires at least one argument, the start index. Calling .slice() with no arguments is like saying .slice(undefined). In the ECMAScript Language Spec, step 5 in the .slice() algorithm says "Let relativeStart be ToInteger(start)". If you look at the algorithm for the abstract operation ToInteger(), which in turn uses ToNumber(), you'll see that it ends up converting undefined to 0.
Still, in my own code I would always say .slice(0), not .slice() - to me it seems neater.
array.slice() = array shallow copy and is a shorter form of array.slice()
Is there any reason for doing this, or is the author just making the code more complicated than it should be?
Yes there may be a reason in the following cases (for which we do not have a clue, on whether they apply, in the provided code):
checkVal() or getBufferElement() modify the content of the arrays passed to them (as second and first argument respectively). In this case the code author wants to prevent the global variable _buffer's content from being modified when calling unmaskedvalue().
The function passed to $.map runs asynchronously. In this case the code author wants to make sure that the passed callback will access the array content as it was during unmaskedvalue() execution (e.g. Another event handler could modify _buffer content after unmaskedvalue() execution and before $.map's callback execution).
If none of the above is the case then, yes, the code would equally work without using .slice(). In this case maybe the code author wants to play safe and avoid bugs from future code changes that would result in unforeseen _buffer content modifications.
Note:
When saying: "prevent the global variable _buffer's content from being modified" it means to achieve the following:
_buffer[0].someProp = "new value" would reflect in the copied array.
_buffer[0] = "new value" would not reflect in the copied array.
(For preventing changes also in the first bullet above, array deep clone can be used, but this is out of the discussed context)
Note 2:
In ES6
var buffer = _buffer.slice();
can also be written as
var buffer = [..._buffer];