I was curious so I poked the link. The first bullet was not clear to
me.
Why is:
a useless function?
Yes. Not only is it is useless, it can lead to potential misuse.
Compared to `val !== undefined`, `goog.isDef(val)` is less clear and
less efficient.
It could /potentially/ be useful would be in an iteration style pattern
where a callback was needed however the way `goog.isDef` is organized
indicates that it is not intended to be used in that manner, but instead
as a general method to determine if a value is not undefined.
To see how Google uses goog.isDef, I did a search for goog.isDef and
came up with the following:
http://code.google.com/p/doctype/wiki/ArticleCoordinates
| Updated Nov 15, 2008 by pilgrim
| Labels: is-article, about-dom
| ArticleCoordinates
| HOWTO deal with page coordinates (goog.math.Coordinates)
| [...]
| /**
| * Class for representing coordinates and positions.
| * @param {Number} opt_x Left
| * @param {Number} opt_y Top
| * @constructor
| */
| goog.math.Coordinate = function(opt_x, opt_y) {
| /**
| * X-value
| * @type Number
| */
| this.x = goog.isDef(opt_x) ? Number(opt_x) : undefined;
|
| /**
| * Y-value
| * @type Number
| */
| this.y = goog.isDef(opt_y) ? Number(opt_y) : undefined;
|
| };
goog.math.Coordinate first calls `goog.isDef(opt_x)`. As we've seen,
`goog.isDef` checks to see if the value of `opt_x` is not undefined. If
that is the case, then the value of opt_x is converted to a number,
otherwise `this.x` is given value undefined.
It is strange design to be giving `x` a value that could be any of: 1) a
finite number, 2) NaN, or 3) undefined. If avoiding NaN was wanted, (as
would happen for Number(undefined)), then the code fails on that
account. Instead, it could have succeeded by using instead the built-in
`isFinite` function. Example:
this.x = isFinite(opt_x) ? Number(opt_x) : undefined;
- and that could be changed to use the more efficient unary +, which
uses the same type conversion algorithm ToNumber.
Eliminating NaN values from being assigned to the object's `x` and `y`
properties would change Coordinate.equals to return true where two
Coorinates had both NaN values, which might make sense in what appears
as an overengineered alternative to {x:0, y:1}.
Google's goog.math.Coordinate provides a stellar example of why
goog.isDef is useless. It achieves this by showing an example of how the
abstraction reduces code clarity and makes the intent less clear.
Instead, the function isFinite probably should have been used
`isFinite`. (and ideally it would seem best to just use {x: 0, y: 0} on
an as-needed basis).
Although the function is useless, it is also potentially misleading.
This is because the identifier is "isDef" could be interpreted as "is
defined". The closest thing to describign "defined" in ECMAScript is
[[HasProperty]], however this function does not make a determination
about an object having a property; only that val !== undefined. The
function is potentially misleading to a beginner who might use the
function in lieu of the `in` operator to check property existence.
I actually had a conversation about a year ago with a prominent
javascript expert and contributor to YUI regarding a bug in YUI. The
code in question was ObjectAssert.hasProperty.
The problem came down to making the same false inference about "if
obj.prop is undefined, then obj does not have a property prop".
The problem function was calling YAHOO.lang.isUndefined, which does the
same thing that the goog.isDef function does but in the positive sense
(or negative sense, depending how you look at it). That is, it returns
`val === undefined`. Like goog.isDef, YAHOO.lang.isUndefined does not
check an object for the existence of property (that would require both
the object and a property to be passed in).
I noticed the problem when testing a "clone" type of function with an
object that had a property with the value undefined. Although it may
seem odd to give a property with value `undefined`, it can happen (as
the goog.Math.Coordinate does). I wanted to make sure that the property
had been cloned properly and the clone function was required to be able
to handle that case.
Realizing the problem in the YUI function, I filed a bug:
| ObjectAssert.hasProperty -- provides inaccurate results. Instead of
| checking for the presence of a property, Assert.hasProperty checks the
| value.
The author and his manager both wanted me prove what I'm saying with a
testcase, should I actually want the bug fixed.
Much easier, I found, was to just fix the bug myself.
Using a similar strategy to YAHOO.lang.isUndefined, goog.isDef checks to
see if the value is not undefined. If the code must determine if an
object has a property, then goog.isDef(myObj.prop) will not provide that
information. The reason it won't tell you if the object has the property
is that the object could have a property, and the value could be undefined.
That type of abstraction is not useful. It is a useless abstraction that
requires explanation.
What is worse is that it can actually be deceptive to those who don't
know the difference between an object having a property with an
undefined value and an object not having a property.
In contrast val !== undefined is instantly recognizable to anyone who
understands ECMAScript.
Also, reading a little further, the term "nonstandard" might be
avoided. The function statement, it says, is "nonstandard" but it is
in the 3 and 5 standards. The key point is that it is "allowed" and
not "required" and it is that choice of the implementers that make it
a bad choice to use. Calling something in the standards a nonstandard
isn't helping the unenlightened.
No, a Function statement is not defined by either 3 or 5 editions.
Function statement is a nonstandard syntax extension.
Please take a look at the FAQ and see if that doesn't clear things up
for you.
http://jibbering.com/faq/#functionStatement
Asen noted that function declaration appearing where only statements are
allowed will result in a SyntaxError in BESEN and DMDScript. I plan to
add that to the FAQ. Currently, we have:
| Implementations that have the function statement extension process
| Fze as a Statement, in order, while other known implementations
| evaluate Fze upon entering the execution context that it appears in.
| For consistent behavior across implementations, avoid function
| statement; use either FunctionExpression or FunctionDeclaration
| instead.
I'd like to change the FAQ to mention that.
Proposed:
| Implementations that have the function statement extension process
| Fze as a Statement, in order. Others, including JScript, evaluate Fze
| upon entering the execution context that it appears in. Yet others,
| notably BESEN and DMDScript, throw a SyntaxError.
|
| For consistent behavior across implementations, do not use function
| statement; use either FunctionExpression or FunctionDeclaration
| instead.
Garrett