What's the point of callback implementation inside function declaration? - javascript

In the Eloquent Javascript book, in chapter 6 there's the following example:
class Matrix {
constructor(width, height, element = (x, y) => undefined) {
this.width = width;
this.height = height;
this.content = [];
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
this.content[y * width + x] = element(x, y);
}
}
}
//...
}
As you can see the 3rd parameter to the constructor is not just a callback parameter, but actually the implementation of the callback.
At first I thought, maybe the body of the implemented callback function is disregarded but at least the future callbacks used in the constructor will be checked to have the same signature. However, I found that the signatures don't matter as the code below will work:
const test = new Matrix(2, 4, () => console.log('hello'));
So what's the point of implementing callback, it being a parameter of a function? Is just for a reader to infer how many parameters will be passed to the callback?

If you do not specify a third parameter, the default value of element would be (x, y) => undefined.
Please refer to this MDN link. It will give some insight. Hope this helps.

What the example is doing with element is to set a default value. In this case the default value does nothing.
Note that you can also use ()=>{} as default of element, it will work in JavaScript since the language doesn't validate the number of arguments when you call a function (but it may give you a type checking error in TypeScript).
This is a common pattern: instead of using undefined or null, you put a default parameter that does nothing, so in the code you don't need to check if element is defined before calling the function. See: https://en.wikipedia.org/wiki/Null_object_pattern
Some libraries like lodash also include constants like noop defined as en empty function, so you can write the code as:
const noop = ()=>{}
class Matrix {
constructor(width, height, element = noop) {
//...
}
}
Additional information:
The Matrix constructor seems to be initializing a single dimension Array to store the matrix. You can replace that nested for loop with Array.from. Something like:
this.contents = Array.from(
{length: height * width},
n => element(n % width, Math.floor(n/height))
);
I didn't check the math so the example may have index errors. See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from

The way I understand it, it's simply an optional initializer. If you call it with something like () = > 0, it will initialize your matrix with 0 instead of undefined. (x,y) => x === y ? 1 : 0 would produce an identity matrix. etc ....
(update after reading the chapter)
This is borne out by the sentence following the exemple in the book:
The constructor function takes a width, a height, and an optional element function that will be used to fill in the initial values.

This class has 3 parameters applying to "Constuctor".
The third one is callback function named "element" is optional, and has default value of "(x,y)=>undefined". So if you did not pass third argument when building a new instance of "Matrix" class it will be as default.
if you pass specific function here (for example)
let myMatrix = new Matrix(100,100,(x,y) => x * y);
at this stage
this.content[y * width + x] = element(x, y);
it will returns corresponding values to respective array slots of "this.content" property of your new "Matrix" instance.
So your Matrix will have such "content" property (for example):
myMatrix.content[0] = 0;
myMatrix.content[1] = 0;
...
myMatrix.content[101] = 1;
myMatrix.content[102] = 2;
// and so on
Otherwise if you don't pass any function when creating a new instance, all generated array slots of "this.content" property will be assigned with undefined values because of default property value of
(x, y) => undefined

Related

declaring a variable twice in IIFE

I came through this fun quiz on the internet.
console.log((function(x, f = (() => x)){
var x;
var y = x;
x = 2;
return [x, y, f()]
})(1))
and the choices were:
[2,1,1]
[2, undefined, 1]
[2, 1, 2]
[2, undefined, 2]
I picked solution 2 TBH, basing that on that x has been redefined, y was declared and defined with no value, and that f has a different scope hence getting the global x memory spot than function x memory spot.
However, I tried it in jsbin.com
and I found it was solution 1, while I was not sure why that happened I messed with the function body and I removed var x from the function body, I found that the response changed to #3 which makes sense as x value changed and hence it showed x and f as 2 and y as 1 which was declared globally.
but still I can't get why it shows 1 instead of undefined.
but still I can't get why it shows 1 instead of undefined.
It's not just you. This is a deep, dark part of the specification. :-)
The key here is that there are two xs. Yes, really. There's the parameter x, and there's the variable x.
A parameter list containing expressions (like f's default value) has its own scope separate from the function body's scope. But prior to parameter lists possibly having expressions, having var x within a function with an x parameter had no effect (x was still the parameter, with the parameter's value). So to preserve that, when there's a parameter list with expressions in it, a separate variable is created and the value of the parameter is copied to the variable at the beginning of the function body. Which is the reason for this seemingly-odd (no, not just seemingly) odd behavior. (If you're the kind who likes to dive into the spec, this copying is Step 28 of FunctionDeclarationInstantiation.)
Since f's default value, () => x, is created within the parameter list scope, it refers to the parameter x, not the var.
So the first solution, [2, 1, 1] is correct, because:
2 was assigned to the var x in the function body. So at the end of the function, the var x is 2.
1 was assigned to y from the var x before x got the value 2, so at the end of the function, y is 1.
The parameter x's value has never changed, so f() results in 1 at the end of the function
It's as though the code were written like this instead (I've removed unnecessary parens and added missing semicolons):
console.log(function(param_x, f = () => param_x) {
var var_x = param_x;
var y = var_x;
var_x = 2;
return [var_x, y, f()];
}(1));
...I removed var x from the function body, I found that the response changed to #3...
#3 is [2, 1, 2]. That's correct, because when you remove the var x from the function, there's only one x, the parameter (inherited by the function body from the parmeter list). So assigning 2 to x changes the parameter's value, which f returns.
Taking the earier example with param_x and var_x, here's what it looks like if you remove the var x; from it:
console.log(function(param_x, f = () => param_x) {
var y = param_x;
param_x = 2;
return [param_x, y, f()];
}(1));
Here's an annotated description of the original code (with the extraneous parentheses removed and missing semicolons added):
// /---- the parameter "x"
// v vvvvvvvvvvv--- the parameter "f" with a default value
console.log(function(x, f = () => x) {
var x; // <=== the *variable* x, which gets its initial value from the
// parameter x
var y = x; // <=== sets y to 1 (x's current value)
x = 2; // <=== changes the *variable* x's value to 2
// +---------- 2, because this is the *variable* x
// | +------- 1, because this is the variable y
// | | +--- 1, because f is () => x, but that x is the *parameter* x,
// | | | whose value is still 1
// v v vvv
return [x, y, f()];
}(1));
Final note regarding your title:
declaring a variable twice in IIFE
The variable is only declared once. The other thing is a parameter, not a variable. The distinction is rarely important...this being one of those rare times. :-)
The tricky part of that code is that the => function is created as part of a default parameter value expression. In parameter default value expressions, the scope includes the parameters declared to the left, which in this case includes the parameter x. Thus for that reason the x in the => function is in fact the first parameter.
The function is called with just one parameter, 1, so when the => function is called that's what it returns, giving [2, 1, 1].
The var x declaration, as Mr Crowder points out, has the (somewhat weird, at least to me) effect of making a new x in the function scope, into which is copied the value of the parameter x. Without it, there's only the one (the parameter).

Short hand to change variable with function

I was wondering if there's a way of changing some variable value with the return of some function. A short-hand-way of doing it.
If I want to add some value to a variable and changing it, we do like that:
let numb = 5;
numb *= 2; // Returns 10
But lets say I have a function that return the double of its argument like this:
function double(a) {
return a * 2;
}
let numb = 5;
numb = double(numb); // Short hand of doing this line <----
You need to understand how reference and value parameters work. When you pass in a number or a string to a function that is a value parameter and changing the value of the parameter withing the function has no effect on the variable that was passed in. If the parameter is a reference to an object then changes to properties on that object will then change the variable passed in.
let x = 5;
someFunc(x);
There is no way for someFunc to change x because the value 5 of x was passed into the function, not a reference to x;
let x = { prop: 5 };
someFunc(x);
Now if the body of someFunc changes x.prop then it will also change it to the variable x that was passed in because a reference to an object instance was passed in.
It is the same as assigning variables.
let x = 5;
let y = x;
Now x and y are both 5 but changing y = 6 does not effect x.
let x = { prop: 5 };
let y = x;
Now y is a reference to the same object so y.prop = 6 will change x as well.
All that aside good programming principles and modern functional programming concepts dictate that modifying parameters passed into functions is not good practice.
You could use an arrow key function. Saves a line or two.
const double = a => a * 2;
let numb = 5;
numb = double(numb);
Removing the short hand, the double function would look like
const double = (a) => {
return a * 2
}
Arrow key functions are pretty much the same as a normal function, however they give you more control over the 'this' keyword.

What is the role of the this variable when it comes to function currying using the .bind()?

I came across to the following JS code (ES5)
and I don't really I understand what is the meaning of the this variable.
function multiply(a,b){
return a * b;
}
var multipleByThree = multiply.bind(this,3);
multipleByThree(10) // outputs 30
I do understand that the bind copies the multiply function and that 'a' parameter of it, will have the value 3. But what is the purpose of the this variable?
Can you help me out please?
The this variable that you are providing to .bind() is the context. In your case, this refers to the global object space.
Here's an example of how this works:
var message = 'within global context';
function multiply(a,b){
console.log(this.message);
return a * b;
}
var someOtherContext = {
message: 'within some other context'
};
var multipleByThree = multiply.bind(this,3);
var multipleByThreeOtherContext = multiply.bind(someOtherContext, 3);
console.log(multipleByThree(10))
console.log(multipleByThreeOtherContext(10))
By changing the context that multiply executed within, we can change what variables it references.
The first argument to bind must be the thisArg:
fun.bind(thisArg[, arg1[, arg2[, ...]]])
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
That is, whatever the keyword this inside multiply will refer to. Since multiply doesn't use this at all, it's irrelevant what it refers to. You must still pass something as the first argument to bind, so likely the developer simply chose this (whatever that refers to in this code is unknown to us), but they could just as well have used false, null or anything else.
In javascript this is some kind of "reserved keyword" which refers to current object of the scope.
If this used outside of any object - it refers to window object.
Inside eventhandlers this refers to the DOM object which raised an event.
bind function provide possibility to define which object this will refer inside bound function.
For example if you using this inside function
const calculate = function (price, amount) {
return (price * amount) - this.discount;
};
You can bound a function with predefined this
const calculateWithDiscount = calculate.bind({ discount: 100 });
const total = calculateWithDiscount(1000, 2); // return 1900
When you bound function which doesn't use this object, you can easily pass null there, which clearly "tell" other developers your intents about using this in the function.
const add = function (a, b) {
return a + b;
};
const add5 = add.bind(null, 5);
const result = add5(19); // return 24
bind Method (Function) (JavaScript)
For what it's worth, you can do currying without relying upon Function.prototype.bind
Once you stop relying upon this in JavaScript, your programs can start looking like beautiful expressions
const curry = f => x => y =>
f (x,y)
const mult = (x,y) =>
x * y
const multByThree =
curry (mult) (3)
console.log (multByThree (10)) // 30
For a more generic curry implementation that works on functions of varying arity
const curry = (f, n = f.length, xs = []) =>
n === 0
? f (...xs)
: x => curry (f, n - 1, xs.concat ([x]))
If you want to bellyache about the exposed private API, hide it away with a loop – either way, this is not required to write functional programs in JavaScript
const loop = f =>
{
const recur = (...values) =>
f (recur, ...values)
return f (recur)
}
const curry = f =>
loop ((recur, n = f.length, xs = []) =>
n === 0
? f (...xs)
: x => recur (n - 1, xs.concat ([x])))
it fixes 3 as the first argument, the arguments of the new function will be preceded by 3
function multiply(a,b){
console.log(a, b);
console.log(arguments)
return a * b;
}
var multipleByThree = multiply.bind(console.log(this),3);
console.log(multipleByThree(10)) // outputs 30
console.log(multipleByThree(10, 15)) // outputs 30
passing this would provide a copy of this(i.e the global object) with the preceded arguments list
For more information check out the MDN docs
In the context of Currying the this object in the code presented has no purpose other than as a placeholder. You could replace this with the string "cats" if you wanted and still get the same result. It is simply there to occupy the first argument position and I think it is very misleading to use it in the context of
either currying or partial application when using bind. It is better to replace it with the null keyword.
In the case of this example it will pass in the global object and the rest of the code will simply ignore that value since the keyword 'this' is not present within the multiply function itself.
MDN shows a use case, visit https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
and scroll to the section headed Partially applied functions.
ES6 (aka es2015) has improved on the way this code is written by using arrow functions and the code can now be reduced to the following
const multiply = a => b => a * b
const multiplyByThree = multiply(3)
const result = multiplyByThree(10)
console.log(result)
// => 30

Ways to create smart parameter passing in javascript?

I'm a bit new to javascript, I'd like my function to take in parameters and associate
them by name,
myFunction(width = 50, height = 20);
myFunction(height = 20, width = 20)
myFunction(width = 50); // height will get some default value
so then I can have:
function myFunction()
{
var width; // this will somehow get the variable that was passed in or set default value
var height; // this will somehow get the variable that was passed in or set default value
}
Is there a way to possibly do this in javascript?
Also, I've seen syntax of the form
ball: {
x: '124',
y: '22',
}
but I have no idea what it's called.
Maybe I could use this syntax somehow, and create some kind of object that I then pass into my function.
But what I'm looking for is:
Pass parameters into a function by name, not by order.
Make all parameters passed into the function optional; if they are not passed in assign a default value.
What's the best/cleanest way to do this?
Passing an object as single parameter is the way to go.
Example:
function func(options) {
var width = options.width || 0;
var height = options.height || 0;
//...
}
func({height: 100}); // width will be 0 as options.width is undefined
The || shorthand (boolean OR) will set each value to 0 if it is not provided. That is, it will assign 0 if options.width evaluates to false which is the case when it is not defined (i.e. options.width is undefined).
Whether this is sufficient depends on what kind of values are allowed. E.g. if false is a valid value, you have to explicitly test for undefined.
Another and arguably more handy way to define default values would be to use an extend function:
function extend(a, b) {
for(var prop in b) {
if(b.hasOwnProperty(prop) && !a.hasOwnProperty(prop)) {
a[prop] = b[prop];
}
}
}
This copies all properties of object b to object a if they are not present.
It lets you set default values this way
function func(options) {
extend(options, {width: 0, height: 0});
// access the values with options.height and options.width
// options.height is not overwritten
}
regardless of the value.
This is the way jQuery uses. It provides an $.extend [docs] function which is commonly used when developing plugins to provide default settings. A good example of a function which accepts named and optional parameters is $.ajax [docs].
Yes. You would create an object literal and pass it as a parameter to the function:
var param = {
x: 10,
y: 20
}
pass it to your function:
foo(param);
and in your function code refer to is like so (for example):
function foo(param)
{
console.log(param.x);
console.log(param.y);
}
On your second question - passing parameters to the functions is optional in JavaScript - the parameters that didn't get passed would be undefined - that is not have value, but when accessed return undefined. Same goes for undefined properties of your param object - had you not defined x - param.x would return undefined upon access.
You could pass a JS object to your function:
function myFunction(data) {
var width = data.width;
var height = data.height;
}
myFunction({'width':50, 'height':20});

dynamic function arguments in array

A bit hard to find a proper title...
I have an object which basically is a wrapper around an array of Cartesian coordinates (x, y values). I'm now defining a few transform methods on that array (move, rotate, skew, mirror). Basically all these methods need an iterator of the array, so I wrote a function iterate:
myList.prototype.iterate = function() {
var fn = arguments[0]; // first argument is the actual transform function.
..
Optionally a second argument may be passed in, which must be an instance of myList. If this argument is passed in, the function operates on a clone of the argument, otherwise it must operate on itself:
if (arguments.length === 2 and arguments[2].type === this.type) {
target = $.extend({}, arguments[2]); // deep copy.
} else {
target = this;
}
So far so good, now I'm defining my transformation functions (rotate)
myList.prototype.rotate=function() {
var rotatePoint = function (angle, pt) {
return {x : (pt.x * Math.cos(angle) - pt.y* Math.sin(angle))
, y : (pt.x * Math.sin(angle) + pt.y* Math.cos(angle)) };
}
if (arguments.length() === 1) { //Alternative for this if statement.
return this.iterate(rotatePoint.curry(arguments[0]));
} else {
return this.iterate(rotatePoint.curry(arguments[0]),arguments[1]);
}
}
curry is a non standard javascript function, and is described here. I'm not so glad with the if statement. I think it can be done more elegant with apply or call. But I haven't been able to figure this out. Problem is also that arguments[2] in iterate will be an empty array, screwing my if statement when comparing types.
How can rewrite the if statement in some nice clean javascript code, so that there is no second argument at all when it is not in passed in iterate;
does something like this work?
var args = $.makeArray(arguments),
iterator = rotatePoint.curry(args.shift());
args.unshift(iterator);
return this.iterate.apply(YOURTHIS, args);

Categories