JavaScript 解释call()、apply()和bind()方法

JavaScript 解释call()、apply()和bind()方法

在实现bind()、apply()和call()的polyfill之前,让我们先了解一下在JavaScript中polyfill的含义:

Polyfill: Polyfill是对我们的浏览器提供的功能进行实现的方法,但在其以前的版本中可能还不存在。

1. Bind()方法 bind()方法创建一个新的函数,并在调用该新函数时将 this 关键字设置为传递给bind方法的第一个参数。如果在bind方法之前传递了其他序列的参数作为新函数的参数进行调用。

语法:

bind(thisArg)
bind(thisArg, arg1, arg2, /* …, */ argN)
JavaScript

示例1: 首先,让我们看一下javascript提供的bind方法的实际输出:

JavaScript

let nameObj = { 
    name: "Tony"
} 
  
let PrintName = { 
    name: "steve", 
    sayHi: function () { 
  
        // Here "this" points to nameObj 
        console.log(this.name);  
    } 
} 
  
let HiFun = PrintName.sayHi.bind(nameObj); 
HiFun();
JavaScript

输出:

Tony
JavaScript

在这里我们有一个名为“PrintName”的对象,它有一个叫做sayHi的函数,它将打印我们在名为nameObj的对象中传递的人的名字。在这里,我们将nameObj与PrintName的sayHi函数绑定在一起,这样我们就可以在PrintName的sayHi函数中访问nameObj。 this 在PrintName的sayHi函数中,bind方法返回一个函数,这样当我们调用这个函数时,sayHi将有 this 作为nameObj。

例如2: 现在让我们编写我们自己的bind polyfill。我们将使用上面示例中Object类的原型来实现我们的bind polyfill:

JavaScript

let nameObj = { 
    name: "Tony"
} 
  
let PrintName = { 
    name: "steve", 
    sayHi: function () { 
        console.log(this.name); 
    } 
} 
  
Object.prototype.MyBind = function (bindObj) { 
  
    // Here "this" will be sayHi function 
    bindObj.myMethod = this; 
    return function () { 
        bindObj.myMethod(); 
    } 
} 
let HiFun = PrintName.sayHi.MyBind(nameObj); 
HiFun();
JavaScript

输出:

Tony
JavaScript

解释: 因此,我们的 bind polyfill 给出了与之前的 bind 方法相同的输出。现在让我们看看我们实际上在做什么。在 Object 原型中,我们附加了我们的 MyBind 函数。我们的 MyBind 函数以一个对象(在我们的例子中是 nameObj)作为参数,我们希望将其与我们的 PrintName sayHi 函数绑定在一起。

现在,让我们只专注于代码的这一部分(Object.prototype.MyBind):

Object.prototype.MyBind = function (bindObj) {

   // Here "this" will be sayHi function
   bindObj.myMethod = this;
   return function () {
       bindObj.myMethod();
   }
}
JavaScript

在这里,我们有一个名为MyBind的函数,其中一个参数是bindObj,在我们的例子中,bindObj是nameObj。那么实际上我们在做什么呢?我们在nameObj中添加了myMethod,并且在myMethod中存储了 this 。在我们的例子中, this 就是sayHi函数。

例子3: 让我们先看看在运行“bindObj.myMethod=this”这行代码之后,我们的bindObj是什么样子。

Javascript

let nameObj={ 
    name:"Tony"
} 
  
let PrintName={ 
    name:"steve", 
    sayHi:function(){ 
        console.log(this.name); 
    } 
} 
  
Object.prototype.MyBind=function(bindObj) { 
  
    // Here "this" will be sayHi function 
    bindObj.myMethod=this;  
    console.log("bindObj ->",bindObj); 
    return function(){ 
        bindObj.myMethod(); 
    } 
} 
let HiFun=PrintName.sayHi.MyBind(nameObj);
JavaScript

输出:

bindObj -> { name: 'Tony', myMethod: [Function: sayHi] }
JavaScript

在这里,我没有调用HiFun(),因为我们只想看看在运行“bindObj.myMethod=this”之后bindObj的样子。我们可以清楚地看到在bindObj中有一个名为myMethod的函数,它具有sayHi函数。我们还可以看到在运行“bindObj.myMethod=this”行后,bindObj的图示表示。如果我们不能理解上面的输出结果,可以查看下面的代码:

let bindObj = {
   name: "Tony",
   myMethod: function sayHi() {

       // Here 'this' will be bindObj
       console.log(this.name);
   }
}
JavaScript

所以,我们为什么要做这些呢?我们想要在PrintName的sayHi函数中访问nameObj。我们想要编写一个bind的polyfill。所以我们不是将nameObj附加到sayHi函数中的this上。我们所做的是在nameObj本身中创建一个myMethod,在myMethod中添加PrintName的sayHi函数,然后在MyBind中返回一个函数,其中调用了bindObj.MyMethod(),这实际上意味着调用nameObj.myMethod(),因此当在nameObj内部调用sayHi函数时,它将包含在自身的this中,并且会打印出nameObj中的name,即Tony。

示例4: 让我们看一个更多的bind polyfill的例子,当参数被传递给我们的MyBind方法时:

JavaScript

let nameObj = { 
    name: "Tony"
} 
  
let PrintName = { 
    name: "steve", 
    sayHi: function (age) { 
        console.log(this.name + " age is " + age); 
    } 
} 
  
Object.prototype.MyBind = function (bindObj, ...args) { 
    bindObj.myMethod = this; 
    return function () { 
        bindObj.myMethod(...args); 
    } 
} 
let HiFun = PrintName.sayHi.MyBind(nameObj, 42); 
HiFun();
JavaScript

输出:

Tony age is 42
JavaScript

在这里,“…args”是将n个输入放入javascript数组中的剩余参数。 在这里,“…args”将是[42]。

call() 方法: call() 方法直接调用函数,并将 this 设置为传递给call方法的第一个参数。如果在call方法之前传递了其他序列的参数,则它们将作为函数的参数传递。

语法:

call(objectInstance)
call(objectInstance, arg1, /* …, */ argN)
JavaScript

示例1: 在实现自己的调用填充之前,让我们先看一下javascript提供的调用方法

Javascript

let nameObj = { 
    name: "Tony"
} 
  
let PrintName = { 
    name: "steve", 
    sayHi: function (age) { 
        console.log(this.name + " age is " + age); 
    } 
} 
  
PrintName.sayHi.call(nameObj, 42);
JavaScript

输出:

Tony age is 42
JavaScript

注意: call方法不返回新的函数。

示例2: 现在让我们自己编写call的填充方法:

Javascript

let nameObj = { 
    name: "Tony"
} 
  
let PrintName = { 
    name: "steve", 
    sayHi: function (age) { 
        console.log(this.name + " age is " + age); 
    } 
} 
  
Object.prototype.MyCall = function (bindObj, ...args) { 
    bindObj.myMethod = this; 
  
    bindObj.myMethod(...args); 
  
} 
PrintName.sayHi.MyCall(nameObj, 42);
JavaScript

输出:

Tony age is 42
JavaScript

这与MyBind函数完全相同,但唯一的区别是它不返回一个函数,因为由javascript提供的调用方法也不返回一个方法。因此,在实现call的polyfill时,我们还需要记住这一点。

Apply()方法: apply()方法直接调用函数,并将 this 设置为传递给apply方法的第一个参数,如果其他参数以数组形式传递给call方法,则它们作为参数传递给函数。

语法:

apply(objectInstance)
apply(objectInstance, argsArray)
JavaScript

示例1: 最后一次让我们看一下Javascript提供的apply方法:

Javascript

let nameObj = { 
    name: "Tony"
} 
  
let PrintName = { 
    name: "steve", 
    sayHi: function (...age) { 
        console.log(this.name + " age is " + age); 
    } 
} 
PrintName.sayHi.apply(nameObj, [42]);
JavaScript

输出:

Tony age is 42
JavaScript

在apply方法中,我们以数组形式传递参数,这是call和apply之间的主要区别。

示例2: 现在让我们编写我们的最终polyfill,即apply polyfill:

JavaScript

let nameObj = { 
    name: "Tony"
} 
  
let PrintName = { 
    name: "steve", 
    sayHi: function (age) { 
        console.log(this.name + " age is " + age); 
    } 
} 
  
Object.prototype.MyApply = function (bindObj, args) { 
    bindObj.myMethod = this; 
  
    bindObj.myMethod(...args); 
  
} 
PrintName.sayHi.MyApply(nameObj, [42]);
JavaScript

输出:

Tony age is 42
JavaScript

现在在这个应用填充中,我们只需要将一个数组作为参数传递。其余部分与调用填充是相同的。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程

登录

注册