Skip to content
This repository

Modernizr.prefixed(str,obj) to use Function.prototype.bind? #478

Closed
paulirish opened this Issue January 29, 2012 · 14 comments

3 participants

Paul Irish Ryan Seddon Alex Sexton
Paul Irish
Owner

or just

 return function(){ return x.apply(navigator, arguments); }

The reason why

Some recent examples from user tests..

window[ Modernizr.prefixed('requestAnimationFrame', window) ]
battery = nav[ Modernizr.prefixed('battery', nav) ];
window[ Modernizr.prefixed('StorageInfo', window) ];

The double window/nav references kinda suck.. wondering if we just automatically bind the scope of it so we can pass back a function.

Hmmm

But would we only do this if the resulting thing is a function? And still just pass back a string otherwise?

how about Modernizr.prefixed('performance', window); .. pass back object or string?

Also to consider..

HTMLElement.prototype.webkitMatchesSelector
// so
Modernizr.prefixed('webkitMatchesSelector', HTMLElement.prototype); // return value ??

so we should make a call..what do we return?

  1. always return a string? (current behavior)
  2. return bound function in the case of functions?
  3. return actual reference for all cases (matchesSelector example disqualifies this)
  4. require a 3rd param to use as the binding scope (see comment below)
Paul Irish
Owner

a possibility for scoping for the last example from alex... use a 3rd param.

var myelem = evt.target;
var ms = Modernizr.prefixed( 'matchesSelector', HTMLElement.prototype, myelem)
if (ms('.item')) ...
Ryan Seddon
Owner

That is a tough one. I would argue that this about detecting and not creating a helper method, however being both would be advantageous. I could play around with a 3rd arg and see how it feels?

Paul Irish
Owner

I think i wanna do the autobind.

questions:

  1. bind to 2nd arg automatically if its typeof .. == 'function' (and no 3rd arg) ?
  2. require 3rd arg to opt into binding

.

  • what to do about objects (like window.msPerformance) and props? return references and values or string as we do it today..
Alex Sexton
Owner

Sorry was mobile earlier and couldn't chime in. I think we can do this pretty easily with something like the following:

Normal Case

// Since 'requestAnimationFrame' exists on window as a function, 
// return the function bound to window
Modernizr.prefixed('requestAnimationFrame', window)

Override to string:

// Passing false as a third param disables the possibility 
// of a function return, always a string
Modernizr.prefixed('requestAnimationFrame', window, false) // window.webkitRequestAnimationFrame

Override to other binding:

// force a binding by passing the bound object.
// This could be avoided by just passing in the element as the second param (as long as we look into prototypes).
Modernizr.prefixed( 'matchesSelector', HTMLElement.prototype, document.getElementById('theid'))

Downsides I can see:

  • Performance: it will be faster to get a string back once, and use it on all elements.
  • The case of no function being found returns a string, but when it's found it returns a function, so you'd have to test the output. This could be a bad thing.
Alex Sexton
Owner

Perhaps that means you should have to opt in for it. Always returns a string, unless you pass a third param.

pass true for us to auto use the 2nd arg, and any other object to bind to that instead.

Further if you expect a function back, the result should be falsey if it doesn't exist (instead of the raw string like in the string version of the function). A noop function could potentially work, but I haven't thought into that much.

Paul Irish
Owner

It should be falsy return if the test fails.. which would allow for a nice rAF polyfill

window.rAF = Modernizr.prefixed('requestAnimationFrame', window) || function(){ ... 

The rest sounds good to me. I would prefer to return the function / object / prop value when possible instead of its name.

Trying to think of any prefixed property names that are just string values or numbers...

Ryan Seddon
Owner

Check out some early code in the prefixed branch 16a056d

I just grabbed the Function.prototype.bind shim from es5-shim

window.rAF = Modernizr.prefixed('requestAnimationFrame', window) || function(){ ...

This will now work as expected either returning a reference to rAF of false and falling back to function

// Passing in the 3rd arg will bind to that
// e.g. ms("div") -> true
var ms = Modernizr.prefixed("matchesSelector", HTMLElement.prototype, document.querySelector("div"))

So the three possible results that this change can get:

  • false
  • reference to object
  • reference to object with binding
Ryan Seddon
Owner

Also it doesn't do any hand holding so if someone tries to pass in something silly for the 3rd arg it will throw.

Paul Irish
Owner

ryan you got a patch for this alls et?

Paul Irish
Owner

I just merged in Ryan's branch. Considering this ticket closed code-wise but we'll have to add docs.

Paul Irish
Owner

Okay. code and tests updated. lots of tests!

i think this is basically what @SlexAxton proposed here
#478 (comment)

I have some extra checks so we're not calling .bind() on a non-function.
i think the tests explain the API the best, but

  • if prefixed(str,obj) identifies a fn then its auto-bind()'d to obj
  • if the third arg exists and is truthy, then the fn is bind()'d to it.
  • if the third arg is false, then its always returns the stringed name of the prop/method
  • if prefixed(str,obj) finds something that is a non-function, it just returns that.
Paul Irish
Owner

Done except for docs.

Ryan Seddon
Owner

I approve this commit, good stuff!

Paul Irish
Owner

docs added.

Paul Irish paulirish closed this February 06, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.