I am still relatively new to Javascript, and have been trying to wrap my head around how a particular library is managing such clean types and naming convention.
The library in question is Telerik's Kendo UI, and specifically I am curious how they are achieving something that reminds me of C# namespaces. For instance... there is a type called an ObservableArray, which can be accessed through kendo.ui.ObservableArray.
I dug into the source code and am really confused about what is going on. I have omitted a lot of the code for proprietary reasons, but the general closure shouldn't be an issue. I was wondering if someone could help me to grasp how they are achieving some of this...
(function ($, evil, undefined) {
var kendo = window.kendo = window.kendo || { cultures: {} },
extend = $.extend,
each = $.each; // more code omitted
function Class() { }
Class.extend = function (proto) {
// most of this code omitted
return subclass;
};
// more code omitted
})(jQuery, eval); // this line is really confusing me
Particularly, what has me lost beyond belief is that second line. Where they are declaring a variable (kendo) equal to a variable defined on window. I have searched high and low for hours and hours and cannot for the life of me figure out where this is first happening. I have been unable to reproduce the same behavior in my own code.
I have figured out that the extend function serves as a way to pair up an object with an existing object, and selectively attach it like an accessible member. But that window.kendo thing, it is driving me crazy.
It's not so complicated. Take this, for example:
var a, b, c;
a = b = c = 100;
Parentheses might help:
a = (b = (c = 100));
c = 100 is actually an expression. It assigns 100 to c and then evaluates to 100. So that progresses to:
a = (b = 100);
then it assigns 100 to b and further simplifies:
a = 100
And it finally also assigns 100 to a.
So when you have the following:
var kendo = window.kendo = window.kendo || { cultures: {} }
First it assigns the result of window.kendo || {cultures: {} } to window.kendo. Then it assigns that same result to the local variable kendo.
The final trick is what window.kendo || {cultures: {} } does, exactly. a || b evaluates to a if a is true, or b if a is false:
10 || 20; //evaluates to 10
undefined || 20; //evaluates to 20
undefined || null; //evaluates to null
So, if window.kendo is not defined yet, window.kendo || {cultures: {} } evaluates to {cultures: {} }. Otherwise, it evaluates to whatever window.kendo is, already.
This is a nifty way of specifying defaults, for example:
> function logit(s, label) {
label = label || "nolabel";
console.log(label + ": " + s);
}
> logit("Hey there")
nolabel: Hey there
> logit("Hey there", "Fooman")
Fooman: Hey there
window.kendo is a way to get a global variable named kendo.
kendo = window.kendo = window.kendo || { cultures: {} }
This will set the value of both the local kendo and the global kendo to either the value of the global if it exists, or if the global does not exist it will set it equal to that object literal.
Related
I want to extend the number class to have instance functions such as odd and even so I can do something like this:
2.odd() => false
2.even() => true
1.even() => false
1.odd() => true
Extending classes is a good Ruby practise: "Ruby check if even number, float".
Is the same true in JavaScript, or does it cause performance issues or some other problem?
Anyway, I can't extend despite my best efforts:
var NumberInstanceExtensions = {
accuracy: function(){
return 'This is cool ' + this
}
}
$.extend(Number.prototype,NumberInstanceExtensions);
alert( $.type(5) ); //-> number
//alert( 5.accuracy() ); //-> Uncaught SyntaxError: Unexpected token ILLEGAL
http://jsfiddle.net/VLPTb/2/
How can I get this to work? The syntax error makes me think this isn't how JavaScript works on a fundamental level. Is my best bet extending the Math class and doing this instead:
Math.odd(2) => false
Math.even(2) => true
Math.even(1) => false
Math.odd(1) => true
That seems far more inelegant than 2.odd().
I think as long as you understand the side-effects of your "extension" then you're okay. I often modify the String prototype to add an "elipsis" method so I can do things like
"SomeString".elipsis()
But start at the beginning. You're not "extending classes" in JavaScript. JavaScript is a prototype-based language. You can modify prototypes to do what you need.
You won't be able to add a method directly to the number itself. You can, however modify the prototype of the Number object:
Number.prototype.even = function(){
return this.valueOf() % 2 === 0;
}
With this, you won't be able to use the following syntax:
10.even();
But, since you aren't hard-coding stuff, otherwise you wouldn't need this function anyways, you CAN do the following:
var a = 10;
a.even(); //true
I might say that you could consider adding a utilities object to do these things, because modifying primitive prototypes is not always guaranteed to be side-effect free.
This function does not really provide any gain for you. You're checking for odd and even, replacing one line of code with another. Think about the difference:
var a = 10;
var aIsEven = a.even();
vs:
var a = 10;
var aIsEven = a % 2 === 0;
You gain three characters of code, and the second option is less likely to break your "JavaScript".
You can extend natives JS objects by using (for example) Number.prototype.myFn = function(){}.
So you could do :
Math.prototype.odd = function(n){
return n % 2 === 0;
};
Math.prototype.even = function(n){
return n % 2 === 1;
};
And then use it like so :
var two = 2;
console.log(Math.odd(2)); // true
BUT I would strongly advise you against extending natives in JavaScript.
You can read more about it here
EDIT : After trying my code on JSFiddle, it appears the Math object has no prototype, you can read more about it here. The code above won't work !
Instead, you could do :
Math.odd = function(n){
return n % 2 === 0;
};
Math.even = function(n){
return n % 2 === 1;
};
console.log(Math.odd(2)); // true
or :
Number.prototype.odd = function(){
return this % 2 === 0;
};
Number.prototype.even = function(){
return this % 2 === 1;
};
console.log(new Number(2).odd()); // true
I'd like to point out that that is already available in the numbers class.
Just use the boolean methods, odd? and even?
2.odd?
=> false
2.even?
=> true
Hope this helps.
No need to create a new class, it already exists in the numbers class.
I've found this string in JavaScript code.
var c = (a.b !== null) ? a.b : null;
This is a shorthand of an if-else statement, however the value null is assigned if it is null. Isn't that ALWAYS equivalent to
var c = a.b
including all cases - exceptions, null, undefined, etc?
In another words, are these lines (always) equivalent?
var c = (a.b !== null) ? a.b : null;
-vs-
var c = a.b
No, they AREN'T NECESSARILY EQUAL always if b is a getter that updates a variable. It's bad practice to code this way though
var log = 0;
var a = {
get b() {
log++;
return log;
}
}
var c = (a.b !== null) ? a.b : null;
// outputs 2
console.log(c);
var log = 0;
var a = {
get b() {
log++;
return log;
}
}
var c = a.b;
// outputs 1
console.log(c);
These statements are logically equivalent.
That being said, and as mentioned in another answer, if a.b has side effects, the statements will not result in the same program state.
This could be readily obvious in the form of var c having a different value depending on which of these statements are executed, or more hidden, if a.b modifies something elsewhere in the program.
Refactoring
As refactoring has been discussed, I'll touch on it briefly. As the above has hopefully made obvious, directly refactoring would not be safe in all scenarios. However, I would still recommend a refactor of one kind or another.
The two possible situations as I see them are:
a.b has no side effects, direct refactoring is safe
a.b has hidden side effects. This represents very unclear, confusing,
and just downright bad code. It should be refactored so that all
changes happening during the statement are clear and obvious to a
reader (hopefully intuitively so, as well as supported by comments).
As #potatopeelings already pointed out, the two possible statements are not always equivalent, since one can write obscure code, which will have different results.
However, if I see a code, like
var c = (a.b !== null) ? a.b : null;
I will assume that the code's intention is
var c = a.b;
so I will change it to make the code prettier. If I will be negatively surprised, that is, the code does not pass the testing phases due to this change, then I will try to find the author of a.b with git blame.
So, my answer is, that the two statements are not equivalent, but should be equivalent in well-written code.
Well, actually not even
var c = (a !== null) ? a : null;
is guaranteed to be equivalent to
var c = a;
when a is resolved by a getter or an ES6 proxy handler on the global object.
Hence for instance, this assign to c the value 0:
Object.defineProperty(self, 'a', { get: function() { return c ^= 1; } });
var c = (a !== null) ? a : null;
console.log(c);
while this assigns to c the value 1:
Object.defineProperty(self, 'a', { get: function() { return c ^= 1; } });
var c = a;
console.log(c);
You're right, var c = a.b is exactly the same as var c = (a.b !== null) ? a.b : null;
My guess is the null in the ternary operator was meant to be anything except null, a default value if you will.
The reason for that confusingly odd syntax is because a.b might be an empty string OR undefined, and apparently an empty string is valid input.
Also, note: a.b might be a function.
In C I know true and false evaluate to 1 and 0 respectively. show in this case just prints to the screen... Not sure what's going on here. I'm expecting to get true back. This 1 is messing up my karma.
show(1 && true);
true
show(true && 1);
1
Simply put - that's how && is defined. In Javascript, a && b returns a if a is falsy and b if a is truthy.
Conversely a || b returns a if a is truthy and b if a is falsy.
This makes sense intuitively - if a is false in a && b, then why bother reading the rest of the expression? You already know the whole thing is false. So just return false. But Javascript makes the decision to return a, which is falsy, instead of making up the value false to return out of nowhere.
This is based on short-circuit evaluation common to all C-style languages.
It allows for much expressiveness in Javascript. For instance this pattern:
var foo = function(opts) {
opts = opts || {}
// ...
}
Implements an optional parameter opts. If opts is not passed in at all, opts = opts || {} will set opts to {}, so the rest of the code does not have to know opts wasn't passed.
In long-hand it is equivalent to the following:
var x = a || b; // is equivalent to
var x;
if(a) {
x = a;
}
else {
x = b;
}
and
var y = a && b; // is equivalent to
var y;
if(!a) {
y = a;
}
else {
y = b;
}
Therefore Javascript can be much more terse than C or Java, because simple if statements can be replaced by || or && entirely. Sometimes this makes the code more terse and less readable and more like Perl, other times it allows for new Javascript patterns, like opts = opts || {}.
Another use is in patterns like
var displayName = user.fullname || user.email;
Which means "use the full name if available; if not, fall back to email." I personally find this expressive and readable, but it's arguably terse and obscure depending on which part of the Javascript community you hail from. Because of examples like this, and essentially the fact that truthy values are far more diverse then falsy values, using short-circuit || is much more common than short-circuit &&, as in your question.
I have little experience in javascript but in other programming languages the following is possible, to set a default value for a missing parameter in a function.
For instance lets say i have a function
function foo(a , b)
return a + b
{
I would like to be able to call the above function with 1 parameter or with 2 parameters
one parameter case:
foo(2) //a =2 and b would be automatically set to a default no argument value,
two parameter case:
foo(1,2) // a = 1 , b = 2 => 3
Is this possible in javascript that is IE 8 compatible or using Jquery 1.7.2?
JavaScript functions allow you to call them with less parameters than specified.
What you're trying to accomplish is possible doing something like the following:
function foo(a , b){
if(typeof b === "undefined"){
b=3;
}
return a + b;
}
foo(5);//return 3;
I strongly suggest that you check for undefined and not rely on the || operator. I've spent hours debugging code that made that assumption and failed when passing 0 or another falsy value. The JavaScript type system can get really tricky, for example "0" is falsy.
ECMAScript Harmony (the next version) allows default parameters like in those other languages using the following syntax
function foo(a , b=3){
return a + b;
}
This does not work in IE8 like the first version though.
No, but you can simulate this effect manually with a tertiary operator or an if statement (just make sure you check for undefined!):
function foo(a, b) {
b = (typeof b === "undefined") ? 2 : b;
return a + b;
}
Yes, it's possible. If a parameter isn't passed, you get a special value "undefined". The following works for me:
function foo(a, b) {
a = a || defaultForA;
b = b || defaultForB;
}
Due to the way Javascript treats conversion to boolean, the following will all be considered undefined in the above code snippet:
undefined
null
0
"" (empty string)
false
So if those values are important to you, you'll need to explicitly test for undefined rather than the blanket "if not false" test being used above.
An undefined parameter evaluates as false, so you can do something like this in the beggining of your function foo:
a = a || 0;
b = b || 0;
That way if a or b exist, they will be evaluated with their own values and with 0 otherwise.
You can just test if you received a parameter:
function foo(a, b) {
if(typeof b === "undefined") {b = 2;}
}
By testing for "undefined" you can also accept parameters that evaluate to false (like null or "" or 0 or false)
I'm using "Closure Compiler", when compiling my scripts I spend the following:
Before compiling:
// ==ClosureCompiler==
// #compilation_level SIMPLE_OPTIMIZATIONS
// #output_file_name default.js
// #formatting pretty_print,print_input_delimiter
// ==/ClosureCompiler==
var myObj1 = (function() {
var undefined; //<----- declare undefined
this.test = function(value, arg1) {
var exp = 0;
arg1 = arg1 == undefined ? true : arg1; //<----- use declare undefined
exp = (arg1) ? value * 5 : value * 10;
return exp;
};
return this;
}).call({});
var myObj2 = (function() {
this.test = function(value, arg1) {
var exp = 0;
arg1 = arg1 == undefined ? true : arg1; //<----- without declare undefined
exp = (arg1) ? value * 5 : value * 10;
return exp;
};
return this;
}).call({});
Compiled:
// Input 0
var myObj1 = function() {
this.test = function(b, a) {
a = a == void 0 ? true : a; //<-----
var c = 0;
return c = a ? b * 5 : b * 10
};
return this
}.call({}), myObj2 = function() {
this.test = function(b, a) {
a = a == undefined ? true : a; //<-----
var c = 0;
return c = a ? b * 5 : b * 10
};
return this
}.call({});
With this I believe the question of the use of "void 0 " and "undefined", is there any difference in the use or the two cases are well?.
Edit
if I define "var undefined" compiled with "void 0 ", if I did not define "undefined" compiled with "undedined. " then not a matter of number of characters between "undefined" and "void 0"
Test
Edit II: performance, based on this link
Code and Test
IE 8:
typeof: 228ms
undefined: 62ms
void 0: 57ms
Firefox 3.6:
typeof: 10ms
undefined: 3ms
void 0: 3ms
Opera 11:
typeof: 67ms
undefined: 19ms
void 0: 20ms
Chrome 8:
typeof: 3ms
undefined: 5ms
void 0: 3ms
From MDN:
The void operator evaluates the given expression and then returns undefined.
This operator allows inserting expressions that produce side effects into places where an expression that evaluates to undefined is desired.
The void operator is often used merely to obtain the undefined primitive value, usually using "void(0)" (which is equivalent to "void 0"). In these cases, the global variable undefined can be used instead (assuming it has not been assigned to a non-default value).
Closure Compiler swaps in void 0 because it contains fewer characters than undefined, therefore producing equivalent, smaller code.
Re: OP comment
yes, I read the documentation, but in the example I gave, "google closure" in a case using "void 0" and another "undefined"
I believe this is actually a bug in Google Closure Compiler!
The real only semantic difference between void expr and undefined is that on ECMAScript 3, the undefined property of the global object (window.undefined on browser environments) is writable, whereas the void operator will return the undefined value always.
A popular pattern that is often implemented, to use undefined without worries is simply declaring an argument, and not passing anything to it:
(function (undefined) {
//...
if (foo !== undefined) {
// ...
}
})();
That will allow minifiers to shrink the argument maybe to a single letter (even shorter than void 0 :), e.g.:
(function (a) {
//...
if (foo !== a) {
// ...
}
})();
Just a follow-up on all the answers before.
They look the same, but to the Compiler they are completely different.
The two code sections compile to different outputs because one is referring to a local variable (the var undefined), and the compiler simply in-lines it because it is used exactly once and is no more than one line. If it is used more than once, then this in-lining won't happen. The in-lining provides a result of "undefined", which is shorter to represent as "void 0".
The one without a local variable is referring to the variable called "undefined" under the global object, which is automatically "extern'ed" by the Closure Compiler (in fact, all global object properties are). Therefore, no renaming takes place, and no in-lining takes place. Voila! still "undefined".
There is no difference, Try it yourself:
void 0 === undefined
will evaluate to true.
undefined is 3 characters longer, I guess that is the reason why they use it that way.