自己手写call、apply和bind

call

// 手写call
Function.prototype.myCall = function (context, ...parameters) {
  if (context === undefined || context === null) {
    context = window;
  } else {
    // 值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的实例对象
    context = Object(context);
  }
  // 用于指向要绑定this的函数的一个临时属性 用Symbol()可以使其具备唯一性
  temp = Symbol('我是一个与众不同的属性');
  // this指的就是要执行的函数
  context[temp] = this;
  // 将context作为对象 调用它自身的方法 这样自然就隐式绑定了context
  var result = context[temp](...parameters);
  // 删除这个临时属性 (过河拆桥)
  delete context[temp];
  // 返回函数执行的结果
  return result;
}

apply

// 2.apply接受第二个参数为类数组对象, 这里用了JavaScript权威指南中判断是否为类数组对象的方法
Function.prototype.myApply = function (context) {
  if (context === undefined || context === null) {
    context = window;
  } else {
    context = Object(context);
  }
  // JavaScript权威指南判断是否为类数组对象
  function isArrayLike(o) {
    if (o &&                                    // o不是null、undefined等
      typeof o === 'object' &&                // o是对象
      isFinite(o.length) &&                   // o.length是有限数值
      o.length >= 0 &&                        // o.length为非负值
      o.length === Math.floor(o.length) &&    // o.length是整数
      o.length < 4294967296)                  // o.length < 2^32
      return true;
    else
      return false;
  }
  var temp = Symbol('我是一个与众不同的属性');
  context[temp] = this;
  var args = arguments[1];
  var result;
  // 如果传了第二个参数
  if (args) {
    // 不是数组也不是类数组则应该抛出错误
    if (!Array.isArray(args) && !isArrayLike(args)) {
      throw new TypeError('myApply 第二个参数不为数组并且不为类数组对象抛出错误');
    } else {
      var arr = Array.from(args);
      result = context[temp](...arr);
    }
  } else {
    result = context[temp]();
  }
  delete context[temp]
  return result;
}

bind

// 手写bind
Function.prototype.myBind = function (obj, ...parameters) {
  // 存储源函数及其参数
  const fn = this;
  // 返回的函数 以及将要第二次传入的参数
  var retFn = function (...secondParameters) {
    // 对是否new做处理 instanceof 判断this是否是retFn这个函数的实例
    var isNew = this instanceof retFn;
     // new调用就绑定到this上,否则就绑定到传入的objThis上
    var context = isNew ? this : Object(obj);
    return fn.call(context, ...parameters, ...secondParameters);
  };
  retFn.prototype = Object.create(fn.prototype);
  return retFn;
}

你可能感兴趣的:(自己手写call、apply和bind)