Asen said:
They often use the word "magic". That is marketing strategy. There is
many books which explain jQuery or better to say, those books are for
jQuery propaganda. If you open jquery.com you can see a bold
sentence:
| jQuery is designed to change the way that you write JavaScript.
If I am looking for framework for specific application and I see that
sentence I will hit the close button and gone away. If someone want to
change the language, he is free to implement own language. If they try
to change my style of programming that mean more time for development
of my project. And of course that changes do not guarantee nothing.
They not guarantee real improvements and unfortunately they are not
provide any improvements. They only provide excuses for unreasonable
development. Does anybody explain the meaning of:
jQuery.isPlainObject
What should mean "plain object"?
No fairy dust?
In theirs documentation is written:
| Description: Check to see if an object is a plain object
| (created using "{}" or "new Object").
That is just native object for which next object in prototype chain is
The description taken literally does not state anything about the
prototype chain. The code comment does, mention that.
object referred by Object.prototype. Why they need to recognize
prototype chain of native objects, especially in this way? What non-
generic can do it on Object instance to need recognize?
Could someone explain these question.
Good question. I probably can't full answer that without spending well
over an hour on it. Most jQuery methods are long and complicated.
The first occurrence of `jQuery.isPlainObject` occurs in the constructor
for jQuery, `init`, which is defined in the prototype of the jQuery
function (still there, oddly).
Take a look at that `jQuery.prototype.init` and just count the number of
loops and `if` and `else` statements.
| init: function( selector, context ) {
| var match, elem, ret, doc;
|
| // Handle $(""), $(null), or $(undefined)
| if ( !selector ) {
| return this;
| }
|
| // Handle $(DOMElement)
| if ( selector.nodeType ) {
| this.context = this[0] = selector;
| this.length = 1;
| return this;
| }
|
| // The body element only exists once, optimize finding it
| if ( selector === "body" && !context ) {
| this.context = document;
| this[0] = document.body;
| this.selector = "body";
| this.length = 1;
| return this;
| }
|
| // Handle HTML strings
| if ( typeof selector === "string" ) {
| // Are we dealing with HTML string or an ID?
| match = quickExpr.exec( selector );
|
| // Verify a match, and that no context was specified for #id
| if ( match && (match[1] || !context) ) {
|
| // HANDLE: $(html) -> $(array)
| if ( match[1] ) {
| doc = (context ? context.ownerDocument || context :
| document);
|
| // If a single string is passed in and it's a single tag
| // just do a createElement and skip the rest
| ret = rsingleTag.exec( selector );
|
| if ( ret ) {
| if ( jQuery.isPlainObject( context ) ) {
| selector = [ document.createElement( ret[1] ) ];
| jQuery.fn.attr.call( selector, context, true );
|
| } else {
| selector = [ doc.createElement( ret[1] ) ];
| }
|
| } else {
| ret = buildFragment( [ match[1] ], [ doc ] );
| selector = (ret.cacheable ? ret.fragment.cloneNode(true) :
| ret.fragment).childNodes;
| }
|
| return jQuery.merge( this, selector );
|
| // HANDLE: $("#id")
| } else {
| elem = document.getElementById( match[2] );
|
| if ( elem ) {
| // Handle the case where IE and Opera return items
| // by name instead of ID
| if ( elem.id !== match[2] ) {
| return rootjQuery.find( selector );
| }|
|
| // Otherwise, we inject the element directly into the jQuery object
| this.length = 1;
| this[0] = elem;
| }
|
| this.context = document;
| this.selector = selector;
| return this;
| }
|
| // HANDLE: $("TAG")
| } else if ( !context && /^\w+$/.test( selector ) ) {
| this.selector = selector;
| this.context = document;
| selector = document.getElementsByTagName( selector );
| return jQuery.merge( this, selector );
|
| // HANDLE: $(expr, $(...))
| } else if ( !context || context.jquery ) {
| return (context || rootjQuery).find( selector );
|
| // HANDLE: $(expr, context)
| // (which is just equivalent to: $(context).find(expr)
| } else {
| return jQuery( context ).find( selector );
| }
|
| // HANDLE: $(function)
| // Shortcut for document ready
| } else if ( jQuery.isFunction( selector ) ) {
| return rootjQuery.ready( selector );
| }
|
| if (selector.selector !== undefined) {
| this.selector = selector.selector;
| this.context = selector.context;
| }
|
| return jQuery.makeArray( selector, this );
| },
for............0
if............14
else...........7
No for loops in that method, but a combined total of 21 if and else
statements over 104 SLOC. That method, which is complicated in and of
itself, calls several other methods that are also complicated.
Trying to figure the whole mess out requires a map. Of course, the code
does not have to be written that way at all.
The method's contract is part of a public interface and so that,
unfortunately, cannot be easily changed.
The method could, however, be refactored to dispatch the functionality
to different hidden functions, as in:
if ( selector.nodeType ) {
handleDomElement( selector );
}
- which would help shorten the method up and make it easier to read, but
it would not alleviate the inherent complexity in the design of that
methods signature so it would still take a good long look to figure out
all that it is doing and why.
Complexity makes changes and refactoring less safe. Sometimes it can be
avoided. Dynamic overloading is a design decision that adds complexity.
In addition to adding complexity, dynamic overloading requires various
amounts of complicated and often nonstandard checks, particularly around
host objects.
So it's not magic. It is needlessly complex API design that has all the
consequences that can be expected that.