Home  >  Article  >  Web Front-end  >  Detailed explanation of programming paradigms in jQuery_jquery

Detailed explanation of programming paradigms in jQuery_jquery

WBOY
WBOYOriginal
2016-05-16 16:27:011463browse

This article analyzes the programming paradigm in jQuery in detail. Share it with everyone for your reference. The details are as follows:

The face of browser front-end programming has undergone profound changes since 2005. This does not simply mean that a large number of basic libraries with rich functions have emerged, allowing us to write business code more conveniently. More importantly, There has been a major change in the way we look at front-end technology, with a clear awareness of how to unleash programmer productivity in a front-end-specific way. Here, we will give a brief introduction to the programming paradigms and common techniques emerging in JavaScript based on the implementation principles of jQuery source code.

1. AJAX: state persistence, asynchronous update

First, a little history.

A. In 1995, Brendan Eich of Netscape developed the JavaScript language, which is a dynamic, weakly typed, prototype-based scripting language.
B. In 1999, Microsoft IE5 was released, which included the XMLHTTP ActiveX control.
C. Microsoft IE6 was released in 2001, partially supporting DOM level 1 and CSS 2 standards.
D. Douglas Crockford invented the JSON format in 2002.

At this point, it can be said that the technical elements on which Web 2.0 relies have basically taken shape, but it has not immediately had a significant impact on the entire industry. Although some "asynchronous partial page refresh" techniques are secretly circulated among programmers, and even spawned huge and bloated class libraries like bindows, in general, the front end is regarded as a barren and dirty swamp, with only Backend technology is king. What is missing?

When we look back at the js code before 2005 from today's perspective, including those written by the talented people at that time, we can clearly feel their weakness in program control. It’s not that the js technology before 2005 had problems in itself, it’s just that they were scattered at the conceptual level, lacking a unified concept, or lacking their own unique style and soul. At that time, most people and most technologies were trying to simulate traditional object-oriented languages ​​and use traditional object-oriented technologies to implement imitations of traditional GUI models.

2005 was a year of change and a year of concept creation. With the release of a series of refreshing interactive applications by Google, an article "Ajax: A New Approach to Web Applications" by Jesse James Garrett has been widely circulated. Ajax, a front-end-specific concept, quickly unified many scattered practices under the same slogan, triggering a paradigm shift in Web programming. As the saying goes, if the name is not correct, the words will not be correct. Now the unknown masses can find an organization. Before Ajax, people had long recognized that the essential feature of the B/S architecture was that the state spaces of the browser and the server were separated. However, the general solution was to hide this distinction and synchronize the foreground state to the background. Unified logical processing, such as ASP.NET. Because of the lack of mature design patterns to support foreground state persistence, the loaded js object will be forced to be discarded when changing pages. In this way, who can expect it to complete any complicated work?

Ajax clearly states that the interface is partially refreshed and the state resides in the foreground, which promotes a need: js objects need to exist in the foreground for a longer time. This also means the need to effectively manage these objects and functions, which means more complex code organization technology, which means the desire for modularity and a common code base.

There are actually very few parts of jQuery’s existing code that are actually related to Ajax (using XMLHTTP controls to asynchronously access background return data), but without Ajax, jQuery would have no reason to exist as a public code base.

2. Modularization: managing namespaces

When a large amount of code is generated, the most basic concept we need is modularization, which is to decompose and reuse work. The key to decomposing work is that the results of each person's independent work can be integrated together. This means that each module must be based on a consistent underlying concept and can interact. That is to say, it should be based on a common code base, shield the inconsistency of the underlying browser, and implement a unified abstraction layer, such as a unified event management mechanism. More important than a unified code base, there must be no name conflicts between modules. Otherwise, the two modules will not work together even without any interaction between them.

One of the main selling points that jQuery currently promotes is its good control over namespaces. This is even more important than providing more and more complete function points. Good modularity allows us to reuse code from any source, and everyone's work can be accumulated and superimposed. And function implementation is just a matter of temporary workload. jQuery uses a variant of the module pattern to reduce the impact on the global namespace, only adding a jQuery object (that is, $function) to the window object.

The so-called module pattern code is as follows. The key is to use anonymous functions to limit the scope of temporary variables.

Copy code The code is as follows:
var feature =(function() {

//Private variables and functions
var privateThing = 'secret',
PublicThing = 'not secret',

changePrivateThing = function() {
        privateThing = 'super secret';
},

sayPrivateThing = function() {
console.log(privateThing);
         changePrivateThing();
};

// Return to the public API
return {
PublicThing : publicThing,
sayPrivateThing : sayPrivateThing
}
})();

JS itself lacks a package structure, but after years of attempts, the industry has gradually unified its understanding of package loading, forming a solution like the RequireJs library that has gained a certain consensus. jQuery can be well integrated with the RequireJS library to achieve more complete module dependency management. http://requirejs.org/docs/jquery.html

Copy code The code is as follows:
require(["jquery", "jquery.my"], function() {
//Execute when both jquery.js and jquery.my.js are successfully loaded
$(function(){
​​​ $('#my').myFunc();
});
});


The module my/shirt is defined through the following function call, which depends on the my/cart and my/inventory modules,
Copy code The code is as follows:
require.def("my/shirt",
["my/cart", "my/inventory"],
Function(cart, inventory) {
// Use module pattern here to return the API exposed by the my/shirt module
         return {
            color: "blue",
size: "large"
                addToCart: function() {
// decrement is the API exposed by my/inventory
Inventory.decrement(this);
                  cart.add(this);
            }
}
}
);

3. Magic$: Object promotion

What did you think of when you first saw the $function? Traditional programming theory always tells us that function naming should be accurate and should clearly express the author's intention. It even claims that long names are better than short names because it reduces the possibility of ambiguity. But what is $? Garbled code? The message it conveys is too obscure and ambiguous. $ was invented by the prototype.js library and is truly a magical function because it can enhance a primitive DOM node into an object with complex behavior. In the original implementation of prototype.js, the $function was defined as

Copy code The code is as follows:
var $ = function (id) {
Return "string" == typeof id ? document.getElementById(id) : id;
};

This basically corresponds to the following formula
e = $(id)

This is not only a clever function name abbreviation, but more importantly, it establishes a one-to-one correspondence between text id and DOM element at a conceptual level. Before there is $, the distance between the id and the corresponding element is very far. Generally, the element needs to be cached in a variable, such as

Copy code The code is as follows:
var ea = docuement.getElementById('a');
var eb = docuement.getElementById('b');
ea.style....

But after using $, you can see the following writing everywhere
Copy code The code is as follows:
$('header_' id).style...
$('body_' id)....

The distance between id and element seems to be eliminated and they can be very closely intertwined.

prototype.js later expanded the meaning of $,

Copy code The code is as follows:
function $() {
var elements = new Array();
 
for (var i = 0; i < arguments.length; i ) {
        var element = arguments[i];
If (typeof element == 'string')
            element = document.getElementById(element);
 
            if (arguments.length == 1)
           return element;
 
        elements.push(element);
}
 
Return elements;
}

This corresponds to the formula:
[e,e] = $(id,id)

Unfortunately, prototype.js went astray in this step, and this approach has little practical value.
It is jQuery that really promotes $, and its $ corresponds to the formula
[o] = $(selector)
Here are three enhancements:
A. The selector is no longer a single node locator, but a complex collection selector
B. The returned elements are not original DOM nodes, but objects with rich behaviors further enhanced by jQuery, which can start complex function call chains.
C. The packaging object returned by $ is shaped into an array form, which naturally integrates collection operations into the call chain.

Of course, the above is just an oversimplified description of the magical $, and its actual function is much more complicated. In particular, there is a very commonly used direct construction function.

Copy code The code is as follows:
$("
")....

jQuery will directly construct a series of DOM nodes based on the incoming html text and package them as jQuery objects. This can be seen as an extension of the selector to a certain extent: the html content description itself is a Unique designation.

$(function{}) This function is really a bit speechless. It means that this callback function is called when document.ready. Really, $ is a magical function. If you have any questions, please ask.

To sum up, $ is the transition channel from the ordinary DOM and text description world to the jQuery world with rich object behavior. After crossing this door, we arrived at the Utopia.

4. Amorphous parameters: focus on expression rather than constraints

Since weakly typed languages ​​have the word "weak" on their heads, it is inevitable that people will feel a little innately deficient. Is the lack of type constraints in the program really a major shortcoming? In traditional strongly typed languages , the type and number of function parameters are all constraints checked by the compiler, but these constraints are still far from enough. In general applications, in order to strengthen constraints, a large amount of defensive code is always added, such as in C We commonly use ASSERT, and in java we often need to determine the range of parameter values ​​

Copy code The code is as follows:
if (index < 0 || index >= size)
           throw new IndexOutOfBoundsException(
"Index: " index ", Size: " size);

Obviously, these codes will lead to a large number of non-functional execution paths in the program, that is, we have made a lot of judgments, and when the code is executed to a certain point, the system throws an exception, shouting that this path is blocked. If we change our thinking, since we have After making certain judgments, can we use the results of these judgments to do something? JavaScript is a weakly typed language. It cannot automatically constrain parameter types. If we follow the trend and further weaken the shape of parameters, it will "Weakness" has been pushed to an extreme. When there is nothing weak to do, will weak become an iconic feature?

Look at the event binding function bind in jQuery,
A. Bind one event at a time

Copy code The code is as follows:
$("#my").bind(" mouseover", function(){});

B. Bind multiple events at one time
Copy code The code is as follows:
$("#my").bind( "mouseover mouseout",function(){})

C. Change the form and bind multiple events
Copy code The code is as follows:
$("#my").bind({mouseover:function(){} , mouseout:function(){});

D. Want to pass some parameters to the event listener
Copy code The code is as follows:
$('#my').bind('click', {foo: " xxxx"}, function(event) { event.data.foo..})

E. Want to group event listeners
Copy code The code is as follows:
$("#my").bind("click.myGroup", function( ){});

F. Why hasn’t this function gone crazy???

Even if the type is uncertain, the meaning of the parameters at fixed positions must be certain, right? Taking a step back, even if the parameter position is not important, the meaning of the function itself should be certain, right? But what is this?

Value value = o.val(), set value o.val(3)
       
How can a function be so excessive, how can it behave differently depending on the type and number of parameters passed in? Isn’t it displeasing to the eye? But this is our value. Since it cannot be prevented, then it is allowed deliberately. Although there are many forms Change, but not a word of nonsense. The lack of restraint does not hinder expression (I am not here to scare people).

5. Chain operation: gradual refinement of linearization

The main selling point of jQuery in the early days was the so-called chain operation.

Copy code The code is as follows:
$('#content') // Find the content element
.find('h3') // Select all descendant h3 nodes
.eq(2) // Filter the collection and keep the third element
​​​​.html('Change the text of the third h3')
.end() // Return to the previous h3 collection
.eq(0)
​​​​.html('Change the text of the first h3');

In general imperative languages, we always need to filter data in nested loops, and the code to actually operate the data is entangled with the code to locate the data. However, jQuery uses the method of constructing a collection first and then applying functions to the collection. This method achieves the decoupling of the two logics and the linearization of the nested structure. In fact, we can intuitively understand a collection without resorting to procedural thinking, such as $('div.my input:checked') Can be seen as a direct description rather than a tracking of process behavior.

Loop means that our thinking is in a state of repeated rewinding, and after linearization, it goes straight in one direction, which greatly reduces the thinking burden and improves the composability of the code. In order to reduce the interruption of the call chain , jQuery invented a wonderful idea: jQuery wraps the object itself like an array (collection). Collections can be mapped to new collections, and collections can be restricted to their own subcollections. The initiator of the call is a collection, and the returned result is also a collection. Collections can Some structural changes have occurred, but it is still a set. A set is a conceptual fixed point. This is a design idea absorbed from functional languages. Collection operations are too common operations. In Java, we can easily find that a large number of so-called encapsulation functions actually encapsulate some collection traversal operations. In jQuery, collection operations are too straightforward and do not need to be encapsulated.

Chained calls mean that we always have a "current" object, and all operations are performed on this current object. This corresponds to the following formula
x = dx
Each step in the call chain is an incremental description of the current object and a step-by-step refinement process toward the final goal. This idea is also widely used in the Witrix platform. Especially in order to realize the integration of platform mechanism and business code, the platform will provide the default content of the object (container), and the business code can be gradually refined and revised on this basis, including canceling the default settings.

Having said that, although jQuery’s chain call is very simple on the surface, you have to write an extra layer of loops when implementing it internally, because the compiler does not know about "automatically applying to each element in the collection".

Copy code The code is as follows:
$.fn['someFunc'] = function(){
Return this.each(function(){
​​ jQuery.someFunc(this,...);
}
}


6. data: unified data management

As a js library, a big problem it must solve is the state association and collaborative management between js objects and DOM nodes. Some js libraries choose to focus on js objects, and save DOM node pointers in member variables of js objects. When accessing, they always use js objects as the entry point, and indirectly operate DOM objects through js functions. Under this kind of encapsulation, the DOM node is actually just a low-level "assembly" displayed as an interface. The choice of jQuery is similar to the Witrix platform, which is based on the structure of HTML itself. It enhances the function of the DOM node through js and promotes it to an extended object with complex behavior. The idea here is non-intrusive design (non-intrusive) and graceful degradation mechanism (graceful degradation). The semantic structure is complete at the basic HTML level. The role of js is to enhance interactive behavior and control the presentation form.

If we access the corresponding packaging object through $('#my') every time, where are some state variables that need to be maintained for a long time stored? jQuery provides a unified global data management mechanism.

Get data:

Copy code The code is as follows:
$('#my').data('myAttr ')

Set data:
Copy code The code is as follows:
$('#my').data('myAttr',3 );

This mechanism naturally integrates the processing of HTML5 data attributes
Copy code The code is as follows:

The data set in HTML can be read through $('#my').data('myAttr').

When accessing data for the first time, jQuery will assign a unique uuid to the DOM node, and then set it on a specific expando attribute of the DOM node. jQuery ensures that this uuid is not repeated in this page.

Copy code The code is as follows:
elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];

The above code can handle both DOM nodes and pure js objects. If it is a js object, the data is placed directly in the js object itself, and if it is a DOM node, it is managed uniformly through the cache.

Because all data is managed uniformly through the data mechanism, especially all event listening functions (data.events), jQuery can safely implement resource management. When cloning a node, its related event listening functions can be automatically cloned. When the content of the DOM node is replaced or the DOM node is destroyed, jQuery can also automatically cancel the event listening function and safely release the relevant js data.

7. event: unified event model

The picture of "events propagating along the object tree" is the essence of the object-oriented interface programming model. The composition of objects constitutes a stable description of the interface structure. Events continuously occur at a certain node of the object tree and propagate upward through the bubbling mechanism. The object tree naturally becomes a control structure. We can listen to events on all child nodes on the parent node without explicitly establishing an association with each child node.

In addition to establishing a unified abstraction for the event models of different browsers, jQuery has mainly made the following enhancements:
A. Added a custom event (custom) mechanism. The event propagation mechanism has nothing to do with the event content itself in principle, so custom events can pass through the same processing path and use the same monitoring method as the browser's built-in events. Use Custom events can enhance the cohesion of code and reduce code coupling. For example, if there are no custom events, associated code often needs to directly operate related objects

Copy code The code is as follows:
$('.switch, .clapper').click(function() {
var $light = $(this).parent().find('.lightbulb');
If ($light.hasClass('on')) {
          $light.removeClass('on').addClass('off');
} else {
          $light.removeClass('off').addClass('on');
}
});

If you use custom events, the semantics expressed are more restrained and clear,
Copy code The code is as follows:
$('.switch, .clapper').click(function() {
$(this).parent().find('.lightbulb').trigger('changeState');
});

B. Added event monitoring for dynamically created nodes. The bind function can only register listening functions to existing DOM nodes. For example
Copy code The code is as follows:
$('li.trigger').bind('click',function() {}}

If another li node is created after calling bind, the click event of this node will not be monitored.

jQuery’s delegate mechanism can register the listening function to the parent node, and the events triggered on the child node will be automatically dispatched to the corresponding handlerFn according to the selector. In this way, if you register now, you can listen to the nodes created in the future.

Copy code The code is as follows:
$('#myList').delegate('li.trigger', 'click ', handlerFn);

Recently, jQuery 1.7 has unified the bind, live and delegate mechanisms, and the world is unified, only on/off.

Copy code The code is as follows:
$('li.trigger').on('click', handlerFn); // Equivalent to bind
$('#myList').on('click', 'li.trigger', handlerFn); // Equivalent to delegate

 
8. Animation Queue: Global Clock Coordination

Putting aside the implementation of jQuery, first consider what we need to do if we want to achieve animation effects on the interface? For example, we want to increase the width of a div from 100px to 200px within 1 second. It is easy to imagine that over a period of time we need to adjust the width of the div from time to time, [and at the same time] we also need to execute other code. Unlike ordinary function calls, after issuing the animation command, we cannot expect to get what we want immediately The result, and we can't just wait for the result to arrive. The complexity of animation lies in that it must be executed within a period of time after a one-time expression, and there are multiple logical execution paths that need to be unfolded at the same time. How to coordinate?

The great Sir Isaac Newton wrote in "Mathematical Principles of Natural Philosophy": "Absolute, true and mathematical time itself passes". All events can be aligned on the timeline, which It's their inherent coordination. So in order to execute steps A1 to A5 and step B1 to B5 at the same time, we only need to execute [A1, B1] at time t1, [A2, B2] at time t2, and so on. .
t1 | t2 | t3 | t4 | t5 ...
A1 | A2 | A3 | A4 | A5 ...
B1 | B2 | B3 | B4 | B5 ...

A specific implementation form can be
A. For each animation, divide it into an Animation object, which is divided into multiple steps internally.
animation = new Animation(div,"width",100,200,1000,
The interpolation function responsible for step segmentation and the callback function when the animation is completed); B. Register the animation object in the global manager
timerFuncs.add(animation);
C. At each triggering moment of the global clock, advance each registered execution sequence one step further, and if it has ended, delete it from the global manager.

Copy code The code is as follows:
for each animation in timerFuncs
          if(!animation.doOneStep())
           timerFuncs.remove(animation)

Having solved the principle problem, let’s look at the expression problem. How to design interface functions to express our intentions in the most compact form? Practical problems we often need to face:

A. There are multiple elements to perform similar animations

B. Each element has multiple attributes that need to change at the same time
C. After executing one animation, start another animation
jQuery’s answers to these questions can be said to squeeze out the last remaining value of js’s grammatical expression.

Copy code The code is as follows:
$('input')
.animate({left:' =200px',top:'300'},2000)
.animate({left:'-=200px',top:20},1000)
.queue(function(){
//Here dequeue will first execute the last function in the queue, so alert("y")
         $(this).dequeue();
alert('x');
})
.queue(function(){
alert("y");
// If you do not actively dequeue, the queue execution will be interrupted and will not continue automatically.
           $(this).dequeue();
});

A. Use jQuery’s built-in selector mechanism to naturally express the processing of a collection.
B. Use Map to express multiple attribute changes
C. Use microformats to express domain-specific delta concepts. ' =200px' means adding 200px to the existing value
D. Use the order of function calls to automatically define the order of animation execution: animations appended to the execution queue will naturally wait until the previous animation is completely executed before starting.

The implementation details of jQuery animation queue are roughly as follows,

A. The animate function actually calls queue(function(){dequeue needs to be called at the end of execution, otherwise the next method will not be driven})
When the queue function is executed, if it is an fx queue and no animation is currently running (if animate is called twice in a row, the second execution function will wait in the queue), the dequeue operation will be automatically triggered to drive the queue to run.
If it is an fx queue, the "inprogress" string will be automatically added to the top of the queue when dequeueing, indicating that animation is about to be executed.
B. For each property, create a jQuery.fx object. Then call the fx.custom function (equivalent to start) to start the animation.
C. In the custom function, register the fx.step function to the global timerFuncs, and then try to start a global timer.
timerId = setInterval( fx.tick, fx.interval );
D. The static tick function will call the step function of each fx in sequence. In the step function, the current value of the attribute is calculated through easing, and then the update of fx is called to update the attribute.
E. The step function of fx determines that if all attribute changes have been completed, dequeue is called to drive the next method.

What is very interesting is that there are obviously many relay trigger codes in the jQuery implementation code: if you need to execute the next animation, take it out and execute it, if you need to start the timer, start the timer, etc. This is because the js program is single-threaded. There is only one real execution path. In order to ensure that the execution thread is not interrupted, the functions have to help each other. It is conceivable that if there are multiple execution engines inside the program, or even infinite execution engines, then the appearance of the program will change essentially. changes. In this case, recursion will become a more natural description compared to loop.

9. Promise pattern: identification of causal relationships

In reality, there are always so many timelines evolving independently, and people and things intersect in time and space, but no cause and effect occurs. In software, functions are lined up in the source code, and some questions will inevitably arise. Why should the one at the front be executed first? Wouldn't there be me without it? Let the whole universe move forward in unison shouting 1, 2, 3. From God's point of view, management is probably too difficult, so there is the theory of relativity. . If there is no exchange of information and no mutual dependence, then the events that occur sequentially in one coordinate system may appear to be in reverse order when viewed in another coordinate system. The programmer follows the example, and then Invented the promise pattern.

Promise and future patterns are basically the same thing. Let’s first take a look at the familiar future pattern in Java.

Copy code The code is as follows:
futureResult = doSomething();
...
realResult = futureResult.get();

Issuing a function call only means that something has happened, and does not necessarily mean that the caller needs to know the final result of the matter. What the function immediately returns is just a promise (Future type) that will be fulfilled in the future, which is actually Some kind of handle. The handle is passed around, and the code that changes hands in the middle is indifferent to what the actual result is and whether it has been returned. Until a piece of code needs to rely on the result returned by the call, so it opens the future and checks it. If the actual result has been returned , then future.get() returns the actual result immediately, otherwise it will block the current execution path until the result is returned. Calling future.get() after that will always return immediately, because the causal relationship has been established, [result return] This event must have happened before this and will not change again.

The future mode generally means that the external object actively checks the return value of the future, while the promise mode means that the external object registers a callback function on the promise.

Copy code The code is as follows:
function getData(){
Return $.get('/foo/').done(function(){
console.log('Fires after the AJAX request succeeds');
}).fail(function(){
console.log('Fires after the AJAX request fails');
});
}

function showDiv(){
var dfd = $.Deferred();
$('#foo').fadeIn( 1000, dfd.resolve );
Return dfd.promise();
}

$.when( getData(), showDiv() )
.then(function(ajaxResult, ignoreResultFromShowDiv){
console.log('Fires after BOTH showDiv() AND the AJAX request succeed!');
​​​​ // 'ajaxResult' is the server's response
});

jQuery introduces the Deferred structure, reconstructs ajax, queue, document.ready, etc. according to the promise mode, and unifies the asynchronous execution mechanism. then(onDone, onFail) will add a callback function to the promise. If the call is successfully completed ( resolve), the callback function onDone will be executed, and if the call fails (reject), then onFail will be executed. when can wait on multiple promise objects. The clever thing about promise is that after the asynchronous execution has started or even ended, It is still possible to register callback functions

someObj.done(callback).sendRequest() vs. someObj.sendRequest().done(callback)

Registering the callback function before issuing an asynchronous call or registering after issuing an asynchronous call is completely equivalent. This reveals that program expression is never completely accurate, and there is always an inherent dimension of change. If this inherent dimension can be effectively utilized The variability can greatly improve the performance of concurrent programs.

The specific implementation of promise mode is very simple. jQuery._Deferred defines a function queue, which has the following functions:

A. Save the callback function.
B. Execute all saved functions at the time of resolve or reject.
C. After it has been executed, any additional functions will be executed immediately.

Some languages ​​specifically oriented towards distributed computing or parallel computing will have built-in promise mode at the language level, such as E language.

Copy code The code is as follows:
def carPromise := carMaker <- produce("Mercedes");
Def temperaturePromise := carPromise <- getEngineTemperature()
...
When (temperaturePromise) -> done(temperature) {
           println(`The temperature of the car engine is: $temperature`)
} catch e {
          println(`Could not get engine temperature, error: $e`)
}

In E language, <- is the eventually operator, which means it will be executed eventually, but not necessarily now. The ordinary car.moveTo(2,3) means that it will be executed immediately and the result will be obtained. The compiler is responsible for identifying all promise dependencies. And automatically implement scheduling.

10. extend: Inheritance is not necessary

JS is a prototype-based language and does not have a built-in inheritance mechanism. This has always bothered many students who are deeply educated in traditional object-oriented education. But is inheritance necessary? What can it bring us? ? The simplest answer is: code reuse. So, let’s first analyze the potential of inheritance as a means of code reuse.

There used to be a concept called "multiple inheritance", which was the Super Saiyan version of the concept of inheritance. Unfortunately, it was later diagnosed as having a congenital defect, so that an interpretation of the concept of inheritance emerged: inheritance is " is a" relationship, a derived object "is a" has many base classes, which will inevitably lead to schizophrenia, so multiple inheritance is bad.

Copy code The code is as follows:
class A{ public: void f(){ f in A } }
class B{ public: void f(){ f in B } }
class D: public A, B{}

If class D inherits from two base classes A and B, and both classes A and B implement the same function f, then the f in class D is the f in A or the f in B, or is it What about f in A and f in B? The emergence of this dilemma actually stems from the fact that the base classes A and B of D are in a parallel relationship. They satisfy the commutative law and the associative law. After all, at the conceptual level, it may be difficult for us to recognize two Subordination relationships will appear between any concepts. But if we relax some conceptual level requirements and consider code reuse issues more from the operational level, we can simply think that B operates on the basis of A, then we can get a linear The result of transformation. In other words, giving up the commutative law between A and B and only retaining the associative law, extends A, B and extends B, A will have two different results, and there will no longer be any ambiguity in interpretation. scala The so-called trait mechanism in the language actually adopts this strategy.

Long after the invention of object-oriented technology, the so-called aspect-oriented programming (AOP) appeared. It is different from OOP in that it is a positioning and modification technology in the code structure space. AOP only sees classes and methods, and does not know what meaning is. . AOP also provides a code reuse method similar to multiple inheritance, which is mixin. The object is regarded as a Map that can be opened and modified arbitrarily. A set of member variables and methods are directly injected into the object body and directly changed. its behavior.
The prototype.js library introduces the extend function,

Copy code The code is as follows:
Object.extend = function(destination, source) {
for (var property in source) {
destination[property] = source[property];
}
Return destination;
}

is a covering operation between Maps, but it is very effective and has been extended in the jQuery library. This operation is similar to mixin, which is the main technical means of code reuse in jQuery---it is no big deal if there is no inheritance. of.

11. Name mapping: everything is data

If the code is good, there must be less loop judgments. Loops and judgment statements are the basic components of the program, but they are often not found in excellent code libraries, because the interweaving of these statements will blur the main line of logic of the system. Let our minds get lost in the exhausting code tracing. jQuery itself has greatly reduced the need for loop statements through functions such as each and extend. For judgment statements, it is mainly processed through mapping tables. For example, jQuery's val( ) function needs to perform different processing for different tags, so define a function mapping table with tagName as the key

Copy code The code is as follows:
valHooks: { option: {get:function(){}}}

This way you don’t need to write
everywhere in the program
Copy code The code is as follows:
if(elm.tagName == 'OPTION'){
Return ...;
}else if(elm.tagName == 'TEXTAREA'){
Return ...;
}

Can be processed in a unified manner
Copy code The code is as follows:
(valHooks[elm.tagName.toLowerCase()] || defaultHandler).get( elm);


Mapping tables manage functions as ordinary data and are widely used in dynamic languages. In particular, the object itself is a container for functions and variables and can be regarded as a mapping table. A technique used extensively in jQuery is to use name mapping To dynamically generate code, forming a template-like mechanism. For example, in order to implement two very similar functions myWidth and myHeight, we do not need
Copy code The code is as follows:
jQuery.fn.myWidth = function(){
Return parseInt(this.style.width,10) 10;
}
 
jQuery.fn.myHeight = function(){
Return parseInt(this.style.height,10) 10;
}

Instead, you can choose to dynamically generate
Copy code The code is as follows:
jQuery.each(['Width','Height'],function(name){
jQuery.fn['my' name] = function(){
           return parseInt(this.style[name.toLowerCase()],10) 10;
}
});


12. Plug-in mechanism: Actually I am very simple

The so-called plug-ins of jQuery are actually functions added to $.fn. So what is this fn?

Copy code The code is as follows:
(function(window,undefined){
// There is another package inside
var jQuery = (function() {
var jQuery = function(selector, context) {
                   return new jQuery.fn.init( selector, context, rootjQuery );
}
....
// fn is actually the abbreviation of prototype
jQuery.fn = jQuery.prototype = {
​​​​​constructor: jQuery,
            init: function(selector, context, rootjQuery) {... }
}
 
// Calling jQuery() is equivalent to new init(), and the prototype of init is the prototype of jQuery
​​ jQuery.fn.init.prototype = jQuery.fn;
 
// // The jQuery object returned here only has the most basic functions. The following is a series of extend
Return jQuery;
})();
...
//Expose jQuery as a global object
​ window.jQuery = window.$ = jQuery;
})(window);

Obviously, $.fn is actually the abbreviation of jQuery.prototype.

A stateless plug-in is just a function, very simple.

Copy code The code is as follows:
// Define plugin
(function($){
$.fn.hoverClass = function(c) {
           return this.hover(
                 function() { $(this).toggleClass(c); }
);
};
})(jQuery);

//Use plugin
$('li').hoverClass('hover');


For more complex plug-in development, jQuery UI provides a widget factory mechanism,
Copy code The code is as follows:
$.widget("ui.dialog", {
Options: {
        autoOpen: true,...
},
_create: function(){ ... },
_init: function() {
           if ( this.options.autoOpen ) {
This.open();
}
},
_setOption: function(key, value){ ... }
          destroy: function(){ ... }
});


When calling $('#dlg').dialog(options), the actual code executed is basically as follows:
Copy code The code is as follows:
this.each(function() {
         var instance = $.data( this, "dialog" );
          if ( instance ) {
Instance.option( options || {} )._init();
         } else {
               $.data( this, "dialog", new $.ui.dialog( options, this ) );
}
}

It can be seen that the first time the $('#dlg').dialog() function is called, a window object instance will be created and saved in data. At this time, the _create() and _init() functions will be called, and if If it is not called for the first time, the _init() method is called on an existing object instance. Calling $('#dlg').dialog() multiple times will not create multiple instances.

13. browser sniffer vs. feature detection

Browser sniffer was once a very popular technology, such as in the early days of jQuery

Copy code The code is as follows:
jQuery.browser = {
Version:(userAgent.match(/. (?:rv|it|ra|ie)[/: ]([d.] )/) || [0,'0'])[1],
​​​ safari:/webkit/.test(userAgent),
​​​​opera:/opera/.test(userAgent),
          msie:/msie/.test(userAgent) && !/opera/.test(userAgent),
mozilla:/mozilla/.test(userAgent) && !/(compatible|webkit)/.test(userAgent)
};

In the specific code, different processing can be done for different browsers

Copy code The code is as follows:
if($.browser.msie) {
// do something
} else if($.browser.opera) {
// ...
}

However, as competition in the browser market escalates, competitors imitate and disguise each other, resulting in userAgent chaos. Coupled with the birth of Chrome and the rise of Safari, IE has also begun to accelerate its move towards standards, and sniffers can no longer do it. Positive effect. Feature detection (feature detection), as a more fine-grained and more specific detection method, has gradually become the mainstream way to deal with browser compatibility.

Copy code The code is as follows:
jQuery.support = {
// IE strips leading whitespace when .innerHTML is used
​​​​leadingWhitespace: ( div.firstChild.nodeType === 3 ),
...
}

Only based on what you actually saw, rather than what you once knew, this makes it easier to be compatible with the future.

14. Prototype vs. jQuery

prototype.js is a library with lofty aspirations. Its goal is to provide a new user experience, transform JavaScript from the language level with reference to Ruby, and ultimately really change the face of js greatly. $, extends, each, bind... These familiar concepts are all introduced into the js field by prototype.js. It unscrupulously adds various concepts to the window global namespace. Whoever takes advantage of it first is in the right. Whose momentum? jQuery, on the other hand, is more pragmatic and its goal is just to write less and do more.

However, the fate waiting for radical idealists is often to die before their ambitions are fulfilled. When the iconic bind function of prototype.js was absorbed into the ECMAScript standard, its decline was doomed. Modify native everywhere The prototype of the object is the unique secret skill of prototype.js, and it is also its Achilles heel. Especially when it tries to imitate jQuery and returns enhanced objects through Element.extend(element), it is completely thrown into the ditch by jQuery. Prototype.js is different from jQuery. It always directly modifies the prototype of the native object. However, browsers are a field full of bugs, lies, historical baggage and commercial conspiracies. Solving problems at the native object level is destined to be a tragedy. . Performance issues, name conflicts, compatibility issues, etc. cannot be solved by the ability of a help library. The 2.0 version of Prototype.js is said to be undergoing major changes. I don’t know whether to break with history, give up compatibility, or continue Struggling to survive in the cracks.

I hope this article will be helpful to everyone’s jQuery programming.

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn