wsqww / devNote

开发笔记
3 stars 3 forks source link

js 实现代码 call、applay、bind #32

Open wsqww opened 3 years ago

wsqww commented 3 years ago

测试代码,点击这里

wsqww commented 3 years ago

Call

/**
 * call
 * @param {*} ctx
 * 1.ctx 存在就使用 ctx window
 * 2.使用 Object(ctx) 将 ctx 转换成对象,并通过 ctx.fn 将 this 指向 ctx
 * 3.循环参数,注意从 1 开始,第 0 个是上下文,后面才是我们需要的参数
 * 4.将参数字符串 push 进 args
 * 5.拿到结果返回前,删除掉 fn
 */
Function.prototype.myCall = function (ctx) {
  ctx = ctx || window;
  const fn = Symbol(); //  Symbol属性来确定fn唯一。
  const args = [...arguments].slice(1);
  // console.log(this);
  ctx[fn] = this; // this 在这里是调用 call 的函数
  const result = ctx[fn](...args);
  delete ctx[fn];
  return result;
};
wsqww commented 3 years ago

Apply

/**
 * apply
 * @param {*} ctx 
 * @param {*} args 
 * 1.apply 无需循环参数列表,传入的 args 就是数组
 * 2.但是 args 是可选参数,如果不传入的话,直接执行
 */
Function.prototype.myApply = function (ctx, args) {
  ctx = ctx || window;
  const fn = Symbol(); //  Symbol属性来确定fn唯一。
  ctx[fn] = this; // this 是调用 call 的函数 f say() {}
  let result;
  if (!args) {
    // 判断array是否存在
    result = ctx[fn]();
  } else {
    result = ctx[fn](...args);
  }
  delete ctx[fn];
  return result;
};
wsqww commented 3 years ago

Bind

/**
 * bind
 * @param {*} ctx 
 * 1. 改变this指向
 * 2. 接受参数列表、
 * 3. return 一个函数
 * 4. 遇到new这样优先级高于bind方法的时候,bind改变this指向会无效。
 */
/* eslint-disable */
Function.prototype.myBind = function (ctx) {
  var self = this; // 因为之后要return一个函数,这里保存一下this防止混乱
  var args = Array.prototype.slice.call(arguments, 1); // 获取参数
  var fb = function () {
    var bindArgs = Array.prototype.slice.call(arguments);
    const target = this instanceof fb ? this : ctx;
    return self.apply(target, args.concat(bindArgs));
  };
  var fn = function () {};
  fn.prototype = this.prototype; // 让实例可以继承原型
  fb.prototype = new fn();
  return fb;
};
wsqww commented 3 years ago

测试

let Person = {
  name: "Tom",
  say(a, b) {
    this.a = a;
    this.b = b;
    console.log(this);
    console.log(`我叫${this.name}, a: ${this.a}, b: ${this.b}`);
  }
};

// call --------------------------------------------------------
let PersonA = {
  name: "Tom A"
};
Person.say.myCall(PersonA, "A1", "A2");

// apply --------------------------------------------------------
let PersonB = {
  name: "Tom B"
};
Person.say.myApply(PersonB, ["B1", "B2"]);

// bind --------------------------------------------------------
let PersonC = {
  name: "Tom C"
};
const fnC = Person.say.myBind(PersonC, "C1");
fnC("C2");
wsqww commented 3 years ago

call apply bind 用法区别