手写JS中的call、apply、bind方法

手写JS中的call、apply、bind方法

技术杂谈小彩虹2021-08-18 6:11:04200A+A-

相关知识点

  • 实现 call 方法
  • 实现 apply 方法
  • 实现 bind 方法

实现 call 方法

  • 首先 context 为可选参数,如果不传的话默认上下文为 window
  • 接下来给 context 创建一个 fn 属性,并将值设置为需要调用的函数;
  • 因为 call 可以传入多个参数作为调用函数的参数,所以需要将参数剥离出来;
  • 然后调用函数并将对象上的函数删除;
Function.prototype.myCall = function (context) {
  // this 为调用的函数
  // context 是参数对象
  // 判断调用者是否为函数
  if (typeof this !== "function") {
    throw new Error("Error");
  }
  // 不传参默认为 window
  context = context || window;
  // 新增 fn 属性, 将值设置为需要调用的函数
  context.fn = this;
  // 将 arguments 转化为数组将 call 的传参提取出来
  const args = Array.from(arguments).slice(1);
  // 或者使用 ...
  // const args = [...arguments].slice(1);
  // 传参调用函数
  context.fn(...args);
  // 删除函数 fn
  delete context.fn;
};

// 普通函数
function print(age) {
  console.log(this);
  console.log(this.name, age);
}

// 自定义对象
var obj = {
  name: "jack"
};

// 调用 myCall 方法
print.myCall(obj, 1, 2, 3);
/* 输出结果为: {name: "jack", fn: ƒ} jack 1 */

print.myCall(obj, [1, 2, 3]);
/* 输出结果为: {name: "jack", fn: ƒ} jack [1, 2, 3] */

实现 apply 方法

Function.prototype.myApply = function (context) {
  // 判断调用者是否为函数
  if (typeof this !== "function") {
    throw new TypeError("Error");
  }
  // 不传参默认为 window
  context = context || window;
  // 新增 fn 属性, 将值设置为需要调用的函数
  context.fn = this;
  // 判断是否有参数传入
  if (arguments[1]) {
    // 判断参数是否为数组
    if (Object.prototype.toString.call(arguments[1]) === "[object Array]") {
      context.fn(arguments[1]);
    } else {
      throw new TypeError("参数只能为数组");
    }
  } else {
    context.fn();
  }
  // 删除函数
  delete context.fn;
};

// 普通函数
function print(age) {
  console.log(this.name, age);
}

// 自定义对象
var obj = {
  name: "jack"
};

// 调用函数的 apply 方法
print.myApply(obj, [10, 20, 30]); // jack [10, 20, 30]
print.myApply(obj); // jack undefined

实现 bind 方法

Function.prototype.myBind = function (context) {
  if (typeof this !== "function") {
    throw new TypeError("Error");
  }
  const _this = this;
  context = context || window;
  const args = [...arguments].slice(1);
  return function () {
    // console.log(this); // Window
    // console.log(_this); // print 方法
    return _this.apply(context, args.concat(...arguments));
  };
};

function print(args) {
  console.log(this.name, args);
}

var obj = {
  name: "Tom"
};

let fn = print.myBind(obj, [1, 3, 5]);
let fn2 = print.myBind(obj, 2, 4, 6);
fn(); // Tom [1, 3, 5]
fn2(); // Tom 2

点击这里复制本文地址 以上内容由权冠洲的博客整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!

支持Ctrl+Enter提交

联系我们| 本站介绍| 留言建议 | 交换友链 | 域名展示
本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除

权冠洲的博客 © All Rights Reserved.  Copyright quanguanzhou.top All Rights Reserved
苏公网安备 32030302000848号   苏ICP备20033101号-1
本网站由 提供CDN/云存储服务

联系我们