Skip to content

Instantly share code, notes, and snippets.

@derek
Created August 5, 2014 18:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save derek/3599f91c5ea96a3f3045 to your computer and use it in GitHub Desktop.
Save derek/3599f91c5ea96a3f3045 to your computer and use it in GitHub Desktop.
Function.prototype.bind CoffeeScript polyfill
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind#Compatibility
Function::bind ?= (oThis, args...) ->
fNOP = ->
fNOP:: ?= @::
fBound = =>
context = if this instanceof fNOP and oThis then this else oThis
@apply context, args.concat arguments
fBound:: = new fNOP()
fBound
@derek
Copy link
Author

derek commented Aug 5, 2014

Worth noting that the original polyfill assigns fNOP.prototype to this.prototype unconditionally, but when this.prototype is actually undefined, then you break instanceof. This is an edge-case that you can run into when you are running bind on a native method, such as Function.prototype.apply.bind.

So, a simple ?= fixes that issue. Shouldn't assign it a prototype that doesn't exist.

Whipped this up to better understand the issue. Here's a comparison of using the faulty MDN polyfill compared to native bind to show that the two are not equivalent.

Function::customBind = (oThis, args...) ->
    fNOP = ->
    fNOP:: = @::

    fBound = =>
        context = if this instanceof fNOP and oThis then this else oThis
        @apply context, args.concat arguments

    fBound:: = new fNOP()
    fBound

a = Function::apply.bind (class noop)
b = Function::apply.customBind (class noop)

# Test a()
try
  a()
  console.log 'a: OK'
catch error
  console.log "a: #{error.message}"

# Test b()
try
  b()
  console.log 'b: OK'
catch error
  console.log "b: #{error.message}"

Output

a: OK
b: Function has non-object prototype 'undefined' in instanceof check 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment