Skip to content

Instantly share code, notes, and snippets.

@ositowang
Created April 3, 2019 18:02
Show Gist options
  • Save ositowang/e212dbec409cc28db4e2d5fc22db09b4 to your computer and use it in GitHub Desktop.
Save ositowang/e212dbec409cc28db4e2d5fc22db09b4 to your computer and use it in GitHub Desktop.
a more comprehensive bind() that covers prototype chain and constructor function
/**
* Here comes the hardest parts. Have you considered if the function you are
* going to bind is a constructor function.In this scenario, the this value you
* bind should get ignored.
*
* @param {*} context
*/
Function.prototype.bindUltimate = function(context) {
if (typeof this !== 'function') {
throw new Error('bind is only invoked on functions');
}
let fn = this;
let args = [...arguments].slice(1);
let resultFn = function() {
let bindArgs = [...args];
/**
* Here is tricky part:
* 1. if the fn is an constructor,this points to the instance, fn
* points to the function to be bound.However, we explicitly set the
* prototype of resultFn.prototype to the fn.prototype. Therefore, it would
* be true and the this is set to the instance.
* 2. if fn is not an constructor function. this points to the global
* object, fn points to the function to be bound. So the this set to the
* context passed in
*/
fn.apply(this instanceof fn ? this : context, args.concat(bindArgs));
};
//dealing with the prototype issues, we uses a bus function to link to the chain
function bus() {}
bus.prototype = this.prototype;
resultFn.prototype = new bus();
return resultFn;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment