call apply bind特性及手动实现

call

// 原生的call
var foo = { value: 1 };

function bar(...args) {
  console.log("this", this.value, args);
}

bar.call(foo)

// call 改变了bar的this指向
// bar函数执行了
// 等价于
// var foo = {
//   name: "tengzhu",
//   sex: "man",
//   bar() {
//     console.log("this", this);
//   },
// };
  • 手动实现call
var foo = { value: 1 };

function bar(...args) {
  console.log("this", this.value, args);
}

// 1. 将函数设置为对象的属性
// 2. 执行该函数
// 3. 删除该函数
// 4. 接受多个参数
Function.prototype.myCall = function (context, ...args) {
  // this参数为null 的时候 ,指向window
  // context === foo
  // args 为 bar的入参
  const ctx = context || window;
  const symbol = Symbol();
  ctx[symbol] = this;
  // const args = [...arguments].slice(1);
  const result = ctx[symbol](...args);
  delete ctx[symbol];
  return result;
};

bar.myCall(foo, 1, 2, 3);
  • 手动实现apply
var foo = { value: 1 };

function bar(...args) {
  console.log("this", this.value, args);
}

// 1. 将函数设置为对象的属性
// 2. 执行该函数
// 3. 删除该函数
// 4. 接受两个入参,第一个为要指向的对象,数组
Function.prototype.myApply = function (context, args) {
  // this参数为null 的时候 ,指向window
  // context === foo
  // args 为 bar的入参
  const ctx = context || window;
  const symbol = Symbol();
  ctx[symbol] = this;
  // const args = [...arguments].slice(1);
  const result = ctx[symbol](...args);
  delete ctx[symbol];
  return result;
};

bar.myApply(foo, [1, 2, 3]);
  • 手动实现bind

基础版

// 1. 返回该函数
// 2. 接收多个入参,并且主动调用时的入参也生效
Function.prototype.myBind = function (context, ...args) {
  const _self = this; // bar
  return function (...newArgs) {
    return _self.myApply(context, [...args, ...newArgs]);
  };
};

const bindFoo = bar.myBind(foo, 1, 2, 3);
bindFoo(4, 5, 6);

通过new bindFoo()使用

const foo = { value: 1 };
function bar(name, age) {
  this.habbit = "basketball";
  console.log("this", name, age);
}
bar.prototype.friend = "xiaoming";

// 手写bind
// 1. 一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数
// * 当 bind 返回的函数作为构造函数的时候,bind 时指定的 this 值会失效,但传入的参数依然生效
Function.prototype.myBind = function (context, ...args) {
  // 判断是否是undefined 和 null
  if (typeof context === "undefined" || context === null) {
    context = window;
  }
  const _self = this; // bar
  const middleFn = function () {}; // 中转空函数

  const returnFn = function (...newArgs) {
    // 当作为构造函数时,this 指向实例,此时结果为 true,将绑定函数的 this 指向该实例,可以让实例获得来自绑定函数的值
    // 当作为普通函数时,this 指向 window,此时结果为 false,将绑定函数的 this 指向 context
    const ctx = this instanceof returnFn ? this : context; // 判断this是否失效
    return _self.myApply(ctx, [...args, ...newArgs]);
  };
  // 修改返回函数的 prototype 为绑定函数的 prototype,实例就可以继承绑定函数的原型中的值
  // 方法一:
  // 原型链共享 影响父层原型(即修改returnFn.prototype上的属性会影响父级(bar)的原型):bar.prototype.friend 会变成xiaohong
  // returnFn.prototype = _self.prototype;
  // returnFn.prototype.friend = "xiaohong";

  // 方法二:
  // 通过一个空函数中转,构造函数的实例指向构造函数的prototype,但是不会修改构造函数原型上的属性,相当于实例=>构造函数原型为只读状态
  middleFn.prototype = _self.prototype;
  returnFn.prototype = new middleFn();
  return returnFn;
};

// const test = bar.myBind(foo, "xiaoshuai", 19);
// test(4, 5, 7);
const bindFoo = bar.myBind(foo, "xiaoshuai", 19);
const test = new bindFoo(9);

console.log("test", test, test.friend, bar.prototype.friend);
  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
call、applybind都是用来改变函数中的this指向的方法。其中,call和apply可以直接调用函数并传递参数,而bind则返回一个新的函数,需要手动调用。 具体实现方案如下: - call的实现: 1. 给想要绑定的对象设置一个属性,并将该属性指向需要调用的函数。 2. 使用该对象调用函数,并传递参数。 3. 结束调用后,删除该属性。 - apply实现: 1. 给想要绑定的对象设置一个属性,并将该属性指向需要调用的函数。 2. 使用该对象调用函数,并传递参数数组。 3. 结束调用后,删除该属性。 - bind实现: 1. 创建一个新的函数,并将原函数作为其中的属性保存起来。 2. 当新函数被调用时,将之前绑定的对象作为this,并传递参数。 3. 返回新函数供后续调用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [如何实现call、applybind](https://blog.csdn.net/XIAO_A_fighting/article/details/116701887)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [原生JS实现 call apply bind](https://download.csdn.net/download/weixin_38628990/14046564)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值