Constants in OpalRB - javascript

I'm wondering about something in a project of mine with OpalRB (the Ruby-to-JavaScript compiler): when you make a constant in Opal, like so:
ONE = 1
... is that essentially the same thing as saying this is JavaScript?:
const ONE = 1;
The reason that I ask this question is that the const keyword in JS in not always properly supported in each browser and, due to that, I'm somewhat wary about using constants with Opal.

... is that essentially the same thing as saying this is JavaScript?
No it's not. const in JavaScript makes a variable that ignores any re-assignments and keeps its original value. In Ruby, constants complain with a warning when re-assigned, but actually do get re-assigned.
Here is how ONE=1 in Ruby gets compiled by Opal:
$opal.cdecl($scope, 'ONE', 1);
As you can see, constants aren't stored as variables the way local variables are, they're stored internally inside the scope object.
The cdecl function can do whatever it wants if ONE is already declared. The developers of Opal however, seemed to choose to not show a warning when constants are reassigned. Try this (it's always fun to play around with this webpage and see how the compiler works).
Therefore, constants in Opal-compiled Ruby aren't.

Related

How actually is the features that are not available in JS is achieved using TS as TS is ultimately compiled to JS?

I was learning TS after JS and it is said that many features that are not in JS like types and all is achieved using TS. But ultimately TS is compiled down to JS. So how is this possible? How features that are not available in a language is achieved using another one if latter one is finally converted to 1st one?
So as stated in comments, typescript doesn't do anything at runtime. After transpilation all of the type information is gone for good. The point of typescript is just to check your code before-hand and find potential errors, that may cause problem when executing the resulting javascript code. All of it's features that are not part of javascript are erased after the checks are performed. private and public are also erased, the only reason they are there is that in your code you cannot use them. But it's just a "recommendation", you can totally ignore it (because, again, private doesn't exist at runtime). For example you can do something like this:
class Foo {
private bar() {}
}
;(new Foo() as any).bar()
Or even
class Foo {
private bar() {}
}
// #ts-ignore
new Foo().bar()
And here you are, you've successfully tricked the typescript compiler and this code will totally work after transpilation, even though the bar method is private and is not supposed to be accessible.
Speaking about "are all high level languages have type system like typescript?". Well, I'd not say so.
Take C for example. There types also don't exist at runtime per se. When the program is compiled, assembled an executed, everything is just a sequence of ones and zeroes, computer doesn't care if a memory location holds a string or a boolean or whatever, everything is just a sequence of bits. However the types are essential for your program to work, because the type defines, how many bytes in memory are considered a single variable. Like if you define an integer variable, you let the compiler know, that this variable will occupy 4 bytes in memory and that when, for example, adding a value to this variable, it should update all 4 bytes. If you define a char variable, it knows to update only 1 byte.
But these types don't really exist at runtime, you can totally use some pointer shenanigans to trick the compiler into thinking char variable you define is actually an integer. Will it cause problems? A lot. Is it cool? Heck yes. Now every time you add a number to this variable, your program will update 4 bytes instead of one, probably erasing some important information in these 3 bytes that don't belong to your variable, good luck debugging.
With other languages it's a little different, like Java abstracts away this pointers trickery, so you can't trick the compiler as easily. But still, variables of different types generate different byte code after compilation.
So in some languages (like C and Java) types actually impact how your program works (like how many bytes a variable occupies), but in typescript it doesn't. You could always just use any and disable type checking for any piece of your code, if the algorithm is correct, it will still work. Not the case in C though

Is there any reason for "saving" variables?

I've got this function a colleague once has written:
setSentence: function (e) {
this.setState({
issueText: e.target.value
});
if (this.refs.messages.textContent.length > 0 && e.target.value.length > 2) {
this.refs.messages.textContent = '';
}
},
He uses e.target.value on two places within the code. I would tend to make something like this:
let textBoxContent = e.target.value;
Then use the variable with the more descriptive name instead.
I once talked to him about these avoiding variables-thing. He just said that he wants "to save variables".
Would like to change these code-pieces but I'm still not sure ...
So therefore my question:
Does "saving variables" respectively avoiding variables in the code make any sense?
There is no economy in "saving variables" while repeating verbose code over and over. To me, this definitely falls in the category of DRY (Don't Repeat Yourself).
Javascript interpreters are very optimized for fast access to local variables. When a variable is being referenced, the very first scope that is looked in is the local scope so it will be found immediately and because of that and because there is no outside access to local variables, code within the function using them can be optimized pretty well.
In the end, it's probably as much a personal coding preference as anything.
My personal rule is that if I have some multi-step reference such as e.target.value and I'm using it more than once in a function, then I will creating a meaningfully named local variable and assign it to that so I can then just use the local variable in the multiple places and avoid repeating the same multi-step property reference over and over (a textbook example of DRY).
This definitely makes the code easier to read too, both because you have a meaningful variable name and because it's just a simple variable rather than a multi-step property reference that has a generic name. While, it might technically be one additional line of code for the local variable assignment, it saves a lot of repeated property lookups so the theory is that it should be faster to save the end value into textBoxContent and not have to have the interpreter lookup e.target.value every time.
Also, you should never fall for people who want to micro-optimize regular code as they first write it. Optimizations like this generally only need apply to 0.000001% of all your code and only after you've proven exactly where your bottleneck for performance is. And, even then you will have to devise multiple benchmarks in your target environment to prove what actually makes things faster (not use one person opinion - measurements only).
Before that, all your code should first be correct, clear, readable, maintainable, extensible, DRY, appropriate performance and about 10 other priorities before anyone thinks about a micro-optimization. If you apply the above priorities to the case you asked about, you will always decide to assign e.target.value to a local variable if you are referencing it more than once within a context.

Is there any reason to define module.exports using an IIFE?

My team doesn't have any experienced JS developers, but we are writing a library in Node and got a suggestion from a real JS developer that "We should make the js more modular - not to pollute the global namespace and to make it more readable to new-comers", and told us to do the following:
module.exports = (function(){
return {
nameToExpose: functionToExpose
...
};
})();
rather than
module.exports.nameToExpose = functionToExpose;
What's the point of this, if any? The latter does not make any local declarations that would be scoped by the IIFE, and even if it did, they would be local to the module file and not global to the whole program that require()s it.
Some Googling and poking about this site does not turn up any answers on this particular question, though there are many other explanations of IIFEs that I have read (and which are summarized in the above comment). Some testing certainly reveals that the latter does not actually put functionToExpose in the global namespace, though its original name is recorded in the function type itself.
Pretty much no difference. The whole idea of Node.js, using require, having modules, etc., is specifically to separate concerns. I'd say (cautiously) that if you're doing it right, you shouldn't be needing to worry about "polluting" any sort of global scope. Anything within module.exports lives in that module.
When you're dealing with front-end stuff, that's when the global scope becomes something of a concern, because if a function or whatever isn't scoped (i.e., in an IIFE, or other function block), it has access to the global window object, and everything else has access to that function.
a real JS developer
Calling someone that is a red flag.
not to pollute the global namespace and to make it more readable to new-comers
If you're modularizing your code correctly, that shouldn't be a concern. There's a time and a place for IIFEs, but I see no reason why wrapping everything in an IIFE, which is already inside of a module, would somehow magically make the code "more modular" or any more readable to "new comers" than by simply using Node.js like it was designed:
module.exports = function() { ... } // whatever
and even if it did, they would be local to the module file and not global to the whole program that require()s it.
You are correct. I'd take whatever he's saying with a grain of salt. Maybe he knows of some specific use-cases where his approach has been helpful to him in the past, so I'd ask him specifically about that to see what he says. Other than that, I feel like you're on the right track.
The reason to maybe sometimes do this is because if you don't, then any variables you need for the module.exports object have to be scoped to the entire file.
Consider these two ways.
Without IIFE.
var foo = 'la' + 'la'; // some computed value
//
// ... lots of program code here ...
//
module.exports = {
foo : foo,
};
With IIFE.
//
// ... lots of program code here ...
//
module.exports = (function () {
var foo = 'la' + 'la'; // some computed value
return {
foo : foo
}
}());
In the first example, two problems arise.
Your variables (like foo) are created quite far away from where they are used to export a value from the module. This can reduce clarity. Sure, you can declare a variable after the program code, but it still has the same scope (and vars are hoisted). Plus, general best practice is to declare all your variables up front, and not doing so is a tradeoff to consider.
The program code can mess around with your variables, intentionally or accidentally, which complicates things and is undesirable unless you need that (sometimes you do).
The second example eliminates these problems by having a private scope for that area of the file. You can still use variables that are scoped to the entire file, but in cases where you don't need that, you can have variables that are easier to read and understand.
Often times we program for humans, not machines. This is an example of optimizing for the former.
Update:
In modern versions of JavaScript, const and let are probably better solutions to the problems this pattern aims to solve. With them, you can define variables in a way that will throw errors if you make the same mistakes the IIFE is trying to protect you from.
//
// ... lots of program code here ...
//
const foo = 'la' + 'la'; // some computed value
module.exports = {
foo : foo,
};
In the above example, if the program code uses foo, it will crash with a ReferenceError, because of the Temporal Dead Zone, as opposed to receiving undefined as a var would. This is great because now you must explicitly move the declaration of foo to an earlier place in the code if its use was intentional, or otherwise fix the code.
It's a good idea. There's a lot about javascript that seems to push the envelope of how 'modern programming' is done. Maybe one of those is the modular system of CommonJS. But the evolution in javascript has always been along the lines of the classical object oriented paradigms of software development. It most likely always will be.
Javascript may do things differently, but it doesn't do different things... if that makes sense.
It's always a good idea to protect scope and objects from excessive mutations.
https://medium.com/backticks-tildes/the-s-o-l-i-d-principles-in-pictures-b34ce2f1e898

Is there any real danger to overriding the default 'console' in node?

I'm a habit driven creature, and console.log/console.error/etc happens to be the thing I just instinctively use to print things out. However, I'm trying to drive all my logging in node to 'winston'. I'd prefer to do something like var console = require('./modules/logger'); at the top of my file and then just use console.whatever as usual.. tapping into extra arguments as necessary (otherwise the api is pretty much the same). Since this is localized to the file I'm working with and not some sort of global change, is there any danger in setting 'console' to that module's export? And not just "well, it might be confusing for someone else".
I did notice this question pop up as a similar question, but it doesn't really answer whether there's a danger behind it. And there's some other questions that ask if you can override some of node's core, but I'm not doing that - I'm just making a local reference using the same name as a "magic" global.
Other than possibly overriding existing console functions in a non-standard (i.e. unexpected) way, I do not see any danger in replacing the global console with your own object as long as it provides all the expected functions and calling conventions (function signatures) as the default console. I've done it many times without issue.
If you do provide some non-standard implementation of an existing function on the global console with a different signature than other code expects, you're bound to run into problems.
If you do your replacement in a module or function scope, only references in that scope would be affected.

Why is it bad to make elements global variables in Javascript?

I've heard that it's not a good idea to make elements global in JavaScript. I don't understand why. Is it something IE can't handle?
For example:
div = getElementById('topbar');
I don't think that's an implementation issue, but more a good vs bad practice issue. Usually global * is bad practice and should be avoided (global variables and so on) since you never really know how the scope of the project will evolve and how your file will be included.
I'm not a big JS freak so I won't be able to give you the specifics on exactly why JS events are bad but Christian Heilmann talks about JS best practices here, you could take a look. Also try googling "JS best practices"
Edit: Wikipedia about global variables, that could also apply to your problem :
[global variables] are usually
considered bad practice precisely
because of their nonlocality: a global
variable can potentially be modified
from anywhere, (unless they reside in
protected memory) and any part of the
program may depend on it. A global
variable therefore has an unlimited
potential for creating mutual
dependencies, and adding mutual
dependencies increases complexity. See
Action at a distance. However, in a
few cases, global variables can be
suitable for use. For example, they
can be used to avoid having to pass
frequently-used variables continuously
throughout several functions.
via http://en.wikipedia.org/wiki/Global_variable
Is it something IE can't handle?
No it is not an IE thing. You can never assume that your code will be the only script used in the document. So it is important that you make sure your code does not have global function or variable names that other scripts can override.
Refer to Play Well With Others for examples.
I assume by "events" you mean the event-handling JavaScript (functions).
In general, it's bad to use more than one global variable in JS. (It's impossible not to use at least one if you're storing any data for future use.) That's because it runs into the same problem as all namespacing tries to solve - what if you wrote a method doSomething() and someone else wrote a method called doSomething()?
The best way to get around this is to make a global variable that is an object to hold all of your data and functions. For example:
var MyStuff = {};
MyStuff.counter = 0;
MyStuff.eventHandler = function() { ... };
MyStuff.doSomething = function() { ... };
// Later, when you want to call doSomething()...
MyStuff.doSomething();
This way, you're minimally polluting the global namespace; you only need worry that someone else uses your global variable.
Of course, none of this is a problem if your code will never play with anyone else's... but this sort of thinking will bite you in the ass later if you ever do end up using someone else's code. As long as everyone plays nice in terms of JS global names, all code can get along.
There shouldn't be any problem using global variables in your code as long as you are wrapping them inside a uniqe namespase/object (to avoid collision with scripts that are not yours)
the main adventage of using global variable in javascript derives from the fact that javascript is not a strong type language. there for, if you pass somes complex objects as arguments to a function, you will probebly lose all the intellisence for those objects (inside the function scope.)
while using global objects insteads, will preserve that intellisence.
I personally find that very usfull and it certainly have place in my code.
(of course, one should alwayse make the right balance between locales and globals variables)

Categories

Resources