So I've been doing this for as long as I can remember, but I'm curious if this is really what I should be doing. You write a function that takes a parameter, so you anticipate it to have a value, but if it doesn't, you have a good reason to default it, to say zero. What I currently do is write a helper function:
function foo() { return foo(0); };
function foo(bar) { ... };
I just ran across an instance where I did this and I looked at it oddly for a few seconds before understanding my logic behind it. I come from php where it's trivial:
function foo(bar=0) { ... }
Is there a javascript alternative that I'm not aware of?
You can't have overloaded functions in JavaScript. Instead, use object based initialization, or check for the values and assign a default if none supplied.
In your example, the second function foo(bar) will replace the first one.
Here's a function using object initialization.
function foo(config) {
extend(this, config);
}
where extend is a function that merges the config object with the current object. It is similar to the $.extend method in jQuery, or $extend method of MooTools.
Invoke the function and pass it named key value pairs
foo({ bar: 0 });
The other way to initialize is to look at the supplied values, and assign a default if the value is not given
function foo(bar) {
bar = bar || 0;
}
This works as long as bar is not a falsy value. So foo(false) or foo("") will still initialize bar to 0. For such cases, do an explicit check.
function foo(bar) {
bar = (typeof bar == 'undefined' ? 0 : bar);
}
In JavaScript, the argument will be undefined if the user didn't pass it in. You can use the || operator to set the value of the argument if it's undefined:
function foo(bar) {
bar = bar || 0;
...
}
The simplest way I know of is test for a value and then set it to a default value if no value is found. I have not come across a catch all one liner yet, this is the best i have got.
If expecting a string value use this. Default will trigger on these values: [ undefined, null, "" ]
function foo(str) {
str = !!str ? str : 'bar';
...
}
If expecting a number or Boolean value. This allows 0 and false as values. Default will trigger on [ undefined, null, {}, functions ]
Handy for making values arguments that only accept primitive values like number, boolean and string
function foo(val) {
val= !!val == val || val*1 ? val : 10;
...
}
If you're looking to test for objects such as {}, There is documentation on doing this but it isn't so simple.
Hopefully this answers a bit clearer for someone - I ended up using the ol' check for undefined if(typeof functionparameter !== 'undefined') as per:
$.fn.extend({
doThing: function(stringparameter = 'FooBar!', functionparameter){
console.log('Here is your string '+stringparameter);
// Run it if it's been passed through:
if(typeof functionparameter !== 'undefined') functionparameter();
});
Related
I've given some thoughts on declaring a variable called undefined and evaluating a truthy if-else expression with it. I found out that it is not possible in global scope. But in MDN I've found some interesting insight about the undefined datatype. I am directly quoting from MDN
undefined is a property of the global object; i.e., it is a variable
in global scope.
It doesn't say anything about local scope. That means i can create one in local scope. So, I move on to put this insight to test. I have created an object and assign a method to it
var person = {
method : function(){
var undefined = 2
if(undefined){
console.log("undefined works as a variable")
}
}
}
person.method()
And guess what! the if statement passes the test and the string inside the console.log() gets printed on the console.This might be a dangerous thing and of course a bad practice. Is there any way to prevent the declaration of a variable named after undefined keyword in javascript's local scope ? Thanks!
To work around accidental modification of undefined, you should not write this dangerous word in your code at all.
Since you only need read access to undefined, it is recommended to always use void 0 instead, which returns undefined.
var person = {
method: function() {
var undefined = 2
if(void 0) {
console.log("this should never be printed")
} else {
console.log("void 0 is always undefined, no matter what you do")
}
}
}
person.method()
How to work with void 0 and completely get rid of the word "undefined"?
// Turn
if(myVariable === undefined) { ... }
if(typeof myVariable === "undefined") { ... }
// into
if(myVariable === void 0) { ... }
// Turn
if((myVariable === undefined) || (myVariable === null)) { ... }
// into
if(myVariable == null) { ... }
// Turn
myObject.someKey = undefined
// into
myObject.someKey = void 0
Welcome to the wonderful world of JavaScript!
There is no way to prevent someone from doing this, but there is a way to ensure that undefined will mean undefined if you set up your functions as follows (not that you should really have to do this because it would be very bad practice for anyone to actually set up a variable named undefined). Essentially smaller scoped functions could hide a higher scoped undefined variable.
// This is just a way to get a variable called "undefined"
function wrapper(){
var undefined = 10;
console.log("wrapper says undefined is: " + undefined);
// This function declared a parameter called "undefined",
// but if the function gets called with no argument, then
// the value of this, more local, argument will truly be
// undefined. If arguments are needed, just add "undefined"
// to the end of the list.
function foo(undefined){
// Formal test to ensure that undefined is what we believe it to be:
if(typeof undefined === "undefined"){
console.log("foo says undefined is: " + undefined);
}
}
// When foo is called with no arguments passed in, the parameter
// "undefined" will take on a value of undefined within the scope
// of that function.
foo();
}
wrapper();
Now, that's a bit contrived as you're not going to set up all your functions with a "fake" argument, but you could test to see if undefined has been altered with:
function wrapper(){
var undefined = 10;
console.log(undefined);
function foo(){
if(typeof undefined === "undefined"){
// undefined has not been altered
} else {
// undefined has been altered, so reset it for this scope:
let undefined;
console.log(undefined);
}
}
foo();
}
wrapper();
In the end though, you could simply prevent this from affecting your functions by adding var undefined in your functions. Hoisting will make sure that this kicks in at the top of your function, no matter where you declare it.
I can't see any way to stop it, but yes, You can restrict it passing the yes inside If you can make the scope local using ES6.
You will find how scope if changed now and it's not the same thing.
var person = {
method : function(){
let undefined = 2
if(undefined){
console.log("undefined works as a variable")
}
}
}
You will have to forgive me, as I am sure this is addressed elsewhere, but I have no idea what to call this bit of syntax or the concept that this example illustrates. How does this get() function know that the parameter I am passing into it refers to an index of the adjacent array? I am not giving get() any indication of what object I am referring to, unless putting an object in parenthesis directly next to it has this effect. Is this correct? Is there a broader concept here that I am unaware of involving proximity and function calls?
function get(prop) {
return function(obj) {
return obj[prop]
}
}
get(1)([1,2,3]);
// output = 2
It might make more sense if you split get(1)([1,2,3]) out into 2 lines like this:
var get1Function = get(1);
get1Function([1,2,3])
// output = 2
Note: after execution of this line
var get1Function = get(1);
get1Function is now set to function(obj) { return obj[1] }
There's no magic here. You have a function that returns a function. When you call get(2), the returned function has 2 for the value of prop. Your code is essentially equivalent to this:
var fn = get(2);
// fn = function(obj) {
// return obj[2]
// }
fn([1,2,3]);
// => 3
You've just encountered one of the most confusing concepts for early JS programmers. It's called a "closure". MDN has a good article on this topic.
In general though, you can think of get returning a new method where the value of prop has been "saved" to the same value it was when get was first invoked.
The code example you provided would probably be best understood if we renamed some things and broke it down:
function createFunctionToReturnValueForProp(prop) {
return function(obj) {
return obj[prop]
}
}
var getPropertyFor1 = createFunctionToReturnValueForProp(1);
var array1 = [1,2,3];
var array2 = [4,5,6];
var obj = { "0": "foo", "1": "bar" };
getPropertyFor1(array1); // 2
getPropertyFor1(array2); // 5
getPropertyFor1(obj); // "bar"
Since I can determine the number of arguments a function expects to have by calling its Function.length property, is there any way for me to programmatically create the right number of parameters to insert into that function at runtime? Example:
var xyz = function(a,b) {};
var bcd = function(a,b,c,d,e,f) { }; // vararg example
var doc = document, func_length = xyz.length;
doc.xyz = (function() {
return function(a,b,c,d,e) { /* works for one but not the other */ } }).call(doc);
/* would prefer to `return function(a,b)` with only 2 parameters, if it is
used for function `xyz` (though returning 5 works fine in this case), and to
`return function(a,b,c,d,e,f)` with 6 if used for function `bcd` (which does
not work with only five params). */
// thinking about xyz.apply(null,arguments)...but which arguments..? :(
// Returning function(a,b,c,d,e) does not support functions with more than five
// parameters...which would mostly be varargs - hence my question
// I am also well aware that I can use an object or an array instead of
// using many params.
/* This is for incorporating a user-defined function for use in my code, while
* allowing for my function to do 'other stuff' afterward. (And allowing for
* varargs, of course).
* Because coding something like: doc.xyz = xyz is inflexible */
As you can see, I don't know how to do this, or if it is even possible. The search bar hasn't given me any other questions like this one, otherwise I would not have asked...
NOTE: This answer is a product of misunderstanding but
may help the future visitors of this site.
Another way:
Do you really need to add parameters? Writing the function this way would be enough:
function foo(){ //No arguments predefined
a = arguments[0] || ""; //first argument or (if not defined) empty string
b = arguments[1] || ""; //second argument etc.
c = arguments[2] || ""; //third argument etc.
alert(a+b+c);
}
foo("Hello ", "world!");
This alerts "Hello world".
The solution you want:
The simplest way:
This is what you've asked for but it's not as simple as the previous solution.
You can define a meta function with all the parameters and a handler function that changes over the time.
(function(){ //Wrapper
var foo_meta = function(a,b,c,d){ //Local meta of foo
alert(a+b+c+d); //Do the code
};
window.foo = function(a,b){ //Global foo
return foo_meta(a,b,"","");
};
window.redefine_foo = function(){ //Global foo-changer
//Rewrites foo
window.foo = function(a,b,c){
return foo_meta(a,b,c,"");
};
};
})(); //Wrapper
//Do some code
foo("a","b");
redefine_foo(); //Rewrite foo
foo("a","b","c");
//Note that foo_meta is not defined here
foo_meta == undefined; //It's safe in the wrapper :)
This will alert "ab" and then "abc". For the meaning of wrapper function, see the references.
Reference:
Arguments array: http://goo.gl/FaLM1H
Wrapping code: http://goo.gl/uQ5sd0
If you send two parameters 6 and 7 to a function doWork(a,b,c,d,e),a=7 and b=6 will be automatically set and rest of the parameters will be ignored.
Why not just pass one object into the function and use JQuery extend.
e.g.
var parm =
{ x: 1, y : 2};
f(p) {
p = $_.extend({...defaults here}, p);
...
}
This is an example for joining the arguments, regardless of the number of arguments, to show how function arguments can be turned into an array and then processed like any other array.
function foo(){ //No arguments predefined
// convert to real array
var args = Array.prototype.slice.call(arguments);
// or if Array generics are available
var args = Array.slice(arguments);
console.log(args.join(' '));
}
foo('Hello', 'world!');
foo('Hello', 'wonderful', 'world!');
Here is the fiddle
Ref: arguments MDN
Well, I think I've figured it out at last. I've realized that there may be no way to 'truly' add a parameter to a function the way that I was asking, but there is a way to emulate the same result:
var doc = document;
var xyz = function(a,b) {};
var bcd = function(a,b,c,d,e,f) {};
var obj = {};
// Now, here it is (mostly (sort of)):
obj.userFunc = function(args) {
var args_Array = [];
for (var i=0;i < arguments.length; i++ ) {
args_Array.push(arguments[i])
}
xyz.apply(null,args_Array); // or 'this'. or 'undefined'. Whatever you want.
// do other stuff
return this; // we know what to do to make 'this' scope explicit
} // end
var thisFunc = 'xyz'
doc[thisFunc] = obj.userFunc;
doc.xyz('h','i');
doc.xyz('h','i','j');
doc.xyz('h','i','j','k');
doc.xyz('h','i').xyz('j','l').xyz('j','q'); // etc.
The trick was to use the arguments object, which conveniently assimilated all the parameters into a readily available object, push each value into an array then apply the function.
In case you're wondering what the fuss was all about, I wanted to completely incorporate a user-defined function into another function, while still being able to do 'other stuff' afterward. My previous example worked to an extent, but did not have support for varargs. This does.
This approach is greatly more flexible than: doc[thisFunc] = userDefinedFunction
:) 4/26/2014
Let's say I have a variable like this:
var a = this.property || this.parent.anotherProperty;
It's possible to set the context (by context i mean 'this', maybe the 'scope' is a better word...) for a like when using .call() or .apply() for functions?
EDIT:
I have an helper function that given a value return:
if the value is a function -> value()
if it isn't a function -> value
This is the code:
function unwrapValue(value){
return typeof value === 'function' ? value() : value;
}
unwrapValue is inside a plain object (Utils) and it's called from outside this object:
Utils.unwrapValue(value);
Now, I have a property url in a function (that may be either a function or something else):
this.url = this.baseUrl || this.collection.baseUrl;
I don't know if this.url is a function or something else so I use unwrapValue to get the value of url:
var params = {};
params.url = Utils.unwrapValue(this.url);
And the problem is here, unwrapValue return this.url but setting 'this' to something else (i tought it was the Utils object but for some reason it's the window object) so params.url is window.baseUrl || window.collection.baseUrl which is not what i want.
If value is a function I solved this way:
function unwrapValue(value, context){
if(typeof value === 'function'){
return typeof context === 'undefined' ? value() : value.call(context);
}else{
return value;
}
}
so that if a second parameter context is passed to unwrapValue, value's this will be set to context.
with this question I was searching a way to use context aslo in the case value wasn't a function like:
this.url = this.baseUrl || this.collection.url;
And just to clarify a little more: this.baseUrl and this.collection.url are simple strings
There's a way to solve that?
You possibly want to pass an object literal as the thisArg into that function:
function fn() {
var a = this.a || this.parent.a;
console.log(a);
}
fn.call({
a: false,
parent: {
a: "foobar"
}
});
As you don't pass in further arguments, you could've used apply as well instead of call.
Assuming that a is a function (it's unclear from your question) then you can use Function.bind to set the context for all calls made to it:
var a = (this.a || this.parent.a).bind(this);
See MDN for more information and a shim for older browsers.
Does anyone have any example implementation of making individual object props readOnly/non-configurable? I mean primitive data types. Have tried using ES5 Object API, but hitting a brick wall.
I can't show code, because it's still at that "messy" phase, but basically I'm iterating through an outside object which, itself, holds numeruos objects. Those objects each hold various primitive data types. I have made the outer objects readOnly, non-config, etc, but can't figure out how to do likewise for individual props, the innermost props.
So, if outer.inner.prop === "Hello", I want to make that value readOnly.
Thanks!
UPDATE
I just figured this out, it was all in the for loop I was using to iterate over props. Now I've actually get data descriptors for the props, even the primitive ones. :) Thanks all!
You have to iterate through the inner object, since there is no way to deep-freeze an object using standard ES5 methods.
function deepFreeze(obj) {
Object.keys(obj).forEach(function (key) {
if (typeof obj[key] == 'object')
deepFreeze(obj[key]);
});
Object.freeze(obj);
}
Edit:
Also works for defineProperty if you don't want to freeze:
function deepWriteProtect(obj) {
Object.keys(obj).forEach(function (key) {
if (typeof obj[key] == 'object')
deepWriteProtect(obj[key]);
Object.defineProperty(obj, key, { writable: false });
});
}
I'm not 100% sure I understand your question correctly, but from what I gather you are asking for private variables. If so, that can be easily achieved using closures.
function myClass(){
var mySecretProperty = 10;
this.getMySecretProperty = function(){
return mySecretProperty;
}
this.changeMySecretProperty = function(s){
// whatever logic you need for a setter method
mySecretProperty = s;
}
}
var myObj = new MyClass();
myObj.changeMySecretProperty(120);
myObj.getMySecretProperty(); // will return 120
myObj.mySecretProperty // will return undefined
Would the following (ES5) example help? It creates an empty constructor, with a getter for property a (and no setter, so de facto a is read only):
var Obj = function(){};
Obj.prototype = {
get a() {return 5;}
}
var x = new Obj;
alert(x.a); //=> 5
x.a = 6; //=> TypeError: setting a property that has only a getter
Not using ES5 you can do
var Obj = function(){
var a = 5;
if (!Obj.prototype.getA) {
Obj.prototype.getA = {
toString: function() {
return a;
}
};
}
}
var y = new Obj;
alert(y.getA); //=> 5
But that is not 100% failsafe: Obj.prototype.getA can be overwritten.
Here is a jsfiddle showing how you can use ES5 getter/setter definitions to make a property of an object something that can only be fetched. The code looks like this:
var object = {
get x() {
return 17;
}, set x() {
alert("You cannot set x!");
}
};
Of course the getter could obtain the value of the property ("x") from anywhere, like a closure from a constructor or something. The point is that the setter simply does not change the value, so attempts to change it:
object.x = 100;
will not have any effect.