Shim sniffing

Extending native objects and prototypes is bad. If not vile, mean and Jesuitic.

// Noooooo!
Array.prototype.map = function() {
  // stuff
};

Unless it's desirable, for example for adding ECMAScript5 methods in legacy browsers.

In which case we do something like:

if (!Array.prototype.map) {
  Array.prototype.map = function() {
    // stuff
  };
}

If we're paranoid enough we can even try to protect from somebody defining map as something unexpected like true or "the peaches are this way":

if (typeof Array.prototype.map !== "function") {
  Array.prototype.map = function() {
    // stuff
  };
}

(Although that ultimately breaks the other developer's map to the peach trees)

But in a hostile dog-eat-dog cut-throat environment (in other words when you provide or consume a library), you trust no one. What if that other smartass JS loads before your badass JS and defines map() in a way that is not really ES5-compliant and your code doesn't work anymore?

You can always trust browsers though. If Webkit implements map() you can relax that it should probably work OK. Otherwise you'd want to go ahead with your shim.

Luckily that's easy to do in JavaScript. When you call toString() of a native function it should return a string with a function that has a body of [native code]

So for example in Chrome's console:

> Array.prototype.map.toString();
"function map() { [native code] }"

A proper check is ever-so-slightly painful because browsers seem to be a little frivolous with white spaces and new lines. Testing:

Array.prototype.map.toString().replace(/\s/g, '*');
// "*function*map()*{*****[native*code]*}*"  // IE
// "function*map()*{*****[native*code]*}" // FF
// "function*map()*{*[native*code]*}" // Chrome

Simply stripping all \s will give you something more workable:

Array.prototype.map.toString().replace(/\s/g, '');
// "functionmap(){[nativecode]}"

You can opt in for a reusable shim() function so you don't have to repeat all that !Array.prototype... jazz. It can take an object to augment (e.g. Array.prototype), a property to add (e.g. 'map') and a function that implements the shim.

function shim(o, prop, fn) {
  var nbody = "function" + prop + "(){[nativecode]}";
  if (o.hasOwnProperty(prop) &&
      o[prop].toString().replace(/\s/g, '') === nbody) {
    // native!
    return true;
  }
  // shim
  o[prop] = fn;
}

Testing:

// this is native, cool
shim(
  Array.prototype, 'map',
  function(){/*...*/}
); // true
 
//  this is new
shim(
  Array.prototype, 'mapzer',
  function(){alert(this)}
);
 
[1,2,3].mapzer(); // alerts 1,2,3

p.s. And then
there's JJD's! (backstory)

30 Responses to “Shim sniffing”

  1. Kai Sellgren Says:

    You forgot “typeof” from the third code example.

    I think this is a bit exaggerated…

  2. stoyan Says:

    Thanks Kai, fixed!

    can you elaborate on “exaggerated”?

  3. Callum Macrae Says:

    I think Kai means over the top. When I first read it it seemed a bit over the top, but having thought about it, that function could turn out to be pretty useful.

    Nice article, thanks!

  4. Peter van der Zee Says:

    Array.prototype.map = Array.prototype.forEach

    And now you have [native code] problems ;)

    Nah I like the approach, I just think it’s very very defensive. Might as well implement your own if you want to take this route.

  5. Andrea Giammarchi Says:

    Agreed with Peter van der Zee … but if you want to trust a bit more the fact a function is native or not I would use a different approach:

    var isNativeFunction = function(Function){
    var s, toString = Function.prototype.toString;
    return function isNativeFunction(f) {
    try {
    s = toString.call(f);
    try {
    Function(“return ” + s);
    } catch(_) {
    return true;
    }
    } catch(_) {}
    return false;
    };
    }(Function);

  6. Stoyan Says:

    @Peter, @Andrea Unfortunatelly the need for this has come up in practice not just an excercise :)

    @Andrea, why the first `try`? How about a simpler: https://gist.github.com/2878985

  7. Andrea Giammarchi Says:

    f.toString does not ensure it’s a function in first place, neither the toString is the original one.
    Function.prototype.toString can be used for functions/callable objects only so it ensure, without needing extra checks, that the given object is a function, it will fail otherwise.

    As summary, Function.prototype.toString.call({}) will throw an error since it’s not a function, and not native :-)

  8. Andrea Giammarchi Says:

    so … two examples here, the reason I have used those try/catch
    https://gist.github.com/2878985#comments

  9. Peter van der Zee Says:

    So how do/did you defend against replacing one native method with another?

  10. Andrea Giammarchi Says:

    the easiest way to check that is something like isNativeFunction([].map) && [].map.name == “map” … this should work cross platform except for IE less than 9

  11. stoyan Says:

    And what about Function.prototype.toString = alert; Obviously we have to stop somewhere :)

    The point here was not to be overly defensive. isNative doesn’t have to deal with non-function input etc. Just defend against shims that are well-intentioned but possibly slightly off

  12. Peter van der Zee Says:

    Andrea: the array (and object) literal will only use the built-in constructor. They still use the (global) Array.prototype. As such, replacing Array.prototype.map with something else will cause [].map to reflect that.

    Stoyan: Okay, that sounds valid :)

  13. Peter van der Zee Says:

    Oh by the way, there used to be a trick where if you deleted a built-in global object you would get back the built-in one. I just tried on Chrome and it didn’t work so maybe I’m doing it wrong, maybe it’s a different browser, or maybe that just doesn’t work anymore :)

  14. Shim sniffing | JSSpy | The ultimate resource for Javascript info. Says:

    [...] http://www.jspatterns.com/shim-sniffing/ Share on  Twitter  Facebook  Google Reader  Ping.fm No Comments Related [...]

  15. Michel Schakel Says:

    I have been surfing online greater than three hours today, but I by no means found any fascinating article like yours. It is pretty price sufficient for me. In my opinion, if all website owners and bloggers made good content material as you did, the web will be much more useful than ever before.

  16. Work at Home Says:

    Great paintings! This is the kind of information that are supposed to be shared around the web. Disgrace on Google for not positioning this post higher! Come on over and visit my web site . Thank you =)

  17. Phil Says:

    Yeah, I agree with the thoughts of this post. Extending prototype is evil (except in some cases like when you want to add IsNullOrEmpty to String and you have good reasons not to use underscore.js) I also like the thought of trusting native implementations and assuming some jerk developer does not change it to something like: Ha ha!

  18. nike shoes outlet Says:

    the preliminary spherical 31 using the 60yard taxi burberry black friday online , A 38 directory pass restoreradio.net/faq.html , A 104 wide soar restoreradio.net/faq.html and simply 16 distributors black Friday uggs concerning the bench press exercise Cheap Gucci Francis coach donald Ferriera saidOther guiding replica michael kors handbags experience of Plano is included with hankjagt.com/history.html Schimelpfenig middle school, Plano school gucci sale as well as,while robinson nike sneakers f

  19. Bottega Veneta borse Says:

    Ci sono fancy car berlina, Sports utility vehicle fancy car, supposrr que estende / berline esotici, Hummer fancy car, car (autobus partito). È possibile rendere illinois vostro giorno delle nozze ancora più speciale hoax l’assunzione di una Bentley Phantom fancy car e Hayundai Classe Erinarians berlina, rispetto alla tradizionale Lincoln subsequently Metropolis Vehicle fancy car.
    Bottega Veneta borse http://bottegaveneta.kingpolitics.com/

  20. louisvuitton.galleryr.org Says:

    Infezioni. Malattie, come l’HIV Or Helps, malware di Epstein Barr, epatite
    louisvuitton.galleryr.org http://louisvuitton.galleryr.org/

  21. chanel borse Says:

    Sei attualmente attraversando us periodo difficile decidere pueden ottenere us lungo to us breve periodo di giorno di paga prestito Ogni tipo di prestiti sono grandi nella loro approcci. Quando suppos que arriva lungo payday advance prestiti your termine, suppos que ottengono vantaggi in più gna no suppos que fa trick us prestito your breve termine. Nel caso in cui avete bisogno di più di us periodo di due settimane each pagare celui-ci mutuo, apprezzabili us prestito your lungo termine è chicago soluzione migliore.
    chanel borse http://borsechanel.kpifoe.com/

  22. traffic exchange bot Says:

    Simply wish to say your article is as surprising.

    The clarity in your post is simply excellent and i could assume
    you’re an expert on this subject. Well with your permission
    let me to grab your RSS feed to keep up to date with forthcoming post.

    Thanks a million and please continue the gratifying work.

  23. Cheap Parajumpers Says:

    This will increase your electric bills, as well. In fact, in accordance with Poisoned Waters, the EPA doesn’t know how to measure, a smaller amount regulate these chemicals, and nobody really knows what long-term parajumpers pants may lie ahead. It is recommended to use coilovers that are designed for the kind of car you have for best results. Don`t be fooled by all the glamorous looking outer shells of the Parajumpers Jacketss as they sit there on the shelves,parajumpers jacket toronto. This ve

  24. Barbour Outlet Says:

    We saw it first displayed in a video from October 2010 when Cutts was discussing archaic SEO ,Barbour JacketsBarbour Jacketss that do not work (hence the dinosaur reference). Lastly, Bank of America (BAC) remains at the forefront of one particular Barbour Outlet segment in financials that warrants continuously close attention. If you have an echoBarbour UKdiogram and it turns out that you have mitral valve prolpase,Barbour, you will put your mind to rest and never worry about this chest pain aga

  25. canal Says:

    I delight in, lead to I found exactly what I used to be having a look for.

    You have ended my 4 day long hunt! God Bless you man. Have a great
    day. Bye

  26. Chaussures Louboutin Says:

    In the event that joining a trip party, get yourself a lowcalorie chicken drink want seltzer standard water and also juice at the time you occur. In case you glass steadily on your own take in you’ll likely far from top off relating to increased fat cocktails. Then, in 2004, Bryant’s contract with McDonald’s was not renewed. Although Bryant made a public apology and settled the assault case out of court,Christian Louboutin Soldes lo,Christian Louboutin Paris, he lost endorsement agreements with

  27. cheap louis vuitton Says:

    i didn’t expect myself to come back this considerablyI’d louis vuitton store chicago like to point out our next renowned prime selling brand JM men’s underwear, they are available in some intriguing designs and colours. You’ll want to look through our retailer for JM Koton Gray / White Jockstraps. Would you now agree that they’re speedy louis vuitton interesting styles? Inside a planet with a more than 100M guys in US each and every brand name had to arrive up with new designs / colors and in th

  28. Carolina Herrera Vestidos Says:

    I’m not Dennis Kucinich saying impeach everybody now.”Theres a problem there too,Theres research that explains that phenomenon too, Rafferty can’t be sentenced to death; he faces life in prison without chance of parole.” Baumoel said. “the fake Obama appeared to be lying back catching a snooze.By Brian Williams And I’m not thinking about the dozen or so professional athletes who have hosted the show over its 32-year history, however, drama award.

  29. medic ginecolog Says:

    Hiya! I know this is kinda off topic but I’d figured I’d ask.
    Would you be interested in exchanging links or maybe guest writing a blog post or
    vice-versa? My website addresses a lot of the same topics as yours and I believe we could greatly
    benefit from each other. If you are interested feel free to send me an e-mail.
    I look forward to hearing from you! Awesome blog by the way!

  30. mobile games Says:

    Hello, I enjoy reading all of your article. I like to write a
    little comment to support you.

Leave a Reply