call

call方法的特点:
一个函数通过.call()就相当于这个函数执行。
这个函数中 this 的指向就是call方法中的第一个参数。
call方法中从第二个参数开始之后,都是调用call方法函数的参数。

  1. Function.prototype.myCall = function (ctx) {
  2. ctx = ctx ? Object(ctx) : window;
  3. ctx.originFn = this;
  4. var args = [];
  5. for (var i = 1; i < arguments.length; i ++) {
  6. args.push('arguments[' + i + ']');
  7. }
  8. console.log(args);
  9. var res = eval('ctx.origin(' + args + ')');
  10. delete ctx.originFn;
  11. return res;
  12. }

apply

apply方法的特点:
一个函数通过.apply()就相当于这个函数执行。
这个函数中 this 的指向就是call方法中的第一个参数。
apply方法的第二个参数是一个数组,里面是调用apply方法函数的参数。
apply方法只取到第二个参数,后面的忽略。
如果第二个参数是undefined、null、object、function,不报错但是arguments的length为0。
如果第二个参数是原始值,直接报错。

  1. Function.prototype.myApply = function (ctx, args) {
  2. ctx = ctx ? Object(ctx) : window;
  3. ctx.originFn = this;
  4. if (args === undefined || args === null) {
  5. return ctx.originFn();
  6. }
  7. if (typeof args !== 'object' && typeof args !== 'function') {
  8. throw new Error('createListFormArrayLike called on non-object');
  9. }
  10. if (({}).toString.call(args) !== '[object Array]') {
  11. return ctx.originFn();
  12. }
  13. var res = eval('ctx.originFn(' + args + ')');
  14. delete ctx.originFn;
  15. return res;
  16. }

bind

bind方法的特点:
一个函数通过.bind()之后不会立即执行,而是返回一个新的函数。
这个函数中 this 的指向就是bind方法中的第一个参数。
bind方法从第二个参数开始,后面是调用bind方法函数的参数。
bind方法可以接收一部分参数,返回的新函数可以接收另一部分参数。
返回的新函数通过new执行(实例化),this指向原本的函数构造出来的实例。
实例继承原函数构造函数上的原型。

  1. Function.prototype.myBind = function (ctx) {
  2. var originFn = this,
  3. args = [].slice.call(arguments, 1),
  4. _tempFn = function () {};
  5. var newFn = function () {
  6. var newArgs = [].slice.call(arguments),
  7. context = this instanceof newFn ? this : ctx;
  8. return originFn.apply(context, args.concat(newArgs));
  9. }
  10. _tempFn.prototype = originFn.prototype;
  11. newFn.prototype = new _tempFn();
  12. return newFn;
  13. }