Javascript syntax with functions - javascript

I'm not sure what this means or how to word the question correctly.
In the first example I could put the variable before the function "numbers1.forEach(...)" but in the second example I could not "num.square()"?
function forEach(array, action) {
for (var i = 0; i < array.length; i++)
action(array[i]);
}
var numbers2 = [1, 2, 3, 4, 5], sum = 0;
forEach(numbers2, function(number) {
sum += number;
});
console.log(sum);
// → 15
var numbers1 = [1, 2, 3, 4, 5], sum = 0;
numbers1.forEach(function(number) {
sum += number;
});
console.log(sum);
// → 15
// this works!
But this does not work
var square = function(x) {
return x * x;
};
var num = 12;
console.log(square(num));
// → 144
console.log(num.square());
// → TypeError: undefined is not a function (line 9)
// does not work?
Thanks!

Syntax-wise, there's no "magic" happening here. You're describing two very different things.
In your first example, you're passing an Array to your own defined forEach method. In the second example, the forEach you're calling is actually a built-in method on Arrays (see MDN). If you changed your forEach to not invoke action, you'll see that yours breaks and the second one still works.
You can achieve this functionality yourself. You could add a function to Number to make your second example work (although this is not a recommended practice, as it could collide with future JavaScript features [and many other reasons] or break existing functionality):
Number.prototype.square = function() {
return this * this;
};
var num = 12;
var squared = num.square();
alert(squared);

If you remove the forEach function from your first example, it will still work, that is because the Array type has a builtin forEach function.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
Alternatively try to change your forEach function to each and you will see that it will no longer work.
What you are trying to do is add a new method to an existing type. This is not good practice in JavaScript.

The example with the array works because Array in JavaScript (ECMAScript5) defines a forEach function.
The example with the number doesn't work because Number doesn't define a square function. You can extend Number to include the square function like this:
Number.prototype.square = function(x) {
return this * this;
};

Related

Number prototype

Hi everyone i need an help.
I try to modify Number.prototype to add the function sum.
I want to add some numbers to my initial number.
Number.prototype.sum = async (...nums) => {
var x = //What I have to write to have my inizial number here?
for (var i = 0;i<nums.length;i++) {
x=x+nums[i]
}
return x
}
console.log((10).sum(2)) // output: 12
console.log((10).sum(4,6)) // output: 20
(I use visual studio code and the hint after this. is only number)
I tried with:
Number.prototype.valueOf(this)
Number.prototype.valueOf(this.number)
Number.parseInt(this.toString())
Number.parseFloat(this.toString())
Number.parseInt(this.number.toString())
Number.parseFloat(this.number.toString())
this.valueOf()
this.number.valueOf()
You have to use function to access the correct this context (which is the number that the method is called on). Arrow functions inherit their this context from the parent scope (the global object in this case). Also async is not needed since you are not doing anything asynchronous here:
Number.prototype.sum = function (...nums) {
var x = this
for (var i = 0; i < nums.length; i++) {
x = x + nums[i]
}
return x
}
console.log((1).sum(2, 3))
Aside from the fact that augmenting native prototypes is a bad idea, wouldn't you think that a function like this is better suited for the Array prototype?

Allocation-free abstractions in Javascript

I have a general question which is about whether it is possible to make zero-allocation iterators in Javascript. Note that by "iterator" I am not married to the current definition of iterator in ECMAScript, but just a general pattern for iterating over user-defined ranges.
To make the problem concrete, say I have a list like [5, 5, 5, 2, 2, 1, 1, 1, 1] and I want to group adjacent repetitions together, and process it into a form which is more like [5, 3], [2, 2], [1, 4]. I then want to access each of these pairs inside a loop, something like "for each pair in grouped(array), do something with pair". Furthermore, I want to reuse this grouping algorithm in many places, and crucially, in some really hot inner loops (think millions of loops per second).
Question: Is there an iteration pattern to accomplish this which has zero overhead, as if I hand-wrote the loop myself?
Here are the things I've tried so far. Let's suppose for concreteness that I am trying to compute the sum of all pairs. (To be clear I am not looking for alternative ways of writing this code, I am looking for an abstraction pattern: the code is just here to provide a concrete example.)
Inlining the grouping code by hand. This method performs the best, but obscures the intent of the computation. Furthermore, inlining by hand is error-prone and annoying.
function sumPairs(array) {
let sum = 0
for (let i = 0; i != array.length; ) {
let elem = array[i++], count = 1
while (i < array.length && array[i] == elem) { i++; count++; }
// Here we can actually use the pair (elem, count)
sum += elem + count
}
return sum
}
Using a visitor pattern. We can write a reduceGroups function which will call a given visitor(acc, elem, count) for each pair (elem, count), similar to the usual Array.reduce method. With that our computation becomes somewhat clearer to read.
function sumPairsVisitor(array) {
return reduceGroups(array, (sofar, elem, count) => sofar + elem + count, 0)
}
Unfortunately, Firefox in particular still allocates when running this function, unless the closure definition is manually moved outside the function. Furthermore, we lose the ability to use control structures like break unless we complicate the interface a lot.
Writing a custom iterator. We can make a custom "iterator" (not an ES6 iterator) which exposes elem and count properties, an empty property indicating that there are no more pairs remaining, and a next() method which updates elem and count to the next pair. The consuming code looks like this:
function sumPairsIterator(array) {
let sum = 0
for (let iter = new GroupIter(array); !iter.empty; iter.next())
sum += iter.elem + iter.count
return sum
}
I find this code the easiest to read, and it seems to me that it should be the fastest method of abstraction. (In the best possible case, scalar replacement could completely collapse the iterator definition into the function. In the second best case, it should be clear that the iterator does not escape the for loop, so it can be stack-allocated). Unfortunately, both Chrome and Firefox seem to allocate here.
Of the approaches above, the custom-defined iterator performs quite well in most cases, except when you really need to put the pedal to the metal in a hot inner loop, at which point the GC pressure becomes apparent.
I would also be ok with a Javascript post-processor (the Google Closure Compiler perhaps?) which is able to accomplish this.
Check this out. I've not tested its performance but it should be good.
(+) (mostly) compatible to ES6 iterators.
(-) sacrificed ...GroupingIterator.from(arr) in order to not create a (imo. garbage) value-object. That's the mostly in the point above.
afaik, the primary use case for this is a for..of loop anyways.
(+) no objects created (GC)
(+) object pooling for the iterators; (again GC)
(+) compatible with controll-structures like break
class GroupingIterator {
/* object pooling */
static from(array) {
const instance = GroupingIterator._pool || new GroupingIterator();
GroupingIterator._pool = instance._pool;
instance._pool = null;
instance.array = array;
instance.done = false;
return instance;
}
static _pool = null;
_pool = null;
/* state and value / payload */
array = null;
element = null;
index = 0;
count = 0;
/* IteratorResult interface */
value = this;
done = true;
/* Iterator interface */
next() {
const array = this.array;
let index = this.index += this.count;
if (!array || index >= array.length) {
return this.return();
}
const element = this.element = array[index];
while (++index < array.length) {
if (array[index] !== element) break;
}
this.count = index - this.index;
return this;
}
return() {
this.done = true;
// cleanup
this.element = this.array = null;
this.count = this.index = 0;
// return iterator to pool
this._pool = GroupingIterator._pool;
return GroupingIterator._pool = this;
}
/* Iterable interface */
[Symbol.iterator]() {
return this;
}
}
var arr = [5, 5, 5, 2, 2, 1, 1, 1, 1];
for (const item of GroupingIterator.from(arr)) {
console.log("element", item.element, "index", item.index, "count", item.count);
}

Callback that didn't need parameters - why?

So, I have been working on this 2-part problem and managed to solve it, however I have some questions on how the code actually works - specifically the nature of the callback function. Below are the 2 parts of the problem laid out, along with my solution to both. I was able to solve the first part rather easily, but the second was much more challenging for me.
// FIRST PART OF PROBLEM
var merge = function(array1, array2, callback){
//your code here.
}
var x = merge([1, 2, 3, 4], [5, 6, 7, 8], function(a, b){
return a + b;
});
//x should now equal [6, 8, 10, 12].
// MY SOLUTION:
var merge = function(array1, array2, callback){
var newArray = [];
for (var i = 0; i < array1.length; i++) {
newArray[i] = callback(array1[i], array2[i]);
}
return newArray;
}
var x = merge([1, 2, 3, 4], [5, 6, 7, 8], function(a, b){
return a + b;
}); // x equals [6, 8, 10, 12].
Now here is the second part of the problem that I was able to solve, but where I am having trouble is in specifically walking through the code step by step. My question is - why did I not need to give the callback parameter to the merge function any parameters? When I did attempt to provide parameter, x became NaN.
euclidian distance = sqrt((x2-x1)^2 + (y2-y1)^2))."
var euclid = function(coords1, coords2){
//Your code here.
//You should not use any loops and should
//instead use your original merge function.
}
var x = euclid([1.2, 3.67], [2.0, 4.4]);
//x should now equal approximately 1.08.
// My solution:
var euclid = function(coords1, coords2){
// // why does function() below require no parameters?
var merged = merge(coords1, coords2, function() {
return (coords1[0] - coords2[0]) * (coords1[0] - coords2[0]) +
(coords1[1] - coords2[1]) * (coords1[1] - coords2[1]);
});
return Math.sqrt(merged[0]);
};
var x = euclid([1.2, 3.67], [2.0, 4.4]); //x does equal approximately 1.08.
I'm a newbie to programming, so I realize this is probably a rather trivial question. But any help with walking me through how the callback is actually working in this solution would be much appreciated. Thanks!
why did I not need to give the callback parameter to the merge function any parameters?
Given:
var euclid = function(coords1, coords2){
// why does function() below require no parameters?
var merged = merge(coords1, coords2, function() {
return (coords1[0] - coords2[0]) * (coords1[0] - coords2[0]) +
(coords1[1] - coords2[1]) * (coords1[1] - coords2[1]);
});
return Math.sqrt(merged[0]);
};
The (callback) function passed to the merge function has a closure to the variables of its outer scope. Including coords1 and coords2 in the formal parameter list of Euclid makes them local variables, so they don't need to be passed to the callback.
If the function was created outside the scope of Euclid, then you'd need to pass them (or reference them some other way).
Incidentally, I prefer function declarations to assignment of expressions, e.g.
function euclid(coords1, coords2) {
// code here
}
as it makes it more obvious what the function's name is. Consider:
var foo = function fred() {
// foo or fred in here
};
// only foo out here
The second solution can be said to use merge only trivially. It's like that old question - how do you measure height of a building using an ammeter and a stopwatch? Throw the ammeter from the roof, measure time till pavement.
Your merge function will invoke its callback twice, the callback will calculate the full Euclid distance for the two-size arrays, and it will do it twice (so you'll get [1.08, 1.08] for the result of the merge; then you pick one of the results.
So your merge is a) unnecessary, b) inefficient, and c) doesn't work for any number of elements but 2.
The real solution involves noticing that Euclid distance is a sum; and each element of the sum only involves matching elements from two arrays: a[i] - b[i] squared. That should be your callback; and merge should give you an array like [0.64, 0.53].
The real problem is - how do you sum an array when you can't use loops, only your merge? If you are guaranteed that there will be only two dimensions, it is easy. If not, you will have to cheat.
var euclid = function(aa, bb) {
var squares = merge(aa, bb, function(a, b) {
return (a - b) * (a - b);
});
return Math.sqrt(squares.reduce(function(a, b) {
return a + b;
}));
};
Look, ma, no loops! (At least no overt ones.)
If you really want to only use merge, you will need to cheat harder.
var euclid = function(aa, bb) {
var sum = 0;
var squares = merge(aa, bb, function(a, b) {
sum += (a - b) * (a - b);
return null;
});
return Math.sqrt(sum);
};
In my opinion you're getting confused because your callback is not a callback and thus shouldn't be named this way. You rather wanna name it resolver, or calculator: the function one need to provide is not intended to be called back right after the process, but rather to be called while resolving, thus the naming concern. The pattern of providing a calculator function parameter is when you want to give the ability of customizing your function behavior to the caller.
So, the only reason they didn't tell you to make the euclid function accept a resolver parameter is... well, they didn't want you to create a behavior-customizable function. That simple =D

How does a function gets passed in to another function?

I have a forEach function defined to do "something" with all the items in an array:
function forEach(array, action) {
for (var i = 0; i < array.length; i++)
action(array[i]);
}
var numbers = [1, 2, 3, 4, 5], sum = 0;
So I could do:
forEach(numbers, console.log);
And it would print out all the numbers because 'console.log(array[i])' prints the number to the console.
I get that part.
Here's where I'm stuck: If I pass the function below into the place of the action parameter, instead of 'console.log' then at what point does the function know about every element?
forEach(numbers, function(number) {
sum += number;
});
console.log(sum);
// 15
How does it get evaluated? If I pass console.log into the last problem and it still has to be evaluated as 'console.log(array[i])' with the '(array[i])' code next to whatever parameter is being passed in, then doesn't that get applied to the entire function too since that function is the parameter? Such as below:
function(number) { sum += number; }(array[i])
at what point does the function know about every element
At no point (just like when you pass in console.log).
The forEach function calls it on this line:
action(array[i]);
At which point, it only knows about a single value from the array because that is all that is passed into it.
(It also knows about the sum variable because that is defined in a wider scope than the function).
How does it get evaluated?
It creates a new scope (with array, action and i variables) and assigns the function to the action variable - that's a function invocation.
Your
var sum = 0;
forEach([1, 2, 3, 4, 5], function(number) {
sum += number;
});
is just the same as
var sum = 0;
{ // let's assume block scope here
var array = [1, 2, 3, 4, 5],
action = function(number) {
sum += number;
},
i;
for (i = 0; i < array.length; i++)
action(array[i]);
}
If I pass console.log into the last problem and it still has to be evaluated, then doesn't that apply to the entire function too since that function is the parameter?
Yes, exactly. You are passing a function object - and whether get that by referencing the console.log variable or by creating it on the fly (with the function expression) doesn't matter to forEach. It only will get executed with action(…) - where the array[i] value is passed for the number parameter of your function.
In JavaScript, functions are first-class citizens. That means they can be treated as variables, just like strings, numbers, etc.
When you do:
forEach(numbers, function(number) {
sum += number;
});
You are passing forEach an anonymous function. Instead of the function being in a variable, it's created on-the-fly. Inside your forEach function, action will contain your anonymous function.
In for for loop, the action function is called for each element.
Heres the solution to your problems:
function forEach(array, action) {
for (var i = 0; i < array.length; i++){
if(typeof action == 'function'){
action(array[i]);
}else{
var slices = action.match(/(.+)\.([a-zA-Z0-9]+)/);
var object = eval(slices[1]);
var action = slices[2];
object[action](array[i]);
}
}
}
I've tested it with both scenarios and it works like magic

How do I add syntactic sugar in my Javascript library?

Right now the library can translate this operation
Select * from List where name = k% order by desc
to
List.filter(function(x) { return x.first_char() == 'k' }).sort().reverse());
Whats the best hack to remove the () so that the developer can write statements like:
List.filter(fn(x) { return x.first_char == 'k' }).sort.reverse;
Naive approach:
maxfn = function() {this[0]..}; Array.prototype.max = maxfn();
But with this approach I can't access 'this'.
I wanted to add a syntactic sugar for
new Array("1","2","3")
to something like :)(suggestions needed)
_("1","2" ,"3")
like we have in scheme where list -> '
I tried to clone the arguments but failed.
Thanks.
For lists you can use JSON notation:
["1", "2", "3"]
You can use JSON notation as suggested by RoBorg, if you control the list... However, there's no cross-browser way to treat a property as a method. Note: spidermonkey (firefox) does support using a getter (get method for a property).
Whats the best hack to remove the ()
Property getters/setters in JavaScript. Unfortunately it's a relatively new JavaScript feature that won't work on IE6/7 (as well as various other older browsers), so it's not really ready for prime-time yet (despite the intro of the linked article).
You could do this particular example by making a JavaScript object that wrapped a String and shadowed all String's methods, then add a static ‘first_char’ property set to the String's first character on initialisation. But it's really not worth it.
new Array("1","2","3")
to something like :)(suggestions needed)
_("1","2" ,"3")
Well that's simple enough:
function _(/* items */) {
var a= new Array();
for (var i= 0; i<arguments.length; i++)
a[i]= arguments[i];
return a;
}
There's no point in doing it nowadays, though, since the array literal syntax:
['1', '2', '3']
has been available since JavaScript 1.1-1.2 era and is available in every browser today. (It predates JSON by many, many years.)
I'll try to answer one by one:
1) Why would you want to remove parenthesis from a functon call?
2) If the "naive" approach is failing it's probably because you are calling the maxFn and assigning the results to Array.prototype.max. It should be like this:
maxfn = function() {this[0]..}; Array.prototype.max = maxfn;
3) RoBorg is correct, just use literal notation to construct arrays on the fly.
Edit:
Here's one way of implementing a max function on an array object. The optional evaluator argument is a function that takes two parameters, the current max value and current value in array. It should return the object that is "greater". Useful for non-primitives.
Array.prototype.max = function(evaluator) {
var max, i = 1; len = this.length;
if (len > 0) max = this[0];
for (; i < len; i++) {
if (evaluator) {
max = evaluator(max, this[i]);
}
else if(max < this[i]) {
max = this[i];
}
}
return max;
};
var a = [1, 3, 4, 5, 6];
alert(a.max());
var b = ["Arnold", "Billy", "Caesar"];
alert(b.max());
var c = ["Arnold", new Date(), 99, true];
alert(c.max());
var d = [1, 3, 4, 5, 6];
alert(d.max(function (max, val) { return max < val ? val : max }));

Categories

Resources