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});
Related
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
BRIEF: I have frequented SO for years, but this is my first post. I've heavily searched SO for this, so I'm sorry if I overlooked it and this is a duplicate.
function actionFunction(values) {
this.defaultValues = {
valueX : 2.5,
valueY : 5.5
};
this.valuesRanges = {
xRange : { min : 0, max : 10 },
yRange : { min : 5, max : 10 }
};
};
Obviously I can access these within the function itself using this.defaultValues.valueX, etc. What I'd like to know is how to access these outside of the function? I'm aware this is most likely a return or scope/hoisting problem and just do not know how to attack it.
Essentially, I need to get actionFunction.defaultValues.valueX. Also, I'd like to get the values inside of actionFunction.valuesRanges.xRange. I've tried these as arrays and more, but just can't figure out the correct, proper methodology. I have a multitude of functions structured like this that I need to pull these values from, so a modular way to do so without bringing in jQuery just for $.extend() and other basal functionality at the cost of overhead would be great.
EDIT I realized after posting this that I forgot to mention I was properly calling var example = new actionFunction();, but for some reason am/was having issues.
That said, what would be a cleaner and more logical, reliable way to store these values within the function as opposed to the this method so that they could still be grabbed by an exterior call for the values like previously mentioned?
It seems you're misunderstanding how exactly you should go about using functions that use this. Generally, we use these sorts of functions to construct objects based on them -- we call these functions "constructors". To use a constructor, you have to use the new keyword, passing any necessary arguments. For example, if we had this constructor:
function Test() { this.a = 1; }
We could create an instance (an object based on a constructor) by doing:
var foo = new Test();
console.log(foo.a); // 1
However, calling it as a normal function will not work as intended, as #Tibos pointed out -- that's probably not what you wanted. In most circumstances, it'll be defined in the global scope (that's where variables go by default). However, you shouldn't call a constructor like a normal function, as the value of this can change in some situations and the misuse of this in your function is likely to mislead others.
var foo = Test(); // no "new"
console.log(a); // 1
console.log(foo.a); // TypeError: Cannot read property 'a' of undefined
Let's go back to your original constructor. By using new with your constructor, instead of calling it as a normal function, we can do this:
function actionFunction(values) {
this.defaultValues = {
valueX : 2.5,
valueY : 5.5
};
this.valuesRanges = {
xRange : { min : 0, max : 10 },
yRange : { min : 5, max : 10 }
};
}
var example = new ActionFunction();
console.log(example.defaultValues.valueX); // 2.5
If you'd like, you can make sure that it always returns an instance by doing a check:
if (!(this instanceof actionFunction)) return new ActionFunction(arg1, arg2, ...);
It's usually simpler though to always remember to use new for constructors than to include this though -- most people don't bother including this check in their code.
this is the object your function was called on. this.defaultValues is a property of that object. If your function wasn't called on anything, then the global (window) object will be this, thus this.defaultValues will be window.defaultValues, which is also accessible as defaultValues
function actionFunction(values) {
this.defaultValues = {
valueX : 2.5,
valueY : 5.5
};
this.valuesRanges = {
xRange : { min : 0, max : 10 },
yRange : { min : 5, max : 10 }
};
};
actionFunction();
console.log(window.defaultValues); // Object {valueX: 2.5, valueY: 5.5}
console.log(defaultValues); // Object {valueX: 2.5, valueY: 5.5}
If you call the function on an object, then this will be that object and this.defaultValues will be obj.defaultValues.
var obj = {};
actionFunction.call(obj);
console.log(obj.defaultValues); // Object {valueX: 2.5, valueY: 5.5}
A similar thing happens when you use the function as a constructor, except that the object will be created implicitly and returned by the constructor:
var o = new actionFunction();
console.log(o.defaultValues); // Object {valueX: 2.5, valueY: 5.5}
Your "function" is here obviously a JS class definition.
To access it, you'll need to create an "instance" of this class through new;
Sample:
var af=new actionFunction();
var defaultX=af.defaultValues.valueX;
var vrangeymin=af.valuesRanges.yRange.min;
defaultValues and valuesRanges are set as properties on whatever this refers to when the function is invoked. Presumably you're treating that function as a constructor and invoking it with the new operator, which would mean this refers to a new instance:
var instance = new actionFunction();
instance.defaultValues; // This will be a reference to the object in question
If that's not what you're doing, you probably don't want to use this, as it will refer to the global object.
If that's the case, and you need to access that object outside of the function, you could simply declare it outside the function where it will be accessible to any descendant scopes.
If you haven't done that because you have several "action functions" that should have their own set of default values you could set them as static properties on the function objects:
actionFunction.defaultValues = { /*...*/ };
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
“this” inside object
I'm trying to make an object literal for a couple of default options for a jQuery plugin that I'm working on:
var defaults = {
r: 5,
top: this.r,
bottom: this.r,
topleft: this.top,
topright: this.top,
bottomleft: this.bottom,
bottomright: this.bottom
};
when I reference the defaults.top it is undefined
anything I can do to make this work? Or perhaps a different approach? I need it to be an object literal.
Added:
It is (default object), the way it's cascading down as you can see, was intended to be some what of a short hand technique. For example, if you would like to define all corners to be the same, you would use {r: 5} but if you want the top and bottom to be different {top: 5, bottom: 1} again, individually {topleft: 5, topright:2, bottomleft: 3, bottomright:19 } I apologize for not making this clear, but am very grateful for your answers.
ANSWERED: This is what I ended up doing
if(o.topleft == undefined || o.topright == undefined || o.bottomleft == undefined || o.bottomright == undefined){
if(o.top == undefined || o.bottom == undefined){
if(o.r == undefined){
o.topleft = 5;
o.topright = 5;
o.bottomleft = 5;
o.bottomright = 5;
}else{
o.topleft = o.r;
o.topright = o.r;
o.bottomleft = o.r;
o.bottomright = o.r;
}
}
else{
o.topleft = o.top;
o.topright = o.top;
o.bottomleft = o.bottom;
o.bottomright = o.bottom;
}
}
supper sloppy, but hey it worked! Thank you for all your help! I chose the answer because that explanation led me to do it this way!
"when I reference the defaults.top it is undefined"
That's because this doesn't refer to the object you're creating, it is the this from whatever scope that code is running in.
Object literal syntax does not allow you to set values by referencing other properties in the same object - the object doesn't exist yet. You can reference other variables or functions declared before the object literal. So if you need all the properties to be the same like in your example then you can do this:
var val = 5,
defaults = {
r: val,
top: val,
bottom: val,
topleft: val,
topright: val,
bottomleft: val,
bottomright: val
};
Or create some of the properties with an object literal and set the rest afterwards:
var defaults = {
r : 5
};
defaults.top = defaults.bottom = defaults.r;
defaults.topleft = defaults.topright = defaults.top;
// etc
Obviously the latter is more suited to setting some properties to one value and other properties to another value. (Though again in your example all properties are the same.)
Either way gives you the same object in the end (an object literal is just a shortcut way to create objects).
" I would like it to be simple enough to do something like this $(selector).myPlugin({r:10}); or $(selector).myPlugin({top:10, bottom: 5}); "
Well you can still call the plugin with an object literal as a parameter. But the defaults object (which I assume is defined inside the plugin) can be defined using other techniques.
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);
function myFunct(){
//blah blah blah
}
how to build a function with key/value pair parameters so when i call this, it will be called like this?
myFunt(prm1:'value1',prm2:'value2',prm3:'value3');
so, when i only need to call the 3rd param, i will do this:
myFunct(prm3:'value3');
Specify some defaults in your function and then call using only the params you need:
function myFunct(param) {
var prm1 = param.prm1 || "default1";
var prm2 = param.prm2 || "default2";
var prm3 = param.prm3 || "default3";
}
Call it using a param object, like this:
myFunct({prm3:'value3'});
prm1 and prm2 will get the default values, but prm3 will get what you passed.
You can specify any combination of values in your param object. Any you leave out will be populated with their default values.
If you're using jQuery you can make this a little prettier using $.extend:
function myFunct(param) {
var parameters = $.extend(true, /* deep copy */
{prm1: "default1", prm2: "default2", prm3: "default3"}, param);
};
The first object given to extend will serve as the default and the properties in your param object will be merged in when present.
function myFunt(jsonObj){
var param3 = jsonObj.prm3;
}
Call the function like this:
myFunt({prm3: 'value3'});
As far as I know, that is not supported by Javascript. You can however achieve a similar effect by just passing one argument, that is an object.
Call:
foo({ prm1: 'value1', prm2: 'value2', prm3: 'value3'})
Function definition:
function foo(args)
{
//use values accordingly
var prm1 = args.prm1;
}
Javascript doesn't directly support this syntax (named parameters, specifically), so you'll have to resort to some sort of workaround. There are two approaches that work in certain situations:
If you only need certain contiguous subsets of the parameters supplied, you can just declare them in order and then manually check whether the remaining parameters have been supplied. Javascript lets you call a function with less than the number of declared parameters, with the unpassed ones defaulting to undefined. Hence you could do something like this:
function myFunc(prm3 ,prm1, prm1) {
// Use defaults if not supplied
if (typeOf(prm1) == 'undefined') prm1 = 'value1';
if (typeOf(prm2) == 'undefined') prm2 = 'value2';
// Rest of function as normal
...
};
Alternatively, if you need more flexibility (i.e. either prm3 or prm2 could be supplied on their own, you'll need some way of associating a name with the value. Hence you'd have to pass all parameters in as an associate array, which is javascript is simply an object:
function myFunc(prms) {
// Unpack actual arguments - if not supplied, will be 'undefined'
var prm1 = prms.prm1;
var prm2 = prms.prm2;
var prm3 = prms.prm3;
// Rest of function as normal
...
};
// Call this function something like the following:
myFunc({prm1: 'Hello', prm3: 'World'});
Now both of these approaches have disavantages, but if you need to support optional arguments they're the only ways I'm aware of to do it.
Use arrays.
either:
var param = [null, 'value2', null]
or
var param = ['value1', 'value2', 'value3']
with function:
myFunct(param);
function myFunct(array){
//blah blah blah
}
This is most easily done by passing an object in as an argument:
myFunct({prm1: 'value', prm2: 'value', prm3: 'value'});
However, if you want any omitted key to have a default value, the most common methodology for this is to use $.extend (assuming you are using jQuery). Example:
function myFunct(obj) {
var defaults = {
prm1: 'value',
prm2: 'value',
prm3: 'value'
};
// Set any defaults
obj = $.extend(defaults, obj);
// Output the results to the console
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
console.log("obj[" + i + "] =", obj[i]);
}
}
}
Then you can call some sample code:
myFunct(); // will output all three params as being "value"
myFunct({prm3: 'test'}); // will output first two as being "value", third as being "test"
If you are not using jQuery, you can use the method described by lwburk above. However, lwburk's method gets rather lengthy if you have a lot of options possible.
The reason the extend method works is that it takes the first object (default in this case) and overwrites all values in the first object (default) with the ones specified in the second object (obj in this case). So $.extend({a: 1, b: 2}, {a: 2}) returns {a: 2, b: 2}; note that the a value was taken from the second object, but the b value from the first was untouched because it was not specified in the second.
Other libraries have similar extend methods (not an extensive list):
jQuery's extend (as linked above)
Prototype's extend
MooTools's merge
Or you could write your own, or use the code from any of the above.