Let's say I have the following function:
function get_scaled_coordinates(x, y, scale) {
return [x*scale, y*scale];
}
Is it possible if I have a single variable with [x,y] to pass to the function. Perhaps something similar to this, conceptually speaking:
let point = [1,1];
get_scaled_coordinates(**point, scale);
// instead of having to do get_scaled_coordinates(point[0], point[1], scale)
You could take an array as target for destructuring.
function get_scaled_coordinates([x, y], scale) {
return [x * scale, y * scale];
}
If you like to use higher dimensions, you could map the array with new values.
function get_scaled_coordinates(coordinates, scale) {
return coordinates.map(v => v * scale);
}
Perhaps something similar to this, conceptually speaking:
get_scaled_coordinates(**point, scale);
You seem to be looking for spread syntax in the function call:
get_scaled_coordinates(...point, scale);
No need to change the function, making it accept an array.
Related
This question already has answers here:
ES6 destructuring function parameter - naming root object
(5 answers)
Closed 11 months ago.
Is it possible to do something like the following in js?
function Something( Point{PointX, PointY} ) {
console.log('Point', Point);
console.log('PointX,PointY', PointX, PointY);
}
Something([1,2]);
If so, what would be the proper way to do that?
function Something(Point) {
const [PointX, PointY] = Point
console.log('Point', Point)
console.log('PointX,PointY', PointX, PointY)
}
Is this what you need?
function Something([PointX, PointY]) {
console.log('PointX,PointY', PointX, PointY);
}
You can destructure both arrays (function([x, y]) and objects (function({ x, y })).
Sure, but make sure the keys match up to do the destructuring assignment for an object, such as:
function Something({x,y}) {
console.log('PointX, PointY', x, y);
}
Something({x: 1, y: 2});
In terms on naming and also assigning it to the outer object, perhaps you can do something like this instead:
function Something(Point) {
const {x,y} = Point;
console.log('Point, PointX, PointY', Point, x, y);
}
Something({x: 1, y: 2});
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
I created a function that takes event object and do some stuff with .clientX and .clientY properties. Is there any performance issue based on that I am passing whole object, not just properties I will use? Is this object passed by reference? Should I pass whole object or just the properties I will use in the function?
Let's consider following examples:
1)
function doSomethingWithMousePos(event) {
return {
// Do some stuff with data
x: event.clientX * Math.floor(Math.random() * 10),
y: event.clientY * Math.floor(Math.random() * 5)
}
}
doSomethingWithMousePos(event);
or
2)
function doSomethingWithMousePos(x, y) {
return {
// Do some stuff with data
x: x * Math.floor(Math.random() * 10),
y: y * Math.floor(Math.random() * 5)
}
}
doSomethingWithMousePos(event.clientX, event.clientY);
Which approach is better? Or it does not matter at all?
JavaScript objects are passed by reference, so it's really six of one, half a dozen of the other. You'll have to access those properties at one point or another, so whether it's in the line that calls the method or inside the method, it doesn't really matter. Arguably the best approach would be whatever you and your team find more readable.
I have so far:
function func(f,x) {
alert(f(x));
}
func(function(x) {return x*x;},2);
This works, but i am thinking that passing function(x) {return x*x;}, is excessive and I could just pass x*x, as the idea is that I can supply (pretty much) any function.
I have tried:
function func(f,y) {
g=function() {return f;};
alert(g(y));
}
func(x*x,2);
amongst others, but I can't get it to work. Perhaps if I passed 'x*x' as a string..?
You're correct that the syntax is excessive, but for ES5 and before, that's just how it is.
However, in ES6 you can use the new "arrow function" lambda syntax:
func(x => x * x, 2);
See http://www.es6fiddle.net/i4o5uj2l/
FWIW, the above func isn't great since it only supports unary functions, i.e. those taking a single parameter. You could expand func to use ES6 "spread arguments":
function func(f, ...args) {
console.log(f.apply(this, args));
}
func((x, y) => x * y, 3, 7);
> 21
Well I have a way to do that using eval here http://jsfiddle.net/q5ayoszy/
function func(f,y) {
g=function()
{ x=y;
return eval(f);
};
alert(g(y));
}
func('x*x',2);
Note : I pass the expression as a string and then use it inside the function.
You just need to assign the value of y to the variable x inside the function so the eval evaluates correctly
The only way to do that with a string is by using the infamous eval: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
var x = 2;
var y = eval("x * x"); //y = 4
But using eval is almost always a very bad idea.
You could use currying to break down the process into smaller functions:
function multiply(x) {
return function() {
return x*x;
}
}
var bytwo = multiply(2);
bytwo(); // 4
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);