I've read a lot of articles on JavaScript formatting and the rules etc. But my question here is how to format core JavaScript elements (i.e. functions, arrays, and objects)
Usually for functions I use the following:
function myFunction(argument1 , argument2 , optionalargument3) {
optionalargument3 === undefined ? optionalargument3 : "default value";
return optionalargument1;
}
or:
var myFunction = function(argument1 , argument2 , optionalargument3) {
optionalargument3 === undefined ? optionalargument3 : "default value";
return optionalargument1;
}
but this is controversial. For objects I use:
var Car = {
model : undefined
make : "Sudan"
MPG : 7.5
highway-mpg : 11.5
};
of course, this is highly controversial and most people use different methods.
and for for loops, I use:
for(var i = 0; i < (array.length + 1); i++) {
console.log(array[i]);
}
People also seem to have devolved the idea to write out global in a list before objects or functions.
eg:
var winMessage = "You Win!";
var loseMessage = "Loser!";
var cash = 0;
var intrest = null;
function randomInteger(low , high) {
return Math.floor((Math.random())*(high-low))+low
}
var Car = {
model : undefined
make : "Sudan"
MPG : 7.5
highway-mpg : 11.5
};
Are there any universal accepted, or a generically "proper" way to format your JavaScript code?
It's mostly down to preference but it is important to keep a consistent style throughout your code base particularly if you are working in a team to increase readability of your code.
You can either define your own style or adopt an existing one such as the Google style guide (https://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml), or Crockfords (http://javascript.crockford.com/code.html).
JavaScript has automatic semi-colon insertion which means that some types of formatting can lead to code that doesn't work as intended such as the following where the interpreter will ignore the object literal because it will insert a semi-colon directly after the return keyword:
return
{
name: "Foo"
};
In your example
optionalargument3 === undefined ? optionalargument3 : "default value";
doesn't actually do anything because there is no assignment, but a nice clean way to deal with default arguments is instead of using
arg = arg === undefined ? "default value" : arg;
you can use the semantically identical and cleaner version:
arg = arg || "default value";
Related
I already searched for similar issues but I didn't find anything that could help me yet.
I'm trying to reach a picture path (using JSON format) depending on the material type of the picked element. Actually, my code is built like this:
if (globalData.Material.Mat_type == "OSCILLOSCOPE") {
var picture = (globalData.Material.Oscilloscope.picture);
}
if (globalData.Material.Mat_type == "ALIMENTATION") {
var picture = (globalData.Material.Alim.picture);
}
But not optimized at all, so Im trying to make it this way :
var mat_type = (globalData.Material.Mat_type);
var picture = (globalData.Material[mat_type].picture);
But it doesn't work... Got some exception:
TypeError : globalData.Material[mat_type] is undefined.
I already tried a lot of things, have you got any idea? Thanks!
I outlined the issue with character case in the comment under the question, so presumably adjusting value of globalData.Material.Mat_type could do the trick:
var mat_type =
globalData.Material.Mat_type.charAt(0).toUpperCase() +
globalData.Material.Mat_type.substr(1).toLowerCase();
I can also see that this general rule may not be applicable in all cases. If it's not a typo, it won't work for the second case where Mat_type == "ALIMENTATION", because then you try to access Alim property of Material instead of Alimentation. In this case you could access property by prefix:
function pictureOf(material) {
if (!material || !String(material.Mat_type)) {
return null;
}
let mat_type = String(material.Mat_type).toUpperCase();
for (var propertyName in material) {
if (mat_type.startsWith(propertyName.toUpperCase())) {
return material[propertyName].picture || null;
}
}
return null;
}
console.log(pictureOf({
Mat_type: "OSCILLOSCOPE",
Oscilloscope: {
picture: "picture of oscilloscope"
}
}));
console.log(pictureOf({
Mat_type: "ALIMENTATION",
Alim: {
picture: "picture of alimentation"
}
}));
But this kind of approach can be error prone, if multiple properties share the same prefix. There's also a hidden issue with case-insensitive prefix matching in case you use some special unicode characters in property names. Lastly this method is not efficient, because it has to iterate over all properties of the object (worst case scenario). It can be replaced with much safer property mapping:
const matTypeMapping = {
"ALIMENTATION": "Alim"
};
function pictureOf(material) {
if (!material || !String(material.Mat_type)) {
return null;
}
let matType = String(material.Mat_type);
// find property mapping or apply general rule, if mapping not defined
let propertyName = matTypeMapping[matType] ||
matType.charAt(0).toUpperCase() + matType.substr(1).toLowerCase();
return material[propertyName].picture || null;
}
console.log(pictureOf({
Mat_type: "OSCILLOSCOPE",
Oscilloscope: {
picture: "picture of oscilloscope"
}
}));
console.log(pictureOf({
Mat_type: "ALIMENTATION",
Alim: {
picture: "picture of alimentation"
}
}));
NB: To avoid headaches, maybe you should prefer strict equality operator over loose equality operator.
Problem Solved
Peter Wolf was right ! It was a case-sensitive issue
I actually don't know how to promote his comment, sorry for this..
Anyway, thank you guys !
var mat_type = (globalData.Material.Mat_type);
if(mat_type!==undefined)
var picture = (globalData.Material[mat_type].picture)
Just do an existential check before accessing the value, for keys that may not be present.
I have to put a validity check before performing any operation using the object which -
If that object exists.
If its exists then a certain property also exists on it.
For ex-
var obj = {
key: "value"
}
Now the most conventional way to do this is-
if(obj) {
if(obj.hasOwnProperty('key') {
//Do some action (validity check pass)
//For Example- console.log(obj.key);
}
}
But i am looking for a more faster and efficient way there must be to solve this.
I'd do:
if ( typeof obj != "undefined" && obj.hasOwnProperty('key') )
{
console.log('found');
}
else
{
console.log('not found');
}
Like this ?
var obj = {
key: "value"
}
var objx = null;
if(obj && "key" in obj){
document.getElementById("check_one").innerHTML = "is valid";
}else{
document.getElementById("check_one").innerHTML ="is not valid";
}
if(obj && "notkey" in obj){
document.getElementById("check_two").innerHTML = "is valid";
}else{
document.getElementById("check_two").innerHTML ="is not valid";
}
if(objx && "key" in objx){
document.getElementById("check_three").innerHTML = "is valid";
}else{
document.getElementById("check_three").innerHTML ="is not valid";
}
<p>
Check One (should be valid): <span id="check_one"></span>
</p>
<p>
Check Two (should be invalid): <span id="check_two"></span>
</p>
<p>
Check Three (should be invalid) <span id="check_three"></span>
</p>
Depending on your required browser support you could also use Reflect.has
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/has
like
Reflect.has(obj, 'key');
if you want to support older IEs I guess you will have to go with HasOwnProperty, there wont be any other possibility - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty
You can definitely combine the two statements into one as #Stuart and #phuzi mentioned:
if(!!obj && obj.hasOwnProperty('key')
also hasOwnProperty will ignore all inherited properties that come through the prototype. If you'd prefer to include the inherited properties the in operator can be used here.
if (!!ob && (prop in ob))
If you care about the protoype chain, then no there isn't a better way; you have to check every link in the chain down.
If not, and the properties usually exist it may be worth just accessing the property and catching any exception, but use performance testing to see.
But I'd say the issue is that you aren't restrictive enough with your input: require the caller of your code to provide an object and let them handle it.
To me it "smells" like two separate issues: "Does the object exist?", if so provide a default and "Does the object have this property?", the business logic.
If so, use a standard pattern to set the default: "obj = obj || {};" for instance; and then the test becomes a single call, hard to make "faster".
Background
We have much of our data formatted like
var X = {value:'some val',error:'maybe an error',valid:true}
as a result we find ourselves calling X.value ALL the time.
We don't use the .error or .valid nearly as much, but we do use it.
What I want
To quit calling .value everywhere, but to still have access to meta data on a per data point level.
The Question
Is there one of
A) A way to put meta data on a primitive? attaching .error to an int for example? Is it possible for bools or strings?
B) A way to make a class that can be treated as a primitive, providing a specific data member when I do? IE X.value = 5, X+3 returns 8.
C) A better design for our data? Did we just lay this out wrong somehow?
You can set the method toString() to your object and return value.
var X = {
value: 1,
error:'maybe an error',
valid:true,
toString: function() {
return this.value;
}
}
X.value = 5;
console.log(X+3);
You can represent you data as a function object that also has properties:
var X = () => 1;
X.value = 1;
X.error = 'maybe an error';
X.valid = true,
console.log(X()); // 1
console.log(X.valid); // true
For better design you can encapsulate the creation of the data object in another function.
I'm using a javascript game engine called panda, and i'm getting an error in the console (Uncaught Class BG already created). And when i explore the source code of the engine, i found the code that is throwing the error (below). My question is, in the second if statement what is the meaning of (this[name])? i don't understand what exactly its saying. Any help would be appreciated. Thanks in advanced.
createClass: function(name, extend, content) {
if (typeof name === 'object') return this.Class.extend(name);
if (this[name]) throw 'Class ' + name + ' already created';
if (typeof extend === 'object') {
content = extend;
extend = 'Class';
}
There are two type of notation in JavaScript to refer object properties.
var Employee = { "firstname" : "John", "lastname" : "Smith" }
1. Dot notation
Employee.firstname; // John
Employee.lastname; // Smith
2. Bracket notation
var fname = "firstname";
var lname = "lastname";
Employee[fname]; // John
Employee[lname]; // Smith
So, incase if the object property is a variable we can user bracket notation.
So in your case this[name] is referring to a property on this object.
This is not really clear from the fragment of code, you've posted, but this might be some kind of class container.
if(this[name]) ... Checks for existence of property with the given name (which in this context shows if the class with such name is already registered.)
The fact you are getting the error means that you have tried to register two classes with the same name.
this[X] will check inside if condition value is undefined
if (this[name]) throw 'Class ' + name + ' already created';
if this[name] is undefined will not goes into if statement.
Example
var chkCondition;
alert(chkCondition);
// This will not goes inside if because chkCondition is undefined.
if (chkCondition) {
alert('yes');
}
chkCondition="A";
// Now chkCondition has value "A" that's why it will return
// true and goes inside if and alert "yes"
if (chkCondition) {
alert('yes');
}
Demo
In JavaScript, using the Prototype library, the following functional construction is possible:
var words = ["aqueous", "strength", "hated", "sesquicentennial", "area"];
words.pluck('length');
//-> [7, 8, 5, 16, 4]
Note that this example code is equivalent to
words.map( function(word) { return word.length; } );
I wondered if something similar is possible in F#:
let words = ["aqueous"; "strength"; "hated";"sesquicentennial"; "area"]
//val words: string list
List.pluck 'Length' words
//int list = [7; 8; 5; 16; 4]
without having to write:
List.map (fun (s:string) -> s.Length) words
This would seem quite useful to me because then you don't have to write functions for every property to access them.
I saw your request on the F# mailing list. Hope I can help.
You could use type extension and reflection to allow this. We simple extend the generic list type with the pluck function. Then we can use pluck() on any list. An unknown property will return a list with the error string as its only contents.
type Microsoft.FSharp.Collections.List<'a> with
member list.pluck property =
try
let prop = typeof<'a>.GetProperty property
[for elm in list -> prop.GetValue(elm, [| |])]
with e->
[box <| "Error: Property '" + property + "'" +
" not found on type '" + typeof<'a>.Name + "'"]
let a = ["aqueous"; "strength"; "hated"; "sesquicentennial"; "area"]
a.pluck "Length"
a.pluck "Unknown"
which produces the follow result in the interactive window:
> a.pluck "Length" ;;
val it : obj list = [7; 8; 5; 16; 4]
> a.pluck "Unknown";;
val it : obj list = ["Error: Property 'Unknown' not found on type 'String'"]
warm regards,
DannyAsher
>
>
>
>
>
NOTE: When using <pre> the angle brackets around <'a> didn't show though in the preview window it looked fine. The backtick didn't work for me. Had to resort you the colorized version which is all wrong. I don't think I'll post here again until FSharp syntax is fully supported.
Prototype's pluck takes advantage of that in Javascript object.method() is the same as object[method].
Unfortunately you can't call String.Length either because it's not a static method. You can however use:
#r "FSharp.PowerPack.dll"
open Microsoft.FSharp.Compatibility
words |> List.map String.length
http://research.microsoft.com/fsharp/manual/FSharp.PowerPack/Microsoft.FSharp.Compatibility.String.html
However, using Compatibility will probably make things more confusing to people looking at your code.