I come from Java/Swift environment. So, I'm used to show the user of my code only "what is necessary".
For JavaScript I use Visual Code.
When I try to use the Intellisense feature, it shows all my functions/methods when I import it.
So, to hide the unnecessary functions, I opted for using nested functions.
Check out this quicksort code:
/**
* Sorts the Array in-place
*
* @param {Array.<Number | String>} array Array to be sorted
*/
function sort(array) {
quickSort(array, 0, array.length - 1);
/**
* Quicksort implementation
*
* @param {Array.<Number | String>} array
* @param {Number} start Start index of the array for quicksort
* @param {Number} end End index of the array for quicksort
*/
function quickSort(array, start, end) {
if (start < end) {
let pivot = partition(array, start, end);
quickSort(array, start, pivot - 1);
quickSort(array, pivot + 1, end);
}
/**
* Partitions the array for Quicksort
*
* @param {Array.<Number | String>} array
* @param {Number} left Starting index of starting of array/sub-array
* @param {Number} right Ending index of starting of array/sub-array
* @returns {Number} Returns pivot index
*/
function partition(array, left, right) {
let pivot = array[right];
let i = left - 1;
for (var j = left; j < right; j++) {
if (array[j] <= pivot) {
i++;
let temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
let temp = array[i + 1];
array[i + 1] = array[right];
array[right] = temp;
return i + 1;
}
}
}
Is this nesting appropriate? Because I(beginner) feel like if the nested functions are big, the readability(I mean like figuring out what the code is doing) is an issue.
Or should I just follow the classic _
before the function names to indicate it as a private or not meant to be used by the user?
A simple code breaking example:
For the user of the
sort()
,partition()
andquickSort()
is an unnecessary functions. Which in-turn can cause collisions if the user names their functionpartition()
(because I might not have mentionedpartition()
in my API as it is not usable on its own).
And also any advice to improve the above code is welcome.
1 Answer 1
Nesting functions
There is nothing wrong with your approch, a few years back and I would have not said so as some browsers would parse functions within functions each time they were call, with the obvious performance hit. That is a thing of the past and functions are parsed then cached for use next time the function is called.
Modules to keep global scope clean.
Modern JS has modules that let you define exports and then import them as needed in other modules
Each module has its own top level context and thus does not add to the global scope.
Use the export
token to define what can be imported.
The only way to access items in the module is via the import
token, and only those items explicitly exported.
Modules also use strict mode by default.
Thus you can flatten you code without worrying about name conflicts.
If you create a default export in a module you can also import it under another name.
Example of a module, and flatting your quick sort.
/* in file quickSort.js */
export default function sort(array) {
quickSort(array, 0, array.length - 1);
}
function quickSort(array, start, end) {
if (start < end) {
let pivot = partition(array, start, end);
quickSort(array, start, pivot - 1);
quickSort(array, pivot + 1, end);
}
}
function partition(array, left, right) {
let pivot = array[right];
let i = left - 1;
for (var j = left; j < right; j++) {
if (array[j] <= pivot) {
i++;
let temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
let temp = array[i + 1];
array[i + 1] = array[right];
array[right] = temp;
return i + 1;
}
To access it from another module
import sort from "quickSort";
sort([4,3,6,3,7,8]);
Or use another name, but only for the default export.
import qSort from "quickSort";
qSort([4,3,6,3,7,8]);
Note that modules must be in files for both export
code and import
code, and the script element must be of type "module" eg <script type="module" src="quickSort.js"></script>
Also as a convention not a requirement modules have the extension .mjs
rather than .js
and some will use .es.mjs
. They all have the same MIME type text/javascript
Singleton
Before modules it was common to use the singleton (AKA immediately invoked function) to reduce or completely eliminate any intrusion to the global scope.
Example of a singleton
const sort = (() => {
function sort(array) {
quickSort(array, 0, array.length - 1);
}
function quickSort(array, start, end) {
if (start < end) {
let pivot = partition(array, start, end);
quickSort(array, start, pivot - 1);
quickSort(array, pivot + 1, end);
}
}
function partition(array, left, right) {
let pivot = array[right];
let i = left - 1;
for (var j = left; j < right; j++) {
if (array[j] <= pivot) {
i++;
let temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
let temp = array[i + 1];
array[i + 1] = array[right];
array[right] = temp;
return i + 1;
}
return sort;
})();
sort([4,3,6,3,7,8]);
-
\$\begingroup\$ Singleton seems a nice idea(with out shoving everything inside a function) when we are not using modules. \$\endgroup\$SkrewEverything– SkrewEverything2018年07月26日 18:34:28 +00:00Commented Jul 26, 2018 at 18:34
Explore related questions
See similar questions with these tags.
sort()
,partition()
andquickSort()
is an unnecessary functions. Which in-turn can cause collisions if the user names their functionpartition()
(because I might not mentionedpartition()
in my API as it is not usable on its own) even though the implementation is not related to mysort()
. \$\endgroup\$