Pure feature detection library, a la carte style.
This document is not complete.
Browser sniffing and feature inference are flawed techniques for detecting browser support in client side JavaScript. The goal of has.js is to provide a collection of self-contained tests and unified framework around using pure feature detection for whatever library consumes it.
You likely won't see has.js as a public API in any library. The idea is that %yourfavoritelibrary% will import some or all the available tests, based on their own needs for providing you a normalized future proof API against common tasks.
not stable, so keep that in mind. This is a young project, and the decided naming conventions may be a moving target. The tests are nothing that haven't been done over and over in various places, so the intention is to come to some agreement on a basic naming convention and API based on real world use cases.
Currently, the testing convention is has('somefeature')
returns Boolean, e.g.:
if(has("function-bind")){
// your enviroment has a native Function.prototype.bind
}else{
// you should get a new browser.
}
In the real world, this may translate into something like:
mylibrary.trim = has("string-trim") ? function(str){
return (str || "").trim();
} : function(str){
/* do the regexp based string trimming you feel like using */
}
By doing this, we can easily defer to browser-native versions of common functions, augment prototypes (which has.js will not do) to supplement the natives, or whatever we choose.
Running has()
is a one-time cost, deferred until needed. After first run, subsequent has()
checks are cached and return immediately.
Each test is self-contained. Register a test with has.add()
:
has.add("some-test-name", function(global, document, anElement){
// global is a reference to global scope, document is the same
// anElement only exists in browser enviroments, and can be used
// as a common element from which to do DOM working.
// ALWAYS CLEAN UP AFTER YOURSELF in a test. No leaks, thanks.
// return a Boolean from here.
return true;
});
You can register and run a test immediately by passing a truthy value after the test function:
has.add("some-other-test", function(){
return false; // Boolean
}, true)
This is preferred over what would seem a much more effective version:
// this is not wrapped in a function, and should be:
has.add("some-other-test", ("foo" in bar)); // or whatever
By forcing a function wrapper around the test logic we are able to defer execution until needed, as well as provide a normalized way for each test to have its own execution context. This way, we can remove some or all the tests we do not need in whatever upstream library should adopt has.
Something resembling a "builder" is coming. A basic dependency matcher and test lister is provided in build/
.
has.js contributions are covered under a common license by way of Dojo Foundation CLA, and brought to you by the following awesome folks:
- John David Dalton - FuseJS Project Lead
- Brad Dougherty
- Bryan Forbes - Dojo Committer
- Ryan Grove - YUI engineer
- Andrée Hansson
- Peter Higgins - Dojo Project Lead
- Paul Irish - jQuery Team, Modernizr developer
- Weston Ruter - X-Team/XHTMLized developer
- Rick Waldron
- Juriy Zaytsev - @kangax, nuff' said.
There is an IRC room setup for discussion or questions: #[email protected]
Internally, we follow these conventions:
- All Strings are quoted using double-quotes
"
- Test names are lowercase, hyphen separated strings. Enclosed in double-quotes
- Tests are passed
g
,d
, andn
. Use these aliases always.
- Tests are passed
- Globals are as follows, available as used but will be reduced to a single ref:
STR == "string"
FN == "function"
- Tests return Booleans. Sometimes, you must coerce a boolean:
- DO return
!!(someExpression)
as necessary - DO N0T return
!!("x" in y)
or anything else that would otherwise return a boolean, e.g.x !== y
,x > y
,typeof y
- DO wrap expressions in parens: e.g.
return ("x" in y)
- DO return
Tentatively, has.js is available under the Academic Free License, New BSD License, and the MIT License. Providing this common code under multiple licenses requires us to have all contributors agree to a CLA.
has.js is open source, and open to contribution. Please fork and send pull requests as you see fit. This is a rough list of things that are needed or coming:
- moar tests. Fork/pull request anytime.
- Static Frontend - some home to put a static instance of has.js online to collect UA -> has(test) mappings
- Documentation regarding each of the tests, by name. eg:
has("native-xhr") // tests if the environment has a native XmlHttpRequest implementation
. - moar tests. Again with the forking.
- "compiler" code / frontend
- ideally something that will use the list of tests, provide a clean interface to selecting tests needed and to download a single has.js file with tests embedded.
- keeping in mind to remove additional closures and provide (only needed)
var CONTS = ""
style helpers in a single wrapping function.