summary:call()、apply()、bind()方法;

76 阅读5分钟

Funation Bindding 函数绑定

解决:丢失“this”问题

let user = {
  firstName: "John",
   // 简写类似缩写方式?
   // sayHi() { ... }是 ES6 新增的方法定义简写语法,它不需要写属性key
  sayHi() {
    alert(`Hello, ${this.firstName}!`); 
  }
  // sayHi: function() {`Hello, ${this.firstName}!`}
};
setTimeout(user.sayHi, 1000); // Hello, undefined!
// setTimeout 是通过 window 对象调用的,没有设置对象的情况下,默认就是 window.setTimeout 相当于 setTimeout

涉及:this绑定规则、词法环境

当直接调用user.sayHi时,会发生this丢失,这是由JavaScript的this绑定规则决定的:

  1. user.sayHi这里属于独立函数调用,没有明确绑定对象。
  2. 根据默认绑定规则,this会指向全局window对象。
  3. 而不是保持对user对象的绑定。
  4. 所以直接调用相当于使this“失去”了对user的绑定,走向了window。
  5. 如果从user对象的角度看,==this就像“走丢”了,没有跟随user行动。==
  6. 通过包装函数调用,可以修正this,重新绑定user对象。
  7. 这是==因为包装函数提供了词法作用域,使this重新指向了user==。

"简写方法"(Method Shorthand),简写方法也实现了更简洁高效的语法格式, 对完整方法定义的缩短表示。

  • 简写方法也保留了方法名,省略了冒号和function关键字。
  • 简写方法强调省略冒号和function来定义方法。

Pasted image 20230916155255.png

解决方案 2:bind

Pasted image 20230918102830.png

  1. 一开始对sayHi进行了bind绑定,绑定到了旧的user对象上。
  2. setTimeout作为异步回调,会延迟到最后执行。
  3. 在中间,重新修改了user对象,替换了sayHi方法。
  4. 但setTimeout闭包保存了之前绑定的旧user对象。
  5. 所以最后setTimeout执行时,依然调用的是旧的sayHi方法。
  6. 实现了闭包保存上下文的效果。 Pasted image 20230918103233.png

部分(应用)函数(Partial functions)

let bound = func.bind(context, [arg1], [arg2], ...);

context=>环境,执行环境。

function mul(a, b) {
  return a * b;
}
let double = mul.bind(null, 2);
alert( double(3) ); // = mul(2, 3) = 6
alert( double(4) ); // = mul(2, 4) = 8
alert( double(5) ); // = mul(2, 5) = 10

绑定先有函数的一些参数来创建一个新函数

  • 如果函数不在严格模式下,null 和 undefined 会被替换为全局对象。@

This Precedence

To determine which object this refers to; use the following precedence of order.

PrecedenceObject
1bind()
2apply() and call()
3Object method
4Global scope

this 是什么?

In an object method, this refers to the object. Alone, this refers to the global object.
In a function, this refers to the global object. In a function, in strict mode, this is undefined.
In an event, this refers to the element that received the event.
Methods like call()apply(), and bind() can refer this to any object.

示例1 方法调用

With call(), an object can use a method belonging to another object. 通过 call() ,一个对象可以使用属于另一个对象的方法。

const person = {  
  fullNamefunction() {  
    return this.firstName + " " + this.lastName;  
  }  
}  
const person1 = {  
  firstName:"John",  
  lastName"Doe"  
}  
const person2 = {  
  firstName:"Mary",  
  lastName"Doe"  
}  
  
// This will return "John Doe":  
person.fullName.call(person1);

示例2,The call() Method with Arguments

The JavaScript call() Method

模板: call(【Object】,arg1,arg2)

const person = {  
  fullNamefunction(city, country) {  
    return this.firstName + " " + this.lastName + "," + city + "," + country;  
  }  
}  
  
const person1 = {  
  firstName:"John",  
  lastName"Doe"  
}  
  
person.fullName.call(person1, "Oslo""Norway");

The Difference Between call() and apply()

The difference is: The call() method takes arguments separately. The apply() method takes arguments as an array.

  • call() 接收参数列表,apply() 接收数组作为参数
  • call方法可以rest参数,展开语法。

Pasted image 20230917165832.png

示例3, Function bind()

Function Borrowing 方法借用

With the bind() method, an object can borrow a method from another object.

Preserving this

Sometimes the bind() method has to be used to prevent losing this.

When a function is used as a callback, this is lost.

const person = {  
  firstName:"John",  
  lastName"Doe",  
  displayfunction () {  
    let x = document.getElementById("demo");  
    x.innerHTML = this.firstName + " " + this.lastName;  
  }  
}  
setTimeout(person.display3000);

回调函数是 person.display,它是一个方法,用于在 person 对象上显示名字。然而,在这种情况下,person.display 函数被传递给 setTimeout,并在延迟之后执行,this 的上下文会发生问题,导致 this 不再指向 person 对象。

setTimeout(callback, delay)

1、callback的核心机制概括为:

  • 将一个函数A作为参数传递给另一个函数B
  • 在B函数内部,在适当的时候调用传递进来的A函数
  • 这样就实现了在B函数内对A函数的调用

2、回调函数理解为代理函数、委托函数、中间函数。

  • 回调函数是一种将函数A作为参数传递给另一个函数B,在B函数内部调用A函数的编程方式。
  • 回调函数将一个函数作为参数传递给另一个函数,在外部函数内部调用这个传入的回调函数。这样就实现了在一个函数里面调用另一个函数。回调函数允许函数之间的代理调用关系。
// 代理函数,接受回调函数作为参数
function processRequest(data, callback) {
  // 模拟异步请求
  setTimeout(function() {
    console.log("处理请求...");
    // 在请求完成后调用回调函数
    callback(data);
  }, 1000);
}

// 回调函数,用于处理请求完成后的操作
function displayData(result) {
  console.log("显示数据:" + result);
}

// 调用代理函数,并传递回调函数
processRequest("这是一些数据", displayData);
/// 输出
// 处理请求...
// 显示数据:这是一些数据
  • processRequest 函数是一个代理函数,它接受一个回调函数作为参数,并模拟了一个异步请求的过程。当请求完成后,它会调用传入的回调函数 callback(data)
  • displayData 函数是回调函数,它用于处理请求完成后的操作,这里只是简单地显示数据。
  • 最后,我们调用 processRequest 函数,并传递数据和回调函数 displayDataprocessRequest 函数代理了请求的处理,并在请求完成后调用了回调函数。