JSLint Reports on last 2 Production Versions of jQuery

A

Andrea Giammarchi

If a developer doesn't understand JSLint's warnings then it
is probably a good idea for them to be following its
suggestions.

that's for sure, but still trying to understand why and not just
considering it "correct" in its absolute meaning.

The point of the second suggestion is to use '===', not
'=== undefined' specifically. Both are suggestions are good
advice.

no, these are not good suggestions if the reason is: "compare via ==
causes coercion"
There are cases and cases and null and undefined are a special case.
Moreover it could be extremely dangerous to rely in undefined variable
(which costs lookup as well)


I'd say that was 5 minutes well spent. Running a colleague's
code through JSLint and then explaining the warnings to them
is a good investment. --Antony

Agreed, except yoou have to repeat yourself every time you meant
something ... and you would like to be able to validate against a
validation tool, so it should be "almost perfect" while this == null
is the most annoying thing ever to me.

Regards
 
A

Antony Scriven

[...]
The point of the second suggestion is to use '===', not
'=== undefined' specifically. Both are suggestions are good
advice.

no, these are not good suggestions if the reason is:
"compare via == causes coercion" There are cases and
cases and null and undefined are a special case.

null !== undefined as you well know.
Moreover it could be extremely dangerous to rely in
undefined variable (which costs lookup as well)

Yes, I agree. That was the first suggestion I was referring
to; you snipped that.
I'd say that was 5 minutes well spent. Running a colleague's
code through JSLint and then explaining the warnings to them
is a good investment. --Antony

Agreed, except yoou have to repeat yourself every time
you meant something [...]

I've not found that in my experience. --Antony
 
R

Richard Cornford

It's possible that this is the case. But my take is that the
quality of JS found around the web is better than it was before
the onset of the GP libraries.

While my impression is that it is about the same.
There are still plenty of really poor scripts floating around
(and I'm talking about ones that make jQuery et al
look positively brilliant)

What about the really poor scripts that use JQuery et al?
but they no longer get the exposure they used to, as it's
become so easy to achieve what these sometimes massive
one-off scripts did using only line or two of jQuery-based
code. (Dojo, MooTools, YUI, whatever.)

The "massive" one-of scripts you refer to (at least the better of
them) tended to be designed to be copied into a web page and then
given a "line or two" of configuration. There is not that much
difference between doing that and using a general purpose library,
except that the one-off script likely did not contain much that it did
not use, but the general purpose library will contain some that is not
used in any equivalent task.

I do see libraries such as JQuery superseding the copy-n-paste script
collections of the past, but only in that they provide the equivalent;
a source of example code that people who don't know what they are
doing can copy and paste into their own pages, achieve a 'working'
outcome, and elaborate through repletion. Indeed, I see that as the
best (if not the only) way in which any new library will achieve
'popularity'. Technical quality will always be largely irrelevant (so
long is it isn't so bad that it is obviously non-functional on common
browsers) because the people looking for a 'solution' to their problem
cannot judge that aspect, while the (relative) ease of pasting an
example into a working context is something that can easily be judged.
Sure these libraries to some degree impose their viewpoints
upon their users -- MooTools users are more likely to look
for OO solutions to their problems, jQuery people always want
to "find something, do something" -- but I don't think
that routinely leads to a a counter-productive skewing of
perspectives.

That isn't what I was referring to. I was thinking in terms of
people's perceptions of their own abilities. I have observed before
that early superficial success (often following earlier frustration)
with the language seems to result in a quite unjustified
overconfidence in ones own abilities, and that while suffering that
overconfidence it becomes difficult to learn/advance (due to the
perception that you have already learnt/advanced). I base this on both
my own experience and observations of others.

I avoided becoming stuck at that first hurdle by interacting with a
(large-ish) number of people who really knew javascript, and were not
afraid letting people know when they were wrong in very plain
language. But what if the people you look to are themselves stuck in
at some early stage, blinded by their overconfidence and trying to be
big fish in some suitably small pond?

I have already cited one example, and here is another in the form of a
book review, of John Resig's "Pro Javascript Techniques":-

<URL: http://robertnyman.com/2007/01/30/pro-javascript-techniques-by-john-resig/
- where the author concludes:-

"I would say that any JavaScript web developer out there, from
intermediate to advanced, can learn something sincerely valuable from
this book. If you’ve just hooked on JavaScript, and want to be a
scripting star, this is the book that explains how to learn about the
inner workings of object-orientation in JavaScript, event handling and
stretching the limits. With some more appealing use cases, this would
be almost a perfect advanced book about JavaScript."

From which we can conclude that the author sees himself as someone who
should be giving advice on the subject, giving advice on "advance"
javascript learning and so presumably considering himself to be
"advance". Yet where does this review cover the many technical
inaccuracies in Resig's book? Even disregarding the books many other
faults, the many statements made that are just technically false
should not have gone by unnoticed by an "advanced" reader, and so such
a positive conclusion would seem unwarranted. Again the author's
perception of his own abilities have lead poor advice being given, but
advice that will likely impact on its reader's perceptions of their
abilities.
Strange, I commented on the same issue with that pattern in a
different forum a few days ago:

<http://forum.jquery.com/topic/advanced-plugin-authoring-tutorial>

I hadn't looked at his other posts to realize that he was quite
possibly a blowhard. I just assumed he was confused and had left
behind detritus from earlier versions of his work. But I think the
answer is more fundamental: his grasp of JS is fairly tenuous.

Yes, "enterprise level", "advanced", "pro", ect., yet a fairly tenuous
grasp on javascript. If that is not a skewed perception I don't know
what is.
I think one of the way they advance is to actually wean
themselves away from using their tool of choice, taking with
them some of what they've learned. If they've learned something
about using closures to maintain state from their work with jQuery,
perhaps they'll take that along. If they've learned how to
decorate objects with additional methods from Prototype, maybe
they'll take that. If they've learned how to structure their
JS in an OO manner from MooTools, that might be what they take.

Of course they'll have unlearning to do. But most advancement
involves some degree of unlearning.

But what if the things that they unlearn include the opinion that
starting out using a general purpose liberally was a good idea?
There will always be those who perceive themselves as more
advanced than they are. And some of them will obnoxiously
trumpet themselves and the knowledge they think they've acquired.
They're likely a very small minority.

Small minorities can have a very disproportional influence. People who
trumpet appealing idea will tend to be found appealing; your don't
have to learn javascript in order to script web browsers at an
enterprise level, read this book and you will lean all you need to
know, we have thought of everything so you don't have to ... .

Richard.
 
A

Andrea Giammarchi

null !== undefined as you well know.

Antony, that is true, but null == undefined does not cause coercion
the suggestion means.

null == {valueOf:function(){return null}} is FALSE

while

1 == {valueOf:function(){return 1}} is TRUE

I do believe this is the coercion JSLint talks about, nothing to do
with specified behaviors

We could say the undefined internal prototype is null so it's normal
to me that null == undefined and, again, undefined is not a proper
value to rely on.
It is surely strictly different "!==" from null, which is a static
constant as true or false (safer 'cause we cannot reassign it) but in
most of the case we don't need the undefined "concept" sicne == null
is all we need to understand if a variable has been defined or it is
exactly null (arguments, properties, etc)
In few words, 99% of the time that is what we want to check, 1% is a
strict operation for those that decided that null and undefined have
different meanings (bad design, imho)
This is what I am complaining about, that warning should be clearer,
it should be a NOTICE rather than a warning, or it should be possible
to disable.

Then we have other gotchas ... but this is another story.

I've not found that in my experience. --Antony

Have you ever tried to validate against JSLint before the build? ...
it is not possible right now to remove that bloody warning and
warnings for non teachy people are never welcome.

Regards
 
S

Scott Sauyet

Richard said:
Certainly restricting the reading of the content seems odd (perhaps
there is money to be made from the user database so it is advantageous
to force as many registrations as possible).

Although I suppose that could make sense, it seems to be the least
popular areas that require registration.
On the other hand, the parts of the new JQuery forum that are readable
function so slowly that I don't have the patience to consider using
that system.

It's been very inconsistent for me in speed. Sometimes it seems
positively snappy. But it seems so much less useful than the Google
Groups version. And as with too many other things in that community,
it seemed to be presented as a _fait accompli_, rather than an idea
for community discussion. Mind you, I'm one of the ones who has
praised jQuery for its helpful community, but there have been some
knuckle-brained actions.
Is that how it works? My impression was that at some point someone had
to do something like:-

$(' xxx ').pluginName();

- to set-up the plugin, and it so it was the JQuery object for that
call that replaced the - pluginName - property of - $.fn - (which is
the JQuery prototype). Without that - $(' xxx ').pluginName - would
refer to a function, and not have the plugin methods.

You're absolutely right. I'm not even sure how I posted it in that
manner, because I actually went to the bother of creating a minimal
plug-in using the architecture as described, and of course had to do
what you noted. When I wrote it up, obviously I misreported the
details.

I kept wondering if there was something that the author was forgetting
to include in his write-up, but the more I think about it, the less I
believe that he had created anything useful, all his talk about "This
is a pattern I first developed for my own needs, and now has found its
way into Fortune 500 companies," notwithstanding.

I am glad that someone questioned this in a context that the author
would find hard to dismiss/ignore, but was there any response? I
assume that there was not.

Absolutely none. My response was a week ago, and there has been no
other activity in the thread.

I was trying to find a way to do what the author seemed to want, and
haven't found anything very useful. Forgetting the specifics of
JQuery, can anyone suggest a useful way of defining a namespace for
additional functions on the prototype of a constructor function so
that those additional functions will be called in the context of the
object created by the constructor?

Perhaps that's a little dense. :)

If I have a constructor,

function MyWidget() { /* ... */}

and a simple plugin architecture:

MyWidget.prototype.myPlugin = function() {
// here "this" is the object created by 'new MyWidget()'
}

Is there a straightforward way to create a plug-in namespace for some
related functionality so that the object constructed is the context
object for calls to the namespaced methods?

// MyWidget.prototype.namespace = ???

var widget = new MyWidget();
widget.namespace.method1() {
// "this" should be a reference to the widget created.
}

Obviously, it wouldn't be hard to do something that worked like this:

widget.namespace().method1()

that had a similar property. In fact, I think it's simple:

MyWidget.prototype.namespace = function() {
var self = this,
method1 = function() {/* ... */},
method2 = function() {/* ... */};
return {
method1: function(){method1.apply(self);},
method2: function(){method2.apply(self);}
};
};


But that doesn't feel quite right. I'd really rather have

widget.namespace.method1()

But I can't think of a way to do this. Any suggestions?

-- Scott
 
R

Richard Cornford

On Mar 5, 1:37 pm, Scott Sauyet wrote:
I kept wondering if there was something that the author was
forgetting to include in his write-up, but the more I think
about it, the less I believe that he had created anything
useful, all his talk about "This is a pattern I first
developed for my own needs, and now has found its way into
Fortune 500 companies," notwithstanding.
<snip>

The latter isn't too incredible. We agree that the 'pattern', as
proposed, isn't going to do what is being claimed for it. At the same
time it is difficult to see how any (even pretty incompetent) script
author would propose such code without even executing it once, so
there must be a way of using this where it can appear to be working.
That one situation is going to be when the - $(' xxx ').pluginName();
- call is applied to a query result where that query result is the
only one to which/with which the plugin is ever used (that is without
the proposed sub-methods, as they won't work even in this limited
case), and the results of that query don't change. As a 'plugin
pattern' the code is a disaster, but as a one-off specialised script,
used under those circumstances, it will (broadly) 'work'.

And that is enough. It is entirely credible that the author has used
it, used it repeatedly, and ended up with the results being deployed
in/on the web applications/sites of Fortune 500 companies, with no
apparent resulting issues. Of course, given what we know about the
code, that says more about the value of the argument "this script is
used by (many, significant, large, etc.) companies, so it must be
good" than it does about the quality of any code that argument is
applied to.

Richard.
 
S

Scott Sauyet

Richard said:
While my impression is that it is about the same.


What about the really poor scripts that use JQuery et al?


The "massive" one-of scripts you refer to (at least the better of
them) tended to be designed to be copied into a web page and then
given a "line or two" of configuration. There is not that much
difference between doing that and using a general purpose library,
except that the one-off script likely did not contain much that it did
not use, but the general purpose library will contain some that is not
used in any equivalent task.

I wish I could remember its name, but I remember having to remove a
150K animation script from a site. All it did was animate positions
and sizes. It was littered with "if (document.layers)" and "if
(document.all)", and worse, it required the user to add those same
guards to sections of their own code. It was easy enough to replace
with a small custom script, and it was replaced at a time when the
client didn't care about the version 4 browsers, so the code was
reasonably clean. But what I remember most about it was that this was
a *popular* script.

I simply haven't seen that sort of thing with the GP libraries. I've
seen plenty of new gratuitous use of animations in pages because they
already include, say, dojo, and it's so easy to just add an animation
now. But I haven't seen the kind of nonsense that requires a new
release of the script on every point release of a browser.

One might not like the APIs provided by these GP libraries, but they
do usually provide APIs straightforward enough that the code that uses
them is simple to write and comprehend. In many site, the worst
problem of code using JQuery is often the relatively innocuous failure
to cache the JQuery objects created, running queries over and over.

I'm not trying to say there is no bad code written by users of GP
libraries. There is certainly some horrendous stuff. But I'm seeing
much less awful code today than five years ago.

I do see libraries such as JQuery superseding the copy-n-paste script
collections of the past, but only in that they provide the equivalent;
a source of example code that people who don't know what they are
doing can copy and paste into their own pages, achieve a 'working'
outcome, and elaborate through repletion. Indeed, I see that as the

"elaborate through repletion"?
best (if not the only) way in which any new library will achieve
'popularity'. Technical quality will always be largely irrelevant (so
long is it isn't so bad that it is obviously non-functional on common
browsers) because the people looking for a 'solution' to their problem
cannot judge that aspect, while the (relative) ease of pasting an
example into a working context is something that can easily be judged.

I'm trying to figure out what it is about the Web that makes this
problem so much more severe than in other development environments.
It certainly seems to be so. Ease of use trumps other measure of
quality all the time in web development. Any thoughts on why?

[ ... ] I was thinking in terms of
people's perceptions of their own abilities. I have observed before
that early superficial success (often following earlier frustration)
with the language seems to result in a quite unjustified
overconfidence in ones own abilities, and that while suffering that
overconfidence it becomes difficult to learn/advance [ ... ]

And, as you say, this becomes especially problematic if people so
stuck become influential.

There is of course a large spectrum of ability in almost any field of
endeavor. With web technologies, including JS, it does seem that at
lot more people without particularly advanced skills do see themselves
as extremely knowledgeable. Perhaps its the number of amateurs
involved. There aren't that many people who aren't professional
programmers or academics trying to implement a tricky cryptography
algorithm in C++. But the church's website might well be entirely
maintained by someone who learned most of their web technologies by
cutting and pasting from sties they like.

And even those of us who are professional are not necessarily as
advanced as we might like. I personally have become involved with
c.l.j.s. because I know that I was missing some fundamentals. For my
last few positions, I've been the go-to-guy on the team for JS
issues. In some cases, I could come up with working solutions to
problems even though I didn't understand all of the underlying
principles thoroughly. I figured that here, I would be able to
contribute and learn at the same time.

For those people who think they're beyond that, the only hope I have
is that they'll be jolted out of their complacency when they actually
do get in over their heads and somebody shows how much they still have
to learn.

Of course [GP library users trying to advance will] have
unlearning to do.  But most advancement involves some
degree of unlearning.

But what if the things that they unlearn include the opinion that
starting out using a general purpose liberally was a good idea?

:)

They might. That's a harsher lesson than they might be ready for, but
if it really is the case, presumably they'll eventually learn it as
they advance.

[ ... much other interesting discussion deleted, as I really have to
get back to work ... ]

-- Scott
 
A

Antony Scriven

Antony, that is true, but null == undefined does not
cause coercion the suggestion means.

== can cause type coercion even if it doesn't in all cases.
And type coercion to boolean wouldn't change the the
semantics of null == undefined. I think you are dwelling too much
on the wording here. It might be worth noting that searching
for the word 'coercion' in the standard brings back Number(null)
matches (and not Number(undefined) matches).
[...]
most of the case we don't need the undefined "concept"
sicne == null is all we need to understand if a variable
has been defined or it is exactly null (arguments,
properties, etc)

Yes but these are different things. One possible problem
could be thinking that a variable holds the value null when
really you forgot to initialise it.
In few words, 99% of the time that is what we want to
check, 1% is a strict operation for those that decided
that null and undefined have different meanings (bad
design, imho)

But they do have different meanings. There is a problem of
intent here. If I'm reading your code and I see
'if(x==null)', then I don't know if you really did mean
'if(x === null || typeof x == "undefined")' or if you made
a mistake. It might be more convenient for you to write, but
not for anyone who has to read it.
This is what I am complaining about, that warning should
be clearer, it should be a NOTICE rather than a warning,
or it should be possible to disable.

I think this is covered by the following warning: 'JSLint
will hurt your feelings.'
[...]

Have you ever tried to validate against JSLint before the
build?
Yes.

... it is not possible right now to remove that
bloody warning and warnings for non teachy people are
never welcome.

Don't take it too personally, it's only a tool. And I can
think of one easy way to remove the warning. :) --Antony
 
A

Antony Scriven

[...]

If I have a constructor,

function MyWidget() { /* ... */}

and a simple plugin architecture:

MyWidget.prototype.myPlugin = function() {
// here "this" is the object created by 'new MyWidget()'
}

Is there a straightforward way to create a plug-in
namespace for some related functionality so that the
object constructed is the context object for calls to the
namespaced methods?

// MyWidget.prototype.namespace = ???

var widget = new MyWidget();
widget.namespace.method1() {
// "this" should be a reference to the widget created.
}

Obviously, it wouldn't be hard to do something that worked like this:

widget.namespace().method1()

that had a similar property. In fact, I think it's simple:

MyWidget.prototype.namespace = function() {
var self = this,
method1 = function() {/* ... */},
method2 = function() {/* ... */};
return {
method1: function(){method1.apply(self);},
method2: function(){method2.apply(self);}
};
};

But that doesn't feel quite right. I'd really rather have

widget.namespace.method1()

But I can't think of a way to do this. Any suggestions?

var addnamespace = function(obj, namespace, methods){
var m;
obj[namespace] = {};
for(m in methods){
obj[namespace][m] = function(){
return methods[m].apply(obj, arguments);
};
}
};

methods = {
method1: function(){
return this.x
}
};

var MyWidget = function(){
this.x = 1;
addnamespace(this, 'namespace', methods);
};

var w = new MyWidget();
w.x; // -> 1
w.x = 2;
w.namespace.method1(); // -> 2

Of course, there's an easier way to accomplish this:

w.namespace_method1();

--Antony
 
S

Scott Sauyet

Antony said:
Scott Sauyet wrote:

[related to my request for t a useful way of defining a namespace for
additional functions on the prototype of a constructor function so
that those additional functions will be called in the context of the
object created by the constructor]
    var addnamespace = function(obj, namespace, methods){
        var m;
        obj[namespace] = {};
        for(m in methods){
            obj[namespace][m] = function(){
                return methods[m].apply(obj, arguments);
            };
        }
    };

    methods = {
        method1: function(){
            return this.x
        }
    };

    var MyWidget = function(){
        this.x = 1;
        addnamespace(this, 'namespace', methods);
    };

Thank you. This does add the namespace, but it does something that I
was trying to avoid, which is making a copy of the namespace and its
methods for each object created. I suppose if there is a solution, it
will probably have some wrapper functions in the namespace the way
your example and my earlier one with a namespace function did, but I'd
rather not have the namespace tied to each instance if at all
possible.

Of course, there's an easier way to accomplish this:

    w.namespace_method1();

The intent, though, is that the prototype of the widget function
serves as the way to attach various collections of new behaviors, each
of which should get its own unique namespace. Although a naming
convention might be the only realistic mechanism, I was hoping for
something a bit more elegant.

Thanks for the reply,

-- Scott
 
A

Antony Scriven

Antony said:
Scott Sauyet wrote:

[related to my request for t a useful way of defining
a namespace for additional functions on the prototype of
a constructor function so that those additional functions
will be called in the context of the object created by the
constructor]
var addnamespace = function(obj, namespace, methods){
var m;
obj[namespace] = {};
for(m in methods){
obj[namespace][m] = function(){
return methods[m].apply(obj, arguments);
};
}
};

methods = {
method1: function(){
return this.x
}
};

var MyWidget = function(){
this.x = 1;
addnamespace(this, 'namespace', methods);
};

Thank you. This does add the namespace, but it does
something that I was trying to avoid, which is making
a copy of the namespace and its methods for each object
created.

Well, it only makes a copy of the proxy object containing
the wrapper functions, not the methods object. Is that
really so bad?
I suppose if there is a solution, it will probably have
some wrapper functions in the namespace the way your
example and my earlier one with a namespace function did,
but I'd rather not have the namespace tied to each
instance if at all possible.



The intent, though, is that the prototype of the widget
function serves as the way to attach various collections
of new behaviors, each of which should get its own unique
namespace.

I don't see how you might get a reference to your new object
before you've executed the constructor.
Although a naming convention might be the only realistic
mechanism, I was hoping for something a bit more elegant.

Are naming conventions so bad? And with regard to the
wrapper functions, elegance in language x doesn't
necessarily translate into elegance in Javascript. And then
you have to weigh up the issue of elegance against that of
additional code complexity in your library and any extra
semantic burden that you might be placing upon developers
using your code.

Do you have a pressing need for the kind of namespaces that
you describe? The speed and memory overhead of the first
method I described might not be an issue in practice. You'd
have to profile it in action. --Antony
 
S

Scott Sauyet

Antony said:
Well, it only makes a copy of the proxy object containing
the wrapper functions, not the methods object. Is that
really so bad?

Perhaps not. I may not have made it clear at the outset that this is
more an academic exercise, not a practical need. I'll discuss at the
bottom a little more of the motivation.
I don't see how you might get a reference to your new object
before you've executed the constructor.

That's not a problem for methods:

var MyWidget = function() { /* ... */ }
MyWidget.prototype.method3 = function() {
// "this" refers to the widget that was constructed.
}

I was wondering if there was some way to gain this behavior with a
namespace object. I couldn't come up with one, and thought it quite
likely there wasn't one, but I thought I'd see if anyone had a
suggestion.

Are naming conventions so bad? And with regard to the
wrapper functions, elegance in language x doesn't
necessarily translate into elegance in Javascript. And then
you have to weigh up the issue of elegance against that of
additional code complexity in your library and any extra
semantic burden that you might be placing upon developers
using your code.

Three's nothing wrong with naming conventions. My notion of elegance
is probably quirky, but very clear to me. But the goal is definitely
to lighten the burden of developers using the code. My hope was that
if there was a way of doing this, it might be possible to wrap it in a
pattern or even a function call that grouped their functions into a
namespaced plug-in.

Do you have a pressing need for the kind of namespaces that
you describe? The speed and memory overhead of the first
method I described might not be an issue in practice. You'd
have to profile it in action. --Antony

There is no pressing need. It grows out of a dissatisfaction with the
way JQuery UI plug-ins are written. They may have the best, or even
the only, realistic solution. But I've never liked it. JQuery's '$'
function is a constructor that creates an object wrapping a number of
DOM elements. (This is an oversimplification, but never mind.) Plug-
ins are attached to the prototype of that constructor. For simple
plug-ins, that's fine. But widgets might need additional behavior,
and the technique adopted for this is to pass a string as the first
argument to the plug-in function to list the method you want to
call.

var picker = $(selector).datepicker(opts);
// ...
picker.datepicker("disable");
// ...
var date = $(selector).datepicker("getDate");

I'm simply not fond of that style API and was wondering if there was a
way to make the API more like:

var picker = $(selector).datepicker(opts);
// or var picker = $(selector).datepicker.create(opts);
// ...
picker.datepicker.disable();
// ...
var date = $(selector).datepicker.getDate();

That was the initial motivation. Even if I found a positive answer,
I'm not sure what I'd do with it. I'm mostly just curious if it's
possible.

-- Scott
 
A

Antony Scriven

[... on wanting to add a namespace to the prototype of an
object, such that anObject.namespace.aMethod() sets
the this value of doMethods's execution context to
anObject, and not namespace ... ]
I don't see how you might get a reference to your new object
before you've executed the constructor.

That's not a problem for methods: [...]

Sorry, I wasn't clear, I meant I didn't see how you might
get a reference to your new MyWidget object from within
MyWidget.prototype.namespace before you've executed the
constructor, which is exactly what you went on to describe.
Do you have a pressing need for the kind of namespaces that
you describe? [...]

There is no pressing need.  It grows out of
a dissatisfaction with the way JQuery UI plug-ins are
written. [...] But widgets might need additional
behavior, and the technique adopted for this is to pass
a string as the first argument to the plug-in function to
list the method you want to call.

    var picker = $(selector).datepicker(opts);
    // ...
    picker.datepicker("disable");
    // ...
    var date = $(selector).datepicker("getDate");


I'm simply not fond of that style API and was wondering if there was a
way to make the API more like:

    var picker = $(selector).datepicker(opts);
    // or var picker = $(selector).datepicker.create(opts);
    // ...
    picker.datepicker.disable();
    // ...
    var date = $(selector).datepicker.getDate();

That was the initial motivation.  Even if I found
a positive answer, I'm not sure what I'd do with it.  I'm
mostly just curious if it's possible.

I agree, the first code snippet looks somewhat ugly to me.
It also looks more complicated than I feel it needs to be.
Do JQuery's authors have no choice given the model they've
settled on?

But your second example looks odd to me too. Why isn't that
written as the following?

var picker = $(selector).datepicker(opts);
  picker.disable();
  var date = picker.getDate();

--Antony
 
S

Scott Sauyet

Antony said:
Scott said:
[W]idgets might need additional
behavior, and the technique adopted for this is to pass
a string as the first argument to the plug-in function to
list the method you want to call.

    var picker = $(selector).datepicker(opts);
    // ...
    picker.datepicker("disable");
    // ...
    var date = $(selector).datepicker("getDate");


I'm simply not fond of that style API and was wondering if there
was a way to make the API more like:

    var picker = $(selector).datepicker(opts);
    // or var picker = $(selector).datepicker.create(opts);
    // ...
    picker.datepicker.disable();
    // ...
    var date = $(selector).datepicker.getDate();

That was the initial motivation.  Even if I found
a positive answer, I'm not sure what I'd do with it.  I'm
mostly just curious if it's possible.

I agree, the first code snippet looks somewhat ugly to me.
It also looks more complicated than I feel it needs to be.
Do JQuery's authors have no choice given the model they've
settled on?

Well, that's what I'm trying to determine. But yes, there is one more
major constraint that I forgot to mention. JQuery places heavy
emphasis on method chaining. Unless there is some compelling reason
not to do so, plug-in methods return the JQuery wrapper object. Thus
they can be used like this:

$
("input.date").highlight("yellow").datepicker().hide().fadeIn("slow");

The simple datepicker() method returns the JQuery wrapper object for
the elements matching the selector "input.date", just as do the
highlight, hide, and fadeIn methods; the getDate method of course
would not. In the existing architecture, there might be at some other
point in the code

$("#end_date").disable().datepicker("disable");

which would disable the element with the id "end_date" and then
disable the datepicker attached to it.

But your second example looks odd to me too. Why isn't that
written as the following?

    var picker = $(selector).datepicker(opts);
    picker.disable();
    var date = picker.getDate();

I think the above also explains the reason that wouldn't work. I
would expect the methods in the namespace to whenever possible return
the JQuery wrapper object. But the first line above would definitely
return a JQuery wrapper.

-- Scott
 
A

Antony Scriven

Antony said:
Scott Sauyet wrote:

[...]  But yes, there is one more major constraint that
I forgot to mention.  JQuery places heavy emphasis on
method chaining.  Unless there is some compelling reason
not to do so, plug-in methods return the JQuery wrapper
object.  Thus they can be used like this:

    $("input.date").highlight("yellow")
.datepicker().hide().fadeIn("slow");

The simple datepicker() method returns the JQuery wrapper
object for the elements matching the selector
"input.date", just as do the highlight, hide, and fadeIn
methods; the getDate method of course would not.

Huh? Then you might as well write

$("input.date").highlight("yellow").hide().fadeIn("slow");
In the existing architecture, there might be at some
other point in the code

    $("#end_date").disable().datepicker("disable");

which would disable the element with the id "end_date"
and then disable the datepicker attached to it.

What's the difference? Why not 'enddate.disable();'?
I think the above also explains the reason that wouldn't
work.  I would expect the methods in the namespace to
whenever possible return the JQuery wrapper object.  But
the first line above would definitely return a JQuery
wrapper.

So? You don't need a dollar to do method chaining. As long
as your datepicker object augments the JQuery wrapper
I don't see a problem. Admittedly my knowledge of JQuery is
limited so I'm quite open to correction on this point. --Antony
 
S

Scott Sauyet

Antony said:
Huh? Then you might as well write

    $("input.date").highlight("yellow").hide().fadeIn("slow");

Well, I didn't mention what it did before it returns the wrapper
object! :) Datepicker() attaches a click handler to a text field.
On click, it pops up a DIV holding a calendar control. When you
choose a date on the calendar, the text field is populated and the div
disappears.
 > In the existing architecture, there might be at some
 > other point in the code
 >
 >     $("#end_date").disable().datepicker("disable");
 >
 > which would disable the element with the id "end_date"
 > and then disable the datepicker attached to it.

What's the difference? Why not 'enddate.disable();'?

Unhooking the event listener is the main thing, I guess.
So? You don't need a dollar to do method chaining. As long
as your datepicker object augments the JQuery wrapper
I don't see a problem. Admittedly my knowledge of JQuery is
limited so I'm quite open to correction on this point. --Antony

The problem is that other plug-ins might also want to expose a
getDate() method, having nothing to do with datepicker's version.
That's what all this namespacing is about. We want datepicker to be
able to somehow expose a getDate method, but it shouldn't add more
than the "datepicker" property to the wrapper object.

I'm sorry, this is taking more iterations than I expected. Obviously
I didn't explain the idea very well up front.

-- Scott
 
G

Garrett Smith

Scott said:
Perhaps not. I may not have made it clear at the outset that this is
more an academic exercise, not a practical need. I'll discuss at the
bottom a little more of the motivation.


That's not a problem for methods:

var MyWidget = function() { /* ... */ }
MyWidget.prototype.method3 = function() {
// "this" refers to the widget that was constructed.
}

I was wondering if there was some way to gain this behavior with a
namespace object. I couldn't come up with one, and thought it quite
likely there wasn't one, but I thought I'd see if anyone had a
suggestion.

I would probably create a separate object so that it is clear what is
what. Depending on the circumstance, that might be done as:-

function MyWidget(){}
function MyAnother(){}
function AnotherWidget(){}

AnotherWidget.prototype mixin(AnotherWidget.prototype,
MyWidget.prototype);

I migut use another approach. What the program wants do do dictates the
abstractions and how they relate.

There is no pressing need. It grows out of a dissatisfaction with the
way JQuery UI plug-ins are written. They may have the best, or even
the only, realistic solution. But I've never liked it. JQuery's '$'
function is a constructor that creates an object wrapping a number of
DOM elements. (This is an oversimplification, but never mind.) Plug-

The actual constructor is jQuery.prototype.init.
ins are attached to the prototype of that constructor. For simple
plug-ins, that's fine. But widgets might need additional behavior,
and the technique adopted for this is to pass a string as the first
argument to the plug-in function to list the method you want to
call.

var picker = $(selector).datepicker(opts);
// ...
picker.datepicker("disable");
// ...
var date = $(selector).datepicker("getDate");


what do you want the code to look like?

$(sel).getDatepicker().slideFade();
Datepicker.fromSelector(sel).slideFade();
Datepicker.fromElement(sel).slideFade();
Datepicker.getById(id).slideFade();

?

A selector seems a bit off, there. The Datepicker is probably going to
be about just one Datepicker. not a collection of Datepicker instances.
Imagine having a page that has a bunch of Datepickers and wanting to
show them all at the same time -- that's unrealistic.

So I would go with either ID or Element. I would promote the Datepicker
as being the principle thing to be acted upon; not the Element. Based on
that, my API design looks like:

var aDp = Datepicker.getById(id);

If you want to namespace that, you can, say:-

thethickness.Datepicker.getById("ohb");

But I am probably missing something else that you wanted out of it.
 
A

Andrea Giammarchi

== can cause type coercion even if it doesn't in all cases.
And type coercion to boolean wouldn't change the the
semantics of null == undefined. I think you are dwelling too much
on the wording here. It might be worth noting that searching
for the word 'coercion' in the standard brings back Number(null)
matches (and not Number(undefined) matches).

undefined >> 0 is 0 tho
parseFloat(null) and parseInt(null) is NaN

what's the point?

Numbers are a different matter and if you don't expect a default, e.g.
Number(myvar || 0) it must return NaN if myvar is undefined since
there is something wrong around that operation or its logic, unless we
did not mean it and checked via isNaN()

Yes but these are different things. One possible problem
could be thinking that a variable holds the value null when
really you forgot to initialise it.

As I have already said, I consider a bad design to mixin two different
states such null and undefined.

Of course there are cases and cases, e.g. JSON.stringify, but again,
if I rely or need that property and I want to check if it has been
defined or not, where undefined for me means == null since null to me
as a state is considered "unassigned" as undefined is, I simply do ==
null

(x === null || typeof x === "undefined")
(x == null)

which one is shorter, faster, maintaining exactly the same meaning?
How many times you repeat that redundant first line check to perform
just x == null ?
But they do have different meanings. There is a problem of
intent here. If I'm reading your code and I see
'if(x==null)', then I don't know if you really did mean
'if(x === null || typeof x == "undefined")' or if you made
a mistake. It might be more convenient for you to write, but
not for anyone who has to read it.

Dude, you don't have to convince me undefined !== from null, you
should consider how useful is an undefined variable/property compared
with a null variable/property.
Moreover, you could decide to have default "not assigned yet"
properties in an instance

Point.prototype.x = null;
Point.prototype.y = null;

now, how convenient is above declaration? Totally useless, if p.x ==
null I know its x property has not been set. Do I need to know
anything else?
is it about "for in"s ?

p.z = p.z; and "for in" with undefined z is there ... does it change
anything for my application? I don't think so!

null is a special case that should be better described/understood and
I don't think a flag able to tell JSLint "ignore ==null" is such
problematic issue since cases where we need === null are 99% of the
time followed by || x === undefined, which IS an issue, or || typeof x
=== "undefined", which is just boring if all we wanna know is if it is
null OR undefined.

Regards
 
A

Antony Scriven

[...]

null is a special case that should be better
described/understood and I don't think a flag able to
tell JSLint "ignore ==null" is such problematic issue
since cases where we need === null are 99% of the time
followed by || x === undefined, which IS an issue, or ||
typeof x === "undefined", which is just boring if all we
wanna know is if it is null OR undefined.

If you're checking for '=== null' 99% of the time, then
write '=== null' 99% of the time. What is boring is
debugging code whose intent has not been made clear by the
author. --Antony
 
A

Antony Scriven

[on JQuery plugin architecture]

The problem is that other plug-ins might also want to
expose a getDate() method, having nothing to do with
datepicker's version. That's what all this namespacing is
about.  We want datepicker to be able to somehow expose
a getDate method, but it shouldn't add more than the
"datepicker" property to the wrapper object.

If datepicker() decorates the wrapper object it returns with
extra methods then I don't think namespacing would be an
issue.
I'm sorry, this is taking more iterations than
I expected.  Obviously I didn't explain the idea very
well up front.

I think you're explaining your point well; iterations are to
be expected. But I think this discussion probably warrants
a separate thread if it is to be continued much further.
--Antony
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,821
Latest member
AleidaSchi

Latest Threads

Top