I tested performance with a script from "Secrets of Javascript Ninja":
function isPrime(number) {
if (number < 2) {
return false;
}
for (let i = 2; i < number; i++) {
if (number % i === 0) {
return false;
}
}
return true;
}
console.time("isPrime");
isPrime(1299827);
console.timeEnd("isPrime");
console.time("isPrime");
isPrime.apply(1299827);
console.timeEnd("isPrime");
And the result is:
isPrime: 8.276ms
isPrime: 0.779ms
Seems that "apply" is faster?
Your comparison is not accurate, because the first parameter passed to apply is the this value of the called function, and the second parameter passed to apply is an array of parameters that function is to be called with. So, your apply is not calling isPrime with any parameters, so no iterations run, because the condition i < number is not fulfilled when i is 2 and number is undefined:
function isPrime(number) {
console.log('calling with ' + number);
if (number < 2) {
return false;
}
for (let i = 2; i < number; i++) {
if (number % i === 0) {
return false;
}
}
return true;
}
console.time("isPrime");
isPrime(1299827);
console.timeEnd("isPrime");
console.time("isPrime");
isPrime.apply(1299827);
console.timeEnd("isPrime");
If you use apply properly and pass in undefined, [1299827], the result is as expected, very similar. You should also use performance.now() for better precision than console at the millisecond level, though for such a quick operation you might not see that might difference anyway:
function isPrime(number){
console.log('calling with ' + number);
if(number < 2) { return false; }
for(let i = 2; i < number; i++) {
if(number % i === 0) { return false; }
}
return true;
}
const t1 = performance.now();
isPrime(1299827);
const t2 = performance.now();
isPrime.apply(undefined, [1299827]);
console.timeEnd("isPrime");
const t3 = performance.now();
console.log(t2 - t1);
console.log(t3 - t2);
The syntax for .apply is
function.apply(thisArg, [argsArray])
the first parameter thisArg refers to the value of 'this' when calling the function, in your case isPrime.apply(1299827) you passed in 1299827 as 'this' but no parameter, so it's really isPrime(), the for loop is not excuted so it's faster
more on .apply here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
You have to read this.
reference: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/apply
This point is Array.prototype.apply(context = this, args = []), so your code is wrong.
Change your code to this.
// incorrect.
isPrime.apply(1299827);
// correct.
isPrime.apply(this, 1299827);
Related
I have an exercise about JavaScript. This exercise requires me to use higher-order functions. I have managed to specify some of the functions so far, but when I try to execute the code, the result does not seem to work properly. I have some images to give you an idea, hopefully, you can help me correct this.
The thread is: Write the function loop(loops, number, func), which runs the given function the given number of times. Also write the simple functions halve() and square().
This is my code:
function loop(loops, number, func) {
var loops = function(n) {
for (var i = 0; i < n; i++) {
if (i < 0) {
console.log('Programme ended')
}
if (i > 0) {
return n;
}
}
}
}
var halve = function(n) {
return n / 2
}
var square = function(n) {
return n ** 2;
}
console.log(halve(50));
console.log(loop(5, 200, halve));
console.log(loop(3, 5, square));
console.log(loop(-1, 99, halve));
Your current loop function declares an inner function and then exits. Ie, nothing actually happens -
function loop(loops,number,func){
// declare loops function
var loops= function(n){
// ...
}
// exit `loop` function
}
One such fix might be to run the supplied func a number of times in a for loop, like #code_monk suggest. Another option would be to use recursion -
function loop (count, input, func) {
if (count <= 0)
return input
else
return loop(count - 1, func(input), func)
}
function times10 (num) {
return num * 10
}
console.log(loop(3, 5, times10))
// 5000
so first things first: Higher-Order functions are functions that work on other functions.
The reason why you get undefined is because you are calling a function which doesn't return anything.
function x(parameter){
result = parameter + 1;
}
// -> returns undefined every time
console.log(x(5));
// -> undefined
function y(parameter){
return parameter+1;
}
// -> returns a value that can be used later, for example in console.log
console.log(y(5));
// -> 6
Second, you are using n for your for loop when you should probably use loops so it does the intended code as many times as "loops" indicates instead of the number you insert (i.e. 200, 5, 99).
By having the "console.log" inside a loop you may get a lot of undesired "programme ended" in your output so in my version I kept it out of the loop.
The other two answers given are pretty complete I believe but if you want to keep the for loop here goes:
function loop(loops, number, func){
if(loops>0){
for(let i = 0; i< loops; i++){ // let and const are the new ES6 bindings (instead of var)
number = func(number)
}
return number
}
else{
return "Programme ended"
}
}
function halve(n) { // maybe it's just me but using function declarations feels cleaner
return n / 2;
}
function square(n) {
return n ** 2;
}
console.log(halve(50));
console.log(loop(5, 200, halve));
console.log(loop(3, 5, square));
console.log(loop(-1, 99, halve));
Here's one way
const loop = (loops, n, fn) => {
for (let i=0; i<loops; i++) {
console.log( fn(n) );
}
};
const halve = (n) => {
return n / 2;
};
const square = (n) => {
return n ** 2;
};
loop(2,3,halve);
loop(4,5,square);
This a simple code for factorial, I have written the function and it loops through giving right output but at the end, it returns undefined. I don't know why.
function factorial(n){
let value=1;
for(let i=1;i<=n;i++) {
value = i*value;
console.log(value);
}
}
Because you do not return anything from the function, so undefined is the result of its work.
You need to return the value explicitly:
function factorial(n){
let value=1;
for(let i=1;i<=n;i++) {
value = i*value;
console.log(value);
}
return value;
}
You can find factorial by using recursion. Here is the implementation.
function factorial(x){
if(x == 0) //Exit condition
return 1;
return x * factorial(x-1); //5*4*3*2*1
}
console.log(factorial(5));
This is good implementation:
const factorial = n => n > 1 ? n * factorial(--n) : 1;
And your function does not have return, so it returns undefined;
I have a 'twice' function that return 2 of the argument passed into it. I also have another function 'runTwice' that counts the number of times it called the 'twice' function (the idea being that I want the 'twice' function to only run 'twice' no matter how often it is called via the 'runTwice' function). Can you please help?
Functions are given below:
var count = 1;
function twice(num){
return num*2;
}
function runTwice(func){
if (count<3){
count++;
return func;
} else {
return 'Function cannot run!';
}
}
var myFunc = runTwice(twice)
var output = [];
for (var i = 0; i < 3; i++){
output.push(myFunc(i));
}
console.log(output);
I would like the output to be [0, 2, 'Function cannot run!'].
I can make this work if I count the 'twice' function directly but I am looking to understand why this doesn't work as presented above.
Just for fun I'll make a generic expireAfter(invocable[, times[, message]]) function:
function expireAfter(invocable, times = 2, message = 'Function cannot run!') {
return function expires() {
if (times > 0) {
times--;
return invocable.apply(this, arguments);
}
return message;
}
}
function twice(n) {
return n * 2;
}
var myFunc = expireAfter(twice);
console.log(Array(3)
.fill()
.map((_, index) => myFunc(index))
);
The function runTwice should return another function that will decide whether to call the function func (using Function.prototype.apply) or to return a string message instead:
function twice(num){
return num * 2;
}
function runTwice(func){
var count = 0; // this will be trapped in a closure along with func
return function() { // this is the function that gets called
count++; // it increments its version of the count variable
if(count <= 2) // if count is less than 2
return func.apply(this, arguments); // then it calls the function func with whatever arguments passed into it and return the returned value of that call
return "Not available anymore!"; // otherwise (count > 2), then it returns a string
}
}
var myFunc = runTwice(twice);
for (var i = 0; i < 3; i++){
console.log(myFunc(i));
}
Even better:
You can pass in the number of times allowed as well:
function double(num) {
return num * 2;
}
function triple(num) {
return num * 3;
}
function run(func, times){
var count = 0; // this will be trapped in a closure along with func and times
return function() { // this is the function that gets called
count++; // it increments its version of the count variable
if(count <= times) // if count is less than times
return func.apply(this, arguments); // then it calls the function func with whatever arguments passed into it and return the returned value of that call
return "Not available anymore!"; // otherwise (count > times), then it returns a string
}
}
var double2times = run(double, 2); // double2times can only be called 2 times
var triple5times = run(triple, 5); // triple5times can only be called 5 times
for (var i = 0; i < 10; i++){
console.log("Double:", double2times(i));
console.log("Triple:", triple5times(i));
}
I noticed if I use += in recursion it runs indefinitely because the variable being used in the termination statement doesn't increase in value. I can't figure out why, I've already looked on the forum for an answer but didn't see one. I'm trying to figure out if I'm doing something wrong and if not I'm looking for an answer on the specifics as to why it's not working.
//this works fine
function recure(n = 0) {
if (n > 10) {
console.log('The End');
return '';
}
console.log(n);
setTimeout(function () {
recure(n + 1)
}, 1000);
}
recure();
//this also works fine, note it's working with n+=1
function loop(amount = 10, n = 1) {
for (let i = 0; i < amount; i++) {
console.log(n);
n += 1;
}
}
//This doesn't work and is the reason for the post, why?
function recure(n = 0) {
if (n > 10) {
console.log('The End');
return '';
}
console.log(n);
n += 1;
setTimeout(function () {
recure()
}, 1000);
}
recure(); //it indefinitely logs 0
n is local to the particular call of a function. Since you call your function without arguments it will bind the new n gets bound to 0.
function test(n=0){
return n;
}
test(); //==> 0
test(2); //==> 2
Recursion isn't really treated special so if you assume that n is kept between calls to recure this should also happen:
function other(n=0) {
return n;
}
function test(n=0) {
n++;
return other();
}
test(0); // ==> 1
However this is absurd since n is local and thus every call have it's won n even if the function is the same.
Also note that the third example is not recursion since the call stack gets reset.
The anonymous function where you call recure has n in it's lexical scope so you can just call it with n+1 so the new recure will get a n that is one higher than the call the thunk derived from.
In JavaScript scope of variables is defined by functions. So, when you are calling the function recure() a new scope is getting created with new "N" in each scope.
Let's try to understand what you are doing here:
1. You called recure().
// No argument hence "N" is undefined therefore N is assigned 0.
2. You incremented value of "N"
// New value of "N" = 1
3. You recursively called recure()
// Again no argument hence "N" is 0
// Since, recure() is called again new scope is created
// This "N" is different from the "N" used is step 1
4. Bad recursion --> #Fail.
//this works fine
function recure(n = 0){
if (n > 10) {
console.log('The End');
return '';
}
console.log(n);
setTimeout(function() {
recure(n + 1)
}, 1000);
}
recure();
//this also works fine, note it's working with n+=1
function loop(amount = 10, n = 1) {
for (let i = 0; i < amount; i++) {
console.log(n);
n += 1;
}
}
//This doesn't work and is the reason for the post, why?
function recure(n = 0) {
if (n > 10) {
console.log('The End');
return '';
}
console.log(n);
n += 1;
setTimeout(function(){recure(n)},1000);
}
recure(); //it indefinitely logs 0
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
This should work
function recure(n=0){
if(n>10){
console.log("The End");
return "";
}
console.log(n);
n+=1;
setTimeout(function(){recure(n)},1000);
}
recure();
At every stage of recursion, that particular closure should know the previous recursion state.
We are passing 'n' to know the state of recursion.
I am trying to practice functional programming and I started by working with forEach and reduce to count zeroes in a given array (a problem in eloquent JavaScript chapter 5). But I do not understand why my code works in some instances but not others.
The code below doesn't work and leaving out the else statement seems to be the problem. But why is the else statement necessary here and not in some of the cases I post towards the end of the post?
function forEach(arr, action) {
for(var i = 0; i < arr.length; i++) {
action(arr[i]);
}
}
function reduce(cb, start, array) {
forEach(array, function(el) { start = cb(start, el); });
return start;
}
function countZeroes(array) {
function counter(total, element) {
if(element === 0) return total + 1; //excluding else statement seems to be the issue but why?
}
return reduce(counter, 0, array);
}
console.log(countZeroes([0,1,0,2,0,3, 0,4,2,0])); //returns NaN
If I rewrite the function as such with an else statement it works:
function forEach(arr, action) {
for (var i = 0; i < arr.length; i++) {
action(arr[i]);
}
}
function reduce(cb, start, array) {
forEach(array, function(el) {
start = cb(start, el);
});
return start;
}
function countZeroes(arr) {
function counter(total, element) {
if (element === 0) {
return total + 1;
} else {
return total;
}
}
return reduce(counter, 0, arr);
}
console.log(countZeroes([0, 1, 2, 0]));
However, the code does not require the else statement in the cases below, why?
function countTarget(arr, target) {
var counter = 0;
for(var i = 0; i < arr.length; i++) {
if(arr[i] === target) counter++; //no else statement required here
}
return counter;
}
console.log(countTarget([0,1, 0, 0, 2, 3, 0, 3, 0, 0, 0], 0));
function forEach(arr, action) {
for(var i = 0; i < arr.length; i++) {
action(arr[i]);
}
}
function test(a) {
return a === 0;
}
function countTarget(arr, target) {
var counter = 0;
forEach(arr, function(el) {
if (test(el)) counter++;
});
return counter;
}
console.log(countTarget([1, 2, 3, 0, 3, 0], 0));
I would appreciate thoughts.
Whatever gets returned from your counter function is the passed to the next call to counter. Therefore, you need to return something on your counter function. If the condition doesn't get satisfied, return the unaffected total:
function counter(total, element) {
return (element === 0) ? total + 1 : total;
}
Explanation: your counter function increments a "total" value depending on some logic and returns the incremented value. The returned value is then passed to the counter function again. Your counter function has a code path which doesn't return a value (when the if statement doesn't pass). In this case, you're not returning anything... which is similar to returning undefined. If you were to isolate this, it would look kind of like this:
// Let's say your current "total" count is 15
var total = counter(15, 2);
console.log(total); //-> undefined
Since 2 !== 0 - the condition didn't pass and the result of the function is undefined. Now, the next time counter is called, it will look like this:
var total = counter(undefined, 0);
Since 0 === 0, the condition will pass, and it will try to increment the total... which is undefined:
return undefined + 1; //-> NaN
Hope that helps.
function counter(total, element) {
if(element === 0) return total + 1; //excluding else statement seems to be the issue but why?
}
in this function, you are returning some value (total + 1) when the element is 0. so for every other case this function returns undefined as you did not specify any value for else case.
undefined + number = NaN
you can check the returned value from counter like this
forEach(array, function(el) {
console.log(start);
start = cb(start, el);
});
case 1: no else
console.log(countZeroes([0,1,0,2,0,3, 0,4,2,0]));
logged values
0 1 undefined NaN so on
case 2: with else
console.log(countZeroes([0,1,0,2,0,3, 0,4,2,0]));
logged values
0 1 1 2 2 3 so on
EDIT
when you define a function like below
function f_name() {
// calculations
return some_value;
}
javascript implements it as
function f_name() {
// calculations
return some_value;
return undefined; // implied by javascript
}
a function can have multiple return statements and function returns when it encounters a return in the execution flow and the remaining code becomes unreachable.
so, in your case
function counter(total, element) {
if(element === 0) return total + 1; //excluding else statement seems to be the issue but why?
return undefined; // implied
}
when the element value is 0, the function return total + 1 and the remaining code(return undefined;) becomes unrechable but when element is not 0, the function executes return undefined.
Hope this clarifies your doubt.