apply和call,bind的区别

区别

三者都可以改变函数的this对象指向
三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefined或null,则默认指向全局window
三者都可以传参,但是apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入
bind是返回绑定this之后的函数,apply、call 则是立即执行

使用

apply
apply接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次
当第一个参数为null、undefined的时候,默认指向window(在浏览器中)

function fn(...args){
    console.log(this,args);
}
let obj = {
    myname:"张三"
}

fn.apply(obj,[1,2]); //{myname: '张三'} [1, 2], this会变成传入的obj,传入的参数必须是一个数组;
fn(1,2) //window [1, 2], this指向window  
fn.apply(null,[1,2]); //window [1, 2], this指向window
fn.apply(undefined,[1,2]); //window [1, 2], this指向window


callcall方法的第一个参数也是this的指向,后面传入的是一个参数列表,第一个参数为null、undefined的时候,默认指向window(在浏览器中)

function fn(...args){
    console.log(this,args);
}
let obj = {
    myname:"张三"
}
fn.call(obj,1,2); //{myname: '张三'} [1, 2], this会变成传入的obj,传入的参数分开传;
fn.call(obj,[1,2]); //{myname: '张三'} [[1, 2]], this会变成传入的obj,传入一个数组默认当一个值
fn(1,2) //window [1,2], this指向window
fn.call(null,1,2); window [1,2], this指向window
fn.call(undefined,1,2); window [1,2], this指向window


bind
bind方法和call很相似,第一参数也是this的指向,后面传入的也是一个参数列表
改变this指向后不会立即执行,而是返回一个永久改变this指向的函数

function fn(...args){
    console.log(this,args);
}
let obj = {
    myname:"张三"
}
const bindFn = fn.bind(obj); // this 也会变成传入的obj ,bind不是立即执行需要执行一次
bindFn(1,2) //{myname:"张三"} [1,2], this指向obj
fn(1,2) //window [1,2], this指向window

const foot ={
    apple:'苹果'
}
function eat(a,b){
   console.log(a,b,this)
}
const bindEat = eat.bind(foot)
eat(1,2) // 1 2 Window
bindEat(1,2) //1 2  foot 
eat.call(foot,1,2) //1 2  foot
/* apply参数已数组形式传递  */
eat.apply(foot,[1,2]) //1 2  foot

手写apply

function greet(msg) {
  console.log(msg, this.name);
}
const obj = { name: "Alice" };

//手写apply
Function.prototype.myApply = function(context, argsArray = []) {
  context = context || window;
  const fnKey = Symbol();
  context[fnKey] = this;
  // 使用展开语法传递数组参数
  const result = context[fnKey](...argsArray);
  delete context[fnKey];
  return result;
};

greet.myApply(obj, ["Hi"]); // 输出: Hi Alice

手写call

function greet(msg) {
  console.log(msg, this.name);
}
const obj = { name: "Alice" };

//手写call
Function.prototype.myCall = function(context, ...args) {
  // 处理 context 为 null 或 undefined 的情况
  context = context || window; 
  // 防止属性名冲突,使用 Symbol 作为唯一键
  const fnKey = Symbol();
  // 将当前函数绑定到 context 上(this 指向调用 myCall 的函数)
  context[fnKey] = this;
  // 执行函数并保存结果
  const result = context[fnKey](...args);
  // 删除临时绑定的属性
  delete context[fnKey];
  return result;
};

greet.myCall (obj, "Hello"); // 输出: Hello Alice

手写bind

Function.prototype.myBind = function(context, ...bindArgs) {
  const originalFunc = this;
  // 返回一个绑定 this 的新函数
  const boundFunc = function(...callArgs) {
    // 判断是否通过 new 调用(this 是否为 boundFunc 的实例)
    const isNewCall = this instanceof boundFunc;
    // 如果是 new 调用,保持 this 指向新对象;否则绑定到 context
    return originalFunc.apply(
      isNewCall ? this : context,
      [...bindArgs, ...callArgs]
    );
  };
  // 维护原型链(避免修改原函数的 prototype)
  if (originalFunc.prototype) {
    boundFunc.prototype = Object.create(originalFunc.prototype);
  }
  return boundFunc;
};

const boundGreet = greet.myBind(obj, "Hey");
boundGreet(); // 输出: Hey Alice

function Person(name) {
  this.name = name;
}
const BoundPerson = Person.myBind({});
const p = new BoundPerson("Bob");
console.log(p.name); // 输出: Bob(正确绑定到新对象)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值