JavaScript methods for setting default function variable values - javascript

I have a question regarding setting default values for variables inside functions. I know there are several posts regarding how to do this however I'm interested in this alternative method and whether anyone can explain to me the pro's/con's of using it particularly as the JSBIN compiler is flagging an error...
Line 2: void 0 === data && (data = 20); --- Expected an assignment or function call and instead saw an expression.
New/Alternative Method
var a = function(data) {
void 0 === data && ( data = 20 );
return data;
};
Current Method using typeof operator
var b = function(data) {
data = typeof data === "undefined" ? data = 30 : data;
return data;
};

I have never seen it written that way, I doubt it will take off. Developers used to use void 0 in place of undefined because undefined was once a writable attribute of the window object. With newer browsers, this has not been the case for a long while now. The only reason you'd write it like that now is to stroke your own ego and feel superior to others who may not know the meaning behind void 0.

Since void 0 is undefined. Than this:
void 0 === data && ( data = 20 );
Is a very goofy way of writing this code:
if (data === undefined)
data = 20
So executed first comparison void 0 === data and if it is true it will execute the right side of the condition which assigns 20 to the data.
The code bellow basically assigns data variable a value 30 when data is undefined. Though again this code is pretty goofy, the reason being is that you don't need to set data = 30 in the true branch, you can just return 30... this code works because when you assign a varaible a vlue the result of the assignment is the value itself so this is what happens here, operation data = 30 returns 30, but you could just write data = typeof data === "undefined" ? 30 : data;
var b = function(data) {
data = typeof data === "undefined" ? data = 30 : data;
return data;
};
The best way I think would be the following:
var b = function (data) {
data = data || 30;
}

All of the methods have various pros and cons --
Here is the method I like:
function hasOptionalParams(p1, p2 p3) {
if (arguments.length === 0) {
p1 = "default";
}
if (arguments.length === 1) {
p2 = "default";
}
if (arguments.length === 2) {
p3 = "default";
}
}
EDIT: More Details
I like this method for a number of reasons.
It is the absolute more clear for someone new to JavaScript. I work on a team and I never know who will be working on the code next and what their skill level is.
This truly does catch arguments that are not passed in, as opposed to someone who purposefully passes a null, undefined or 0
I can set multiple behaviors. I can set p2 and p3 to be different if only p1 is passed.

Related

SendBird create GroupChannel with file as cover

I'm trying to create a group Channel with a cover photo,
this.sendBirdInstance.GroupChannel.createChannelWithUserIds(userIds, true, this.groupName, this.groupPhotoFile, '', function (createdChannel, error) {
...
}
According to the documentation I can add a url or a file
coverUrl : the file or URL of the cover image, which you can fetch to
render into the UI.
But when adding a file, I'm always getting : "SendBirdException", code: 800110, message: "Invalid arguments."
Is there a way to create a group with a file instead of a url (since I want the user to upload the file) ?
Thanks,
As you have already experienced (I saw that you have created an issue in GitHub several days ago) the support of SendBird is kinda unreliable.
The fact that they offer just a minified version of their JavaScript SDK (which personally I find very poor) is helping either.
Anyway, I could isolate the createChannelWithUserIds function:
! function (e, n) {
// ...
}(this, function () {
// ...
var h = function (e) {
for (var n in e) if (e.hasOwnProperty(n)) return !1;
return Array.isArray(e) ? JSON.stringify(e) === JSON.stringify([]) : JSON.stringify(e) === JSON.stringify({})
},
// ...
A = function () { // it returns SendBird function
// ...
var w = function (e) { // w is this.GroupChannel
// ...
w.createChannelWithUserIds = function () {
// ...
// here comes the param validation (I've added spaces for a better lecture):
if (!Array.isArray(e) || "boolean" != typeof n || "string" != typeof t && null !== t && void 0 !== t || "string" != typeof r && h(r) && null !== r && void 0 !== r || "string" != typeof a && null !== a && void 0 !== a || "string" != typeof i && null !== i && void 0 !== i) return void U(null, new p("Invalid arguments.", J.INVALID_PARAMETER), s);
// It will return "Invalid arguments." if any of the conditions evaluates to true
// ...
}
}
}
return function () {
// ...
}().SendBird
});
You are using the function like this:
createChannelWithUserIds(o, n, t, r, a, s);
So the fourth parameter (r) is coverURL: the file with the cover picture (this.groupPhotoFile);
Its validation is basically saying that:
"string" != typeof r // if `r` is not a string (a URL)
&& h(r) // and the returned value of function h(r) is true
&& null !== r // and it is not null
&& void 0 !== r // and it is not undefined
that parameter is invalid.
Your file is not a string, not null and not undefined, so everything boils down to the h() function:
var h = function (e) {
for (var n in e) if (e.hasOwnProperty(n)) return !1;
return Array.isArray(e) ? JSON.stringify(e) === JSON.stringify([]) : JSON.stringify(e) === JSON.stringify({})
}
The function above check in first place if the object has any property what is a member of the object itself (i.e. not properties belonging to the prototype chain).
Then, if it doesn't have any own property, it checks if the stringify object/array is equal to an empty object/array.
I can't say what is the intention of the developers when validating files though this function, but a standard FILE object:
has properties in its prototype chain, but not directly assigned to the instance, so the first condition is true.
when stringify returns a empty object in all major browsers nowadays (it was not always like so), so the second condition is also true.
As we saw before, we need h() to return false: the validation fails if it returns true.
To fix this behavior you could change the h() function to something like:
var h = function( e ){
return !(e instanceof File);
// or return e.constructor != File;
// or return Object.getPrototypeOf( e ) != File.prototype );
// or return e.__proto__ != File.prototype )
// or return e.constructor.prototype != File.prototype )
}
but I won't mess with it. It could be used in future versions with a different purpose.
So your best bet is to change the createChannelWithUserIds() function to:
remove the call to the h() function from the validation.
replace it with a call to your own file validation
To do that, you could override the function in a SendBird instance:
var sb = new SendBird( { appId: ... } );
sb.GroupChannel.createChannelWithUserIds = function(){ ... };
But it is not guarantee to work and could break in future releases, so I would just edit the SendBird.min.js file.
In other words, replace:
if(!Array.isArray(e)||"boolean"!=typeof n||"string"!=typeof t&&null!==t&&void 0!==t||"string"!=typeof r&&h(r)&&null!==r&&void 0!==r||"string"!=typeof a&&null!==a&&void 0!==a||"string"!=typeof i&&null!==i&&void 0!==i)return void U(null,new p("Invalid arguments.",J.INVALID_PARAMETER),s);
with:
if(!Array.isArray(e)||"boolean"!=typeof n||"string"!=typeof t&&null!==t&&void 0!==t||"string"!=typeof a&&null!==a&&void 0!==a||"string"!=typeof i&&null!==i&&void 0!==i)return void U(null,new p("Invalid arguments.",J.INVALID_PARAMETER),s);
In the current version (v3.0.41) you will find two coincidences of the code above: one for createChannel and other for createChannelWithUserIds, you can replace both.
Of course, editing the .js file is annoying because you will need to take care to replace the code everytime you upgrade SendGrid.
You could create an automatic task inside your CI pipeline to do it for you, thought.
Hopefully, the SendGrid developers will acknowledge your issue and fix it in a future release.

Typescript Function Weird Void || && Behaviour

Why is returnObjectcausing an compilation TypeError returnObject2 isn't?
Normally, void || something should return something while void && something should return void.
But in Typescript, it's the opposite that occurs.
var returnVoid = function(){};
var returnObject = function(){ //Typescript compilation TypeError.
//No best common type exists among return expressions.
if(Math.random() < 0.5)
return new Error();
return returnVoid() || null; //always return null
}
var returnObject2 = function(){ //works
if(Math.random() < 0.5)
return new Error();
return returnVoid() && null; //always return undefined
}
Note: TypeError occurs during the compilation, not in the runtime.
EDIT: I did another test. Shouldn't returnNum2 be () => number too considering (undefined || something) === something? Note: Same behaviour for void 0.
var returnNum = function(){ //() => number
return undefined || 0;
}
var returnVoid = function(){};
var returnNum2 = function(){ //() => void | number
return returnVoid() || 0;
}
It's been pointed out in comments, but I think in general you just need to understand that function(){} will return undefined, which has specified behavior for logical operators.
For undefined && somevalue, undefined will always be returned. For undefined || somevalue, somevalue will be evaluated and returned.
Here's a good reference for more information: http://www.javascriptkit.com/jsref/comparison_operators.shtml
EDIT: The question isn't about what is returned for the logical operation, but why typescript gives error TS2354: No best common type exists among return expressions. on compilation.
This does seem like an error, but may make sense in the context. If you replace the logical operators with just a call to returnVoid() only, you'll get the same error in both functions. Static typing allows the && operator to short-circuit entirely for typing, since something && null will never evaluate to a type, but something || null could depending on what the something is.
Related to this, in typescript you cannot explicitly specify null or undefined as a return type for a function.
While I understand why this may be the case, I agree it is a little odd. It might be worth checking with the folks who make Typescript and filing a bug.
TypeScript doesn't special case expressions of the form undefined || T or void || T to be T because a) you shouldn't write that code (use the comma operator!) and b) it's not safe to write this code because return value contravariance means you're not guaranteed to have a falsy value just because you have a void-returning function reference.
Consider if you wrote code like this:
type callback = (arg: any) => void;
function doSomething(x: callback) {
return x(10) || 'Hello, world!';
}
var x = [];
var add = (arg: any) => x.push(arg);
console.log(doSomething(add)); // Prints '1', not 'Hello, world!'

Read value or return

Often writing function's code I need to make sure certain values are defined or I want immediately return false value. But writing whole if block feels too much typing. Is it possible to write instead of:
function getSomethingByModel(model) {
var id = model.id;
if (! id) {
return;
}
// rest of the code
}
Something like this:
function getSomethingByModel(model) {
var id = model.id || return;
// rest of the code
}
This is pure aesthetics question, not functional one.
To some extent, you can use the && operator to accomplish this and avoid cumbersome if statements:
function getSomethingByModel(model) {
var id = model && model.id,
thing = id && getThingById(id),
otherThing = thing && getOtherThingFromThing(thing);
return otherThing || null; // or alternatively, just return otherThing;
}
If any stage of the process produces a falsey value, the logic will just quickly fall through to the end and return null (or the first falsey value encountered if you use the alternative return statement above).
You could define all your properties at the top of the function (or wherever, because hoisting), then use the side-effects of assignment to cause a return. For example:
function getSomethingByModel(model) {
var id;
if(!(id = model.id)) return false;
// rest of the code
}

Javascript function that returns two different types of variables depending on input?

I'm trying to follow the rule and avoid repeating the same code.
I have this single function but depending on the input I want it to either return an array of objects or an object (not an array of just one object)
e.g.(the actual function is much longer and more elaborate than this one obviously, there are just the last few lines after a much longer calculation)
function (nameParameter, ageParameter, inputType)
{
if (inputType === "asObject")
{
var x = {};
x.name = nameParameter;
x.age = ageParameter;
return x;
}
else if (inputType === "asArray")
{
var y = [];
y.push(nameParameter);
y.push(ageParameter);
return y;
}
};
Is this possible and if so is it good practice? Is there some other way around it?
Otherwise I'll have to create two distinct function with almost the exact same code.
Don't do this. Implement one version and add a wrapper function that converts the the other format you may want. That way the caller always gets consistent behaviour, and theres still no code duplication.
function asObject(nameParameter, ageParameter)
{
//Lots of work here.
var x = {};
x.name = nameParameter;
x.age = ageParameter;
return x;
};
function asArray(nameParameter, ageParameter)
{
//Just defer to the other version and repack its response.
var o = asObject(nameParameter, ageParameter);
var y = [o.nameParameter,o.ageParameter ];
return y;
}
You can simplify your code by declaring the object and array with the values already set, but in my opinion if you have this strict type of coding it is not necessary to keep this function... Anyway, here is a simplified version:
function (nameParameter, ageParameter, inputType) {
var ret;
if (inputType === "asObject") {
ret = {
name: nameParameter,
age: ageParameter
};
} else if (inputType === "asArray") {
ret = [nameParameter, ageParameter];
}
return ret;
};
I left it without name and with a semicolon at the end because I guess it has been declared through a variable.
Yes; that will work fine.
Javascript is not strongly-typed; functions can return whatever they want, whenever they want.
if ( typeof inputType == 'object') {
//object part of code
} else {
//array part of code
}

What's the simplest approach to check existence of deeply-nested object property in JavaScript? [duplicate]

This question already has answers here:
Test for existence of nested JavaScript object key
(64 answers)
Closed 8 years ago.
I have to check deeply-nested object property such as YAHOO.Foo.Bar.xyz.
The code I'm currently using is
if (YAHOO && YAHOO.Foo && YAHOO.Foo.Bar && YAHOO.Foo.Bar.xyz) {
// operate on YAHOO.Foo.Bar.xyz
}
This works, but looks clumsy.
Is there any better way to check such deeply nested property?
If you expect YAHOO.Foo.Bar to be a valid object, but want to make your code bulletproof just in case it isn't, then it can be cleanest to just put a try catch around it and let one error handler catch any missing segment. Then, you can just use one if condition instead of four that will detect if the terminal property exists and a catch handler to catch things if the intermediate objects don't exist:
try {
if (YAHOO.Foo.Bar.xyz) {
// operate on YAHOO.Foo.Bar.xyz
} catch(e) {
// handle error here
}
or, depending upon how your code works, it might even just be this:
try {
// operate on YAHOO.Foo.Bar.xyz
} catch(e) {
// do whatever you want to do when YAHOO.Foo.Bar.xyz doesn't exist
}
I particularly use these when dealing with foreign input that is supposed to be of a particular format, but invalid input is a possibility that I want to catch and handle myself rather than just letting an exception propagate upwards.
In general, some javascript developers under-use try/catch. I find that I can sometimes replace 5-10 if statements checking input with a single try/catch around a larger function block and make the code a lot simpler and more readable at the same time. Obviously, when this is appropriate depends upon the particular code, but it's definitely worth considering.
FYI, if the usual operation is to not throw an exception with the try/catch, it can be a lot faster than a bunch of if statements too.
If you don't want to use the exception handler, you can create a function to test any arbitrary path for you:
function checkPath(base, path) {
var current = base;
var components = path.split(".");
for (var i = 0; i < components.length; i++) {
if ((typeof current !== "object") || (!current.hasOwnProperty(components[i]))) {
return false;
}
current = current[components[i]];
}
return true;
}
Example usage:
var a = {b: {c: {d: 5}}};
if (checkPath(a, "b.c.d")) {
// a.b.c.d exists and can be safely accessed
}
var _ = {};
var x = ((YAHOO.Foo || _).Bar || _).xyz;
Consider this utility function:
function defined(ref, strNames) {
var name;
var arrNames = strNames.split('.');
while (name = arrNames.shift()) {
if (!ref.hasOwnProperty(name)) return false;
ref = ref[name];
}
return true;
}
Usage:
if (defined(YAHOO, 'Foo.Bar.xyz')) {
// operate on YAHOO.Foo.Bar.xyz
}
Live demo: http://jsfiddle.net/DWefK/5/
If you need to check the correctness of the path, rather than the existance of the "xyz" member on the "YAHOO.Foo.Bar" object, it will probably be easiest to wrap the call in a try catch:
var xyz;
try {
xyz = YAHOO.Foo.Bar.xyz;
} catch (e) {
// fail;
};
Alternately, you can do some string-kong-fu-magicTM:
function checkExists (key, obj) {
obj = obj || window;
key = key.split(".");
if (typeof obj !== "object") {
return false;
}
while (key.length && (obj = obj[key.shift()]) && typeof obj == "object" && obj !== null) ;
return (!key.length && typeof obj !== "undefined");
}
The use as follows:
if (checkExists("YAHOO.Foo.Bar.xyz")) {
// Woo!
};
This problem is solved quite beautifully by coffeescript (which compiles down to javascript):
if YAHOO.Foo?.Bar?.xyz
// operate on YAHOO.Foo.Bar.xyz
use a try catch.
a={
b:{}
};
//a.b.c.d?true:false; Errors and stops the program.
try{
a.b.c.d;
}
catch(e){
console.log(e);//Log the error
console.log(a.b);//This will run
}
I actually voted to close the question as duplicate of javascript convert dotnotation string into objects.
However, I guess it's a different topic, but the answer there might still be helpful if you don't want to try-catch all the time.

Categories

Resources