More elegant event triggering compatible _ javascript tips-js tutorial

Source: Internet
Author: User
You must be familiar with the client (browser) compatibility problem in JS framework development. Normally, we use if to deal with interface inconsistencies and piles of bugs. However, the methods described here can make compatibility more elegant.

The underlying interface compatibility is nothing more than using if to determine which interface the client supports. The most famous example is the event:

The Code is as follows:


Var addEvent = function (e, what, how ){
If (e. addEventListener) e. addEventListener (what, how, false)
Else if (e. attachEvent) e. attachEvent ('on' + what, how)
}


The standard W3C DOM interface and the interface provided by DHTML are two possible conditions when binding events to elements. Of course, this example is still rough, but it is enough to explain the problem.

The original method was to make an on-site judgment on the compatibility layer call and enter the corresponding if branch. Obviously, this "on-site judgment" method is not very efficient. Later, people adopted the following method:

The Code is as follows:


If (MSIE ){
AddEvent = function (e, what, how ){
E. attachEvent ('on' + what, how );
}
} Else {
AddEvent = function (e, what, how ){
E. addEventListener (what, how );
}
}


After a judgment, bind different codes to addEvent, thus avoiding Branch judgment during runtime.

Unfortunately, this problem is not small. First, binding "using attachEvent" and "client is MSIE" is a very outdated idea. What if Microsoft finds out its conscience? This happens now -- IE9 explicitly supports DOM interfaces and even DOM3. As a result, this "conscience discovery" will destroy many front-end libraries, and they must be forced to modify the code (as when IE8 came ). Moreover, this approach does not consider "unknown clients"-as far as I know, Google has caused many class libraries to rewrite code after Chrome is released.
Feature Detection

So what should we do? Feature Detection can minimize the trouble caused by the "new client"-detect the features of the client through a set of code defined during class library initialization, and use this group of detection values to bind the class library code:

The Code is as follows:


Var supportsAddEventListener = !! (CheckerElement. addEventListener );
If (supportsAddEventListener ){
AddEvent = function (e, what, how ){
E. addEventListener (what, how );
}
} Else if (supportsAttachEvent ){
AddEvent = function (e, what, how ){
E. attachEvent ('on' + what, how );
}
}


Feature Detection decouples "using a client" and "supporting a feature". This allows the if branch to determine whether the feature is consistent, so as to eliminate the "good intentions and bad deeds" caused by the "conscience discovery" of client manufacturers ". In fact, this is also an option that conforms to the historical trend. When the standard interfaces gradually become popular and the clients are gradually "characterized as consistent", why not make a consistent compatible layer interface?
Drop

Let's look at the code again. Generally, a code that uses Feature Detection for compatibility is as follows:

The Code is as follows:


If (new_interface_detected ){
Comp = function () {uses_new_interface };
} Else if (old_interface_detected ){
Comp = function () {uses_old_interface };
} Else {
Throw new Error ('unadaptable! ')
}


In other words, the process is:

If the client supports the new interface, bind the compatibility layer to the new interface.
Otherwise, if the client supports the old interface or inconsistent interface, the compatibility layer will be bound to the old interface.
Otherwise, an error is returned if possible.

That is, the compatibility layer program is "dropped" from a high altitude. If the client supports "advanced" features (new interfaces and standard interfaces) connect it to the compatibility layer; otherwise, continue down -- oh, the old interface is connected, and the old interface is used; if no one is connected, so -- snap -- fell to the ground and shouted in the last breath: "The client you are using is too small, so I can't help you!"

What is this like?

In fact, if you understand the mechanism of the JavaScript Object System, you can make an analogy: this is not a prototype! The prototype system uses this drop to find a member. If it is defined in this object, it returns it; otherwise, it searches up the prototype chain (yes, this time it is up ), repeat this until the prototype chain is connected to the header, an undefined is returned.

Just do it! Here we also use addEvent as an example. First, we define an empty driver, which does not contain anything:

Var nullDriver = {}

Then, create an object and point the prototype chain to it. In The ECMA V5 era, we can use Object. create. Unfortunately, there are still more than N old clients (otherwise, what compatibility should we do), so we can use our own craft functions:

The Code is as follows:


Var derive = Object. create? Object. create: function (){
Var T = function (){};
Return function (obj ){
T. prototype = obj;
Return new T
}
}()


You may think this usage is strange, but it does not work at all, and the speed is not slow-it can reach half of Object. create. We can start with this derive:

The Code is as follows:


Var dhtmlDriver = derive (nullDriver );
Var dhtmlDriverBugfix = derive (dhtmlDriver );


The bugfix here is a special Driver defined for some "bugs" and special circumstances. You can ignore it here. Okay, what is addEvent in DHTML?

The Code is as follows:


If (supportsAttachEvent ){
DhtmlDriver. addEvent = function (e, what, how ){
E. attachEvent ('on' + what, how)
}
}


What then? The front-end of the prototype chain should be the W3C standard driver. Write it!

The Code is as follows:


Var w3cDriver = derive (dhtmlDriverBugfix );
Var w3cDriverBugfix = derive (w3cDriver );

If (supportsAddEventListener ){
W3cDriver. addEvent = function (e, what, how ){
E. addEventListener (what, how)
}
}


Finally, let's put something up for the final called interface. (Because w3cDriverBugfix is too ugly ......)

Var driver = derive (w3cDriverBugfix );

Then, call it. Look, this makes the scary Branch judgment simple and effective, without losing the fallback: Calling addEvent on addEventListener is equivalent to calling w3cDriver. the client that does not support addEventListener will drop to the end, for example, calling dhtmlDriver. addEvent. In addition, it is easy to perform a bugfix-you can hook the bugfix layer, but the original layer is not affected at all.
And so on.

Will it be slow? It is true that the deep prototype chain will be slow, but I have a solution. Do you still remember what will happen when you write an object attribute?

The Code is as follows:


Var ego = function (x) {return x}
For (var each in driver ){
If (! (Each in nullDriver )){
Driver [each] = ego (driver [each])
}
}


That's right. The original method on the prototype chain will "crash" to the bottom! This time, you don't need to search up the prototype chain. You just need to get the attribute from the bottom. The reason for using the ego function here is to prevent some browsers from "optimizing" the code here.
Summary

Although we talk about compatibility here, the essence of it is in terms of language features-using prototype inheritance, we can perform this headache elegantly. Yes, the beauty of the framework should not be on the external side. The interior of the framework, even the most annoying interior, must be elegant.

The technology here can be found in dess.
From: typeof.net
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.