Implementing a Number.prototype.loop(callback) - javascript

How to pass a reference of an argument, originally passed to a prototype function, on to a callback function which, too, is passed to the same prototype function?
The objective of the implementation is to loop for the value of the Number by executing the callback function.
Number.prototype.loop = function(index, callback) {
return Array(this).fill(0).forEach((e, i) => {
if(callback)
callback();
});
};
var num = 3;
num.loop(index, function(){
console.log(index);
});
Solution
Apparently, the reference to index is supposed to be passed directly to the callback function in order to indicate that the actual index property of the Array in the prototype function is to be passed to the callback function.
Number.prototype.loop = function(callback) {
return Array(this).fill(0).forEach((e, i) => {
if(callback)
callback(i);
});
};
var num = 3;
num.loop((index) => {
console.log(index);
});

There are 2 errors.
Pass the index i to callback in Number.prototype.loop function instead of the caller:
num.loop(index, function(index) { → num.loop(function(index) {
Number.prototype.loop = function(index, callback) { → Number.prototype.loop = function(callback) {
callback(); → callback(i);
Pass the numerical value of this instead of the instance itself to the Array constructor:
Array(this) → Array(this.valueOf())
Number.prototype.loop = function(callback) {
var num = this.valueOf();
return Array(num).fill(0).forEach((e, i) => {
if (callback)
callback(i);
});
};
var num = 3;
num.loop(function(index) {
console.log(index);
});

You can extend a Number native class with a function loop as the following. However, it is advised to not extend native as per this eslint's rule described.
Number.prototype.loop = function (callback) {
[...Array(this.valueOf())].forEach((_, idx) => {
callback(idx);
})
};
const num = 30;
num.loop((idx) => {
console.log(idx);
})

Related

JavaScript simple call function behavior

I want to ask about call function behavior. I get stuck every time when I try to understand call function.
Can anybody help me to understand what is going on by suggesting implementation of the find method?
Hoge = function (val) {
this.val = val;
//console.log("this.val" + this.val);
};
Hoge.prototype.find = function (callback) {
callback.call(this.val);
};
var h = new Hoge(1);
h.find((o) => {
console.log(o); // expected 1 but undefined
console.log(o === 1); // expected true but its false (caz o is undefined)
});
You're not passing call a thisArg argument. Well, you are, but it's value you want passed to the callback.
Hoge = function(val) {
this.val = val;
//console.log("this.val" + this.val);
};
Hoge.prototype.find = function(callback) {
// callback.call(this.val);
callback.call(this, this.val); // call wants a "this" argument
// callback(this.val); // Could just do this instead
};
var h = new Hoge(1);
h.find((o) => {
console.log(o); // expected 1 but undefined
console.log(o === 1); // expected true but its false (caz o is undefined)
});
Function#call's first parameter is the this value. To directly invoke a function, just use parentheses.
callback(this.val);
Hoge = function (val) {
this.val = val;
};
Hoge.prototype.find = function (callback) {
callback(this.val);
};
var h = new Hoge(1);
h.find((o) => {
console.log(o);
console.log(o === 1);
});
The first param in call will be the new this you want to use. Then onwards are the params you want to pass.
You are basically not making a lot of use .call here, and if you simply want to use o you can pass null and this.val.
Even simpler, simply invoke the callback function
Hoge = function (val) {
this.val = val;
//console.log("this.val" + this.val);
};
Hoge.prototype.find = function (callback) {
//Both work
callback.call(null,this.val);
callback(this.val);
};
var h = new Hoge(1);
h.find((o) => {
console.log(o); // expected 1 but undefined
console.log(o === 1); // expected true but its false (caz o is undefined)
});

Get current value from an iterator

I was looking into javascript generators and iterators and was wondering if there is a way to write a generator function to return the value at the current position --- without of course having to call next() or to remember the returned value from the last next() call.
More specific, my failed attempt:
function* iterable(arr) {
this.index = 0;
this.arr = arr;
while(this.index < this.arr.length) {
yield this.arr[this.index++];
}
}
iterable.prototype.current = function () {
return this.arr[this.index];
}
const i = iterable([0, 1, 2]);
console.log(i.current()); // TypeError: Cannot read property 'undefined' of undefined
The desired functionality could be implemented using a class like this (I'm aware of the fact that the return values from the iterator would be objects like { value: 1, done: false }):
class iterableClass {
constructor(arr) {
this.index = 0;
this.arr = arr;
}
get(i) {
return this.index < arr.length ? this.arr[this.index] : false;
}
next() {
const val = this.get(this.index);
this.index++;
return val;
}
current() {
return this.get(this.index);
}
}
const i = iterableClass([0, 1, 2]);
console.log(i.current()); // 0
While I could just work with the class (or even a plain old function), I was wondering if this could be done with a generator/iterator or maybe there's an even better option.
The problem with your generator function is that a) it doesn't start running when you call it, it just creates the generator (this.arr and this.index won't be initialised until the first call to next()) and b) there is no way to access the generator object from inside the function like you tried with this.
Instead, you would want
function iterable(arr) {
const gen = Object.assign(function* () {
while (gen.index < gen.arr.length) {
yield gen.arr[gen.index++];
}
}(), {
arr,
index: 0,
current() {
return gen.arr[gen.index];
},
});
return gen;
}
Alternatively, instead of using generator syntax you can also directly implement the Iterator interface:
function iterable(arr) {
return {
arr,
index: 0,
current() { return this.arr[this.index]; },
next() {
const done = !(this.index < this.arr.length);
return { done, value: done ? undefined : this.arr[this.index++] };
},
[Symbol.iterator]() { return this; },
};
}
(which you could of course write as a class as well)
There seem to be multiple interpretations of this question. My understanding is that you want an iterator that provides a way to access the most recently-retrieved value, as shown by the last line in your final code block:
console.log(i.current()); // 0
Doing that isn't part of the iterator interface and isn't provided by generator functions. You could provide an iterator wrapper that did it, and then use that on the generator from the generator function (although you don't need a generator for what you're doing, the standard array iterator does it), see comments:
// Get the Iterator prototype, which has no global name
const itPrototype = Object.getPrototypeOf(
Object.getPrototypeOf([][Symbol.iterator]())
);
function currentWrapper(source) {
// Allow source to be an iterable or an iterator
if (Symbol.iterator in source) {
source = source[Symbol.iterator]();
}
// Create our wrapper iterator
const it = Object.create(itPrototype);
// Remember the last value we saw from `next`
let current = null;
// The iterator method
it.next = () => {
return current = source.next();
};
// Our additional methods
it.current = () => current && current.value;
it.currentResult = () => ({...current});
return it;
}
This has the advantage of being reusable and generic, not tied to a specific iterable.
Live Example:
// Get the Iterator prototype, which has no global name
const itPrototype = Object.getPrototypeOf(
Object.getPrototypeOf([][Symbol.iterator]())
);
function currentWrapper(source) {
// Allow source to be an iterable or an iterator
if (Symbol.iterator in source) {
source = source[Symbol.iterator]();
}
// Create our wrapper iterator
const it = Object.create(itPrototype);
// Remember the last value we saw from `next`
let current = null;
// The iterator method
it.next = () => {
return current = source.next();
};
// Our additional methods
it.current = () => current && current.value;
it.currentResult = () => ({...current});
return it;
}
// Something to iterate over
const a = [1, 2, 3];
// Example use #1: Using `current`
const it = currentWrapper(a[Symbol.iterator]());
console.log("current", it.current()); // undefined
console.log("next", it.next()); // {value: 1, done: false}
console.log("current", it.current()); // 1
console.log("currentResult", it.currentResult()); // {value: 1, done: false}
// Example use #2: Just normal use of an iterator
for (const value of currentWrapper(a)) {
console.log(value);
}
.as-console-wrapper {
max-height: 100% !important;
}
I focussed on the current bit and not the index bit because I think of iterables as streams rather than arrays, but I suppose it would be easy enough to add index. The slightly-tricky part is when the iterator has finished, do you increment the index when next is called or not? The below doesn't:
// Get the Iterator prototype, which has no global name
const itPrototype = Object.getPrototypeOf(
Object.getPrototypeOf([][Symbol.iterator]())
);
function currentWrapper(source) {
// Allow source to be an iterable or an iterator
if (Symbol.iterator in source) {
source = source[Symbol.iterator]();
}
// Create our wrapper iterator
const it = Object.create(itPrototype);
// Remember the last value we saw from `next` and the current "index"
let current = null;
let index = -1;
// The iterator method
it.next = () => {
// Don't increase the index if "done" (tricky bit)
if (!current || !current.done) {
++index;
}
return current = source.next();
};
// Our additional methods
it.current = () => current && current.value;
it.currentResult = () => ({...current});
it.currentIndex = () => index;
return it;
}
// Something to iterate over
const a = [1, 2, 3];
// Example use #1: Using `current`
const it = currentWrapper(a[Symbol.iterator]());
console.log("current", it.current()); // undefined
console.log("next", it.next()); // {value: 1, done: false}
console.log("current", it.current()); // 1
console.log("currentResult", it.currentResult()); // {value: 1, done: false}
console.log("currentIndex", it.currentIndex()); // 0
console.log("next", it.next()); // {value: 2, done: false}
console.log("current", it.current()); // 2
console.log("currentResult", it.currentResult()); // {value: 2, done: false}
console.log("currentIndex", it.currentIndex()); // 1
// Example use #2: Just normal use of an iterator
for (const value of currentWrapper(a)) {
console.log(value);
}
.as-console-wrapper {
max-height: 100% !important;
}
Why not use a function from MDN Iterators and generators, where just the return part is replaced by the value instead of an object with value and done property
function makeIterator(array) {
var nextIndex = 0,
lastValue;
return {
next: function() {
return lastValue = nextIndex < array.length ? array[nextIndex++] : undefined;
},
last: function () {
return lastValue;
}
};
}
var it = makeIterator(['yo', 'ya']);
console.log(it.next());
console.log(it.next());
console.log(it.last());
console.log(it.next());

lodash.debounce get previous function's call arguments

When _.debounce is called multiple times, it only apply with the last call's argument.
var f = _.debounce(function(a) {
console.log(a);
})
f(12)
f(1223)
f(5)
f(42)
//output -----> 42
Is there a way to get previous function's call arguments as well ?
ex:
var f = _.customDebounce(function(a) {
console.log(a);
})
f(12)
f(1223)
f(5)
f(42)
//output -----> [12, 1223, 5, 42]
I finaly made my own implementation of this function, extending lodash:
_.mixin({
debounceArgs: function(fn, options) {
var __dbArgs = []
var __dbFn = _.debounce(function() {
fn.call(undefined, __dbArgs);
__dbArgs = []
}, options);
return function() {
__dbArgs.push(_.values(arguments));
__dbFn();
}
},
throttleArgs: function(fn, options) {
var _thArgs = []
var _thFn = _.throttle(function() {
fn.call(undefined, _thArgs);
_thArgs = []
}, options);
return function() {
_thArgs.push(_.values(arguments));
_thFn();
}
},
})
Usage:
_.debounceArgs(function(a) {
console.log(a);
})
Here's a simplistic debounce that tracks its arguments. It doesn't try to mimic the last parameter of _.debounce
function customDebounce(func, wait) {
var args = [];
var timeoutId;
return function() {
// User formal parameters to make sure we add a slot even if a param
// is not passed in
if (func.length) {
for (var i = 0; i < func.length; i++) {
if (!args[i]) {
args[i] = [];
}
args[i].push(arguments[i]);
}
}
// No formal parameters, just track the whole argument list
else {
args.push(_.toArray(arguments));
}
clearTimeout(timeoutId);
timeoutId = setTimeout(function() {
func.apply(this, args);
args = [];
}, wait);
}
}
// For named arguments, each of the arguments becomes an array that tells
// you how many times it was called
var f = customDebounce(function(a, b, c) {
console.log('Debounced func called',
a.length,
'times', JSON.stringify({
a: a,
b: b,
c: c
}));
});
f(1, 3);
f(2, 3, 5);
f(3);
f(4, 2, 3);
// Debounced func called 4 times
// {"a":[1,2,3,4],"b":[3,3,null,2],"c":[null,5,null,3]}
// Can also be used with unnamed arguments, parameters are passed a little
// differently, each element in `arguments` is the array of arguments for
// that call, the latest one being at the end of the array
var g = customDebounce(function() {
console.log('Debounced no params func called ',
arguments.length,
'times',
JSON.stringify({
args: _.toArray(arguments)
}));
});
g(1, 3);
g(2, 3, 5);
g(3);
g(4, 2, 3);
// Debounced no params func called 4 times
// {"args":[[1,3],[2,3,5],[3],[4,2,3]]}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>

Can JS callback functions ever return a value?

I totally understand why a callback function can't return a value if the logic inside the callback is doing or fetching something on an external server.
What I don't quite get is why does a callback function not return a value if everything inside the callback function is normal, synchronous code:
var myFunc = function(input, callback){
var sum = input + 10;
callback(sum);
};
sum = myFunc(1000, function(input){
console.log(input);
return input + 9000;
});
sum still returns undefined, even though the console.log logs a value of 1010.
Is it a hard and fast rule that callbacks can NEVER return anything?
And do all callbacks in other languages also never return anything?
EDIT
Here's a more complicated example - which also doesn't return anything
discounts = [
{
sku: "126D",
title: "Discount for using 126",
discountCode: "LOVE126",
discountAmount: -2500,
check: function(orderFormContents, callback) {
var discountsApplied = orderFormContents.discountsApplied;
var sqft = orderFormContents.propertyInfo.sqft;
for (var i = discountsApplied.length - 1; i >= 0; i--) {
if (discountsApplied[i].discountCode === this.discountCode) {
if (sqft < 1501) {
return callback('', 'Coupon Added', this.discountAmount);
} else {
return callback('', 'Coupon Added', (this.discountAmount + -2500));
};
};
};
}
},
// additional discount objects in array
];
var checkDiscount = function(code, orderFormContents, allDiscounts) {
for (var i = allDiscounts.length - 1; i >= 0; i--) {
if (allDiscounts[i].discountCode === code) {
allDiscounts[i].check(orderFormContents, function(error, message, amount) {
var result = {
"error": error,
"message": message,
"amount": amount
};
debugger
return result;
});
};
};
};
var orderFormContents = {
propertyInfo: {
sqft: 1000
},
discountsApplied: [
{
discountCode: "LOVE126"
}
]
};
var discountCode = "LOVE126";
var result = checkDiscount(discountCode, orderFormContents, discounts);
debugger
console.log(result);
You're missing the return statement in myFunc.
var myFunc = function(input, callback){
var sum = input + 10;
return callback(sum);
};
sum = myFunc(1000, function(input){
console.log(input);
return input + 9000;
});
For extra clarification, there's nothing terribly special about your callback in this example. If you chain functions, you just need to make sure you return each result. We could rewrite the current example as:
function myInnerFunc(sum) {
return sum + 9000;
}
function myFunc (input){
var sum = input + 10;
return myInnerFunc(sum);
}
var sum = myFunc(1000);
But, the nature of first-class functions in JavaScript allows us to pass functions around. This becomes interesting in functional programming, where one function can now be passed various other functions for different results.
function add (a, b) {
return a + b;
}
function multi (a, b) {
return a * b;
}
var list = [1, 2, 3, 4, 5];
console.log(list.reduce(add)); // 15
console.log(list.reduce(multi)); // 120
Asynchronous operations fire their callbacks at some later time, so they can't be used to return values right away. The easiest example of this is setTimeout which calls its callback after N milliseconds. In this example myFunc will have returned long before the setTimeout has had a chance to fire its callback. Same logic can be applied to AJAX callbacks.
function myFunc (value) {
var val;
window.setTimeout(function () {
val = value;
}, 1000)
return val;
}
var test = myFunc(1000)
console.log(test); // undefined
Answer Part 2: Electric Boogaloo
You're still missing a return.
This line
var result = checkDiscount(discountCode, orderFormContents, discounts);
assigns the result from checkDiscount, but that function doesn't return anything.
var checkDiscount = function(code, orderFormContents, allDiscounts) {
for (var i = allDiscounts.length - 1; i >= 0; i--) {
if (allDiscounts[i].discountCode === code) {
allDiscounts[i].check(orderFormContents, function(error, message, amount) {
var result = {
"error": error,
"message": message,
"amount": amount
};
return result;
});
}
}
// Never returned, default return value is undefined
};
You can fix this by returning properly.
var checkDiscount = function(code, orderFormContents, allDiscounts) {
for (var i = allDiscounts.length - 1; i >= 0; i--) {
if (allDiscounts[i].discountCode === code) {
return allDiscounts[i].check(orderFormContents, function(error, message, amount) {
var result = {
"error": error,
"message": message,
"amount": amount
};
return result;
});
}
}
};
Honestly, this code is really looptastic, and could most likely be refactored into something more concise.

convert the following code from a for-loop to Array#map

i am working on simple js function...
I am trying to convert the following code from a for-loop to Array#map
providing my code below in the fiddle..
bnasically i am trying to learn array map..
http://jsfiddle.net/newtdms2/
function doubleAll(numbers) {
var result = [];
result = numbers.map(function(num) {
for (var i = 0; i < numbers.length; i++) {
result.push(numbers[i] * 2)
}
return result;
});
}
module.exports = doubleAll
You don't have to create a for loop in your map, map will call the function callback on each element of the array you pass as parameter. So just try something like :
function doubleAll(numbers) {
return numbers.map(function (num) {
return num * 2;
});
}
Here is the doc for the map method, could be interesting to you !
Your for inside map is not required:
function doubleAll(numbers) {
var result = [];
result = numbers.map(function(num) {
return (num * 2);
});
return result;
}
And simpler can be:
function doubleAll(numbers) {
return numbers.map(function(num) {
return (num * 2);
});
}
Array.prototype.map: will loop once through each element in an array. It receives a callback function as the argument and the callback function takes three arguments, being the first 2:
currentItem: The element being processed in the array in the example above num.
index: The index of the element being processed in the array, in for loop this will be i.
function doubleAll(numbers) {
return numbers.map(num => num*2);
}

Categories