本文的目的是帮助JavaScript初学者更好地理解"bind"方法,并帮助那些对"this"的理解不太清楚的人更好地理解"bind"方法和"this"之间的关系。特别是对于那些对"this"的理解不太清楚的人是有所帮助的。在深入学习"bind"方法之前,先查看一下MDN Web Docs中的说明。"bind"方法可以生成一个新的函数,当新函数被调用时,"this"关键字将被设置为指定的值。如果您不理解"bind"方法,即使阅读了上述说明,也可能不知所云。
目录
- 1 this 使用
- 2 如何使用bind
- 3 箭头函数的bind使用
- 4 Fetch 函数的使用
- 5 call函数与bind函数的区别
- apply函数与call函数的区别
但是,请先记住"bind"与"this"有关,使用"bind"可以从一个函数中创建一个新函数。接下来我们会通过简单的介绍和示例来解释"bind"和"this"的含义及使用场景。同时,在本文中,我们会尽可能避免使用难以理解的词汇,以便更容易理解。除了"bind"方法,"call"函数和"apply"函数也与"this"密切相关,因此我们也会在本文中介绍它们。通过阅读本文,您可以深入了解这三个函数以及"this"关键字的概念。
JavaScript 特性 this与“bind“和“call“,“apply“的理解
JavaScript 特性 Promise 函数
JavaScript 特性 map、forEach、filter 和 find 与箭头函数的使用
JavaScript 特性 Destructuring 语法
JavaScript 特性 Proxy(代理)和Reflect(反射)
JavaScript 特性 Object.assign与Getter,Setters 和 definePropert
JavaScript 中使用 XMLHttpRequest
1 this 使用
在使用bind方法之前,我们需要先理解this关键字在JavaScript中的作用。下面通过一个例子来说明。
我们定义了一个名为myButton的对象,该对象有content和click属性。click属性是一个方法,当该方法被调用时,会打印出this对象以及一个字符串。
const myButton = {
content: 'OK',
click() {
console.log(this)
alert(this.content + ' clicked');
}
};
myButton.click();
=========== 打印内容 ==============
// this=myButton this关键字指向调用该方法的对象
{ content: 'OK', click: [Function: click] }
OK clicked
我们调用myButton的click方法,会发现this对象指向了myButton对象。这是因为在click方法中,this关键字指向调用该方法的对象,即myButton对象。
接下来,我们添加了一个名为yourButton的属性,它也有content和click属性。与myButton不同的是,yourButton的click方法中打印的this对象指向了yourButton对象。这是因为在click方法中,this关键字指向调用该方法的对象,即yourButton对象。
const myButton = {
content: 'OK',
click() {
console.log(this)
alert(this.content + ' clicked')
},
yourButton: {
content: 'No',
click() {
console.log(this)
alert(this.content + ' clicked your button')
}
}
}
myButton.click();
myButton.yourButton.click();
=========== myButton.click() 打印内容 ==============
{
content: 'OK',
click: [Function: click],
yourButton: { content: 'No', click: [Function: click] }
}
OK clicked
=========== myButton.yourButton.click() 打印内容 ==============
{ content: 'No', click: [Function: click] }
No clicked your button
当执行myButton.click()时,this引用了左侧的myButton对象,与前面的示例类似。而当执行myButton.yourButton.click()时,this引用了click左侧的yourButton对象,这一点也得到了确认。
this对象引用赋值
我们来定义一个looseClick这个引用变量,将myButton.click赋值给looseClick对象,并且执行looseClick对象。
const myButton = {
content: 'OK',
click() {
console.log(this)
alert(this.content + ' clicked');
}
};
const looseClick = myButton.click;
looseClick();
=========== 打印内容 ==============
Object [global]
undefine clicked
大家可能会认为产生和前面程序一样的结果,但是在执行looseClick时,this.content是undefined的,因为this指的是全局对象(浏览器中的Window对象)而不是myButton。大家可能认为 Button.click() 和 looseClick() 在代码中做同样的事情,但是大家必须意识到它们在 JavaScript 中是不同的两个对象引用。从我们目前的例子中可以看出,this不是由被执行对象的内容决定的,而是由它如何执行决定的。也就是说,this的引用不是由myButton的内容决定的。
2 如何使用bind
通过前面的例子,我们已经了解了在 JavaScript 中 this 的使用,以及在不同情况下 this 的指向。现在我们将通过使用 bind 方法来更加显式地指定 this 的参照对象。在之前的例子中,我们发现如果我们直接调用 myButton.click(),this 指向的是 myButton 对象,而如果使用 myButton.yourButton.click(),则 this 指向的是 yourButton 对象。为了更加精确地指定 this 的参照对象,我们可以使用 bind 方法。
使用 bind 方法,我们可以显式地指定 this 的参照对象。例如,在下面的代码中,我们将 myButton 对象作为参数传递给 bind 方法,这样在执行 boundClick 函数时,this 将指向 myButton 对象:
const myButton = {
content: 'OK',
click() {
console.log(this)
alert(this.content + ' clicked');
}
};
const boundClick = myButton.click.bind(myButton);
boundClick();
=========== 打印内容 ==============
//从运行结果,你应该明白bind是和this相关的,你可以通过bind设置this中指定的对象
{ content: 'OK', click: [Function: click] }
OK clicked
在这个例子中,我们使用 myButton 对象作为参数来调用 bind 方法,从而将 this 指定为 myButton 对象。因此,当我们调用 boundClick 函数时,this 指向的就是 myButton 对象。这与我们最初的代码的结果是相同的。到目前为止,我们已经学习了如何使用 bind 方法来指定 this 的参照对象。我们可以看到,通过调用 bind 方法并传递一个对象作为参数,我们可以指定 this 的参照对象。
当我们查看代码时,可能会发现 myButton.click 方法使用了 bind 方法,并且绑定了 myButton 对象作为参数。这可能会引起一个疑问,即是否必须使用相同的对象来调用 bind 方法。为了回答这个问题,我们可以创建一个新的对象 yourButton,然后将其作为参数传递给 bind 方法,如下所示:
const myButton = {
content: 'OK',
click() {
console.log(this)
alert(this.content + ' clicked');
}
};
const yourButton = {
content: 'No'
}
const boundClick = myButton.click.bind(yourButton);
boundClick();
=========== 打印内容 ==============
{ content: 'No' }
No clicked
=========== 对应关系 ==============
myButton.click.bind(yourButton);
| |
click() { |
console.log(this)<-| bind指定this是 yourButton{content:'No'}
alert(this.content + ' clicked');
}
在这个例子中,我们使用 yourButton 对象作为参数来调用 bind 方法,从而将 this 指定为 yourButton 对象。当我们调用 boundClick 函数时,this 指向的就是 yourButton 对象。这表明,我们可以在不同的对象之间使用 bind 方法来指定 this 的参照对象。
总之,通过使用 bind 方法,我们可以显式地指定 this 的参照对象,从而更加精确地控制代码的执行结果。上述的例子有助于更好地理解bind方法。
在下面的例子中,我们将继续使用bind方法来演示它的设置方式。首先定义了一个greeting函数,并在执行bind前后分别调用了greeting函数。在执行bind方法后,我们创建了一个新函数new_greeting并执行它。在执行greeting函数时,由于没有指定this,因此this引用的是全局对象。这意味着this.name会返回undefined。然后,通过将object对象作为参数传递给bind方法,我们将this的引用更改为object对象。这样,this引用的就是object对象,因此我们可以成功输出this.name的值为"zht"。
const greeting = function() {
console.log(this)
console.log(this.name);
}
greeting(); // 没有绑定时,this指向全局对象,输出:Object [global] 和 undefined
const object = { name: "zht" };
const new_greeting = greeting.bind(object);
new_greeting(); // 绑定后,this指向绑定的对象,输出:{ name: 'zht' } 和 zht
通过使用bind方法创建了新的函数new_greeting,这样我们就可以更好地理解MDN Web Docs上的解释:“bind方法生成一个新的函数,该函数在被调用时,将this关键字设置为指定的值。”尽管该解释并不十分明确,但我们至少可以大概理解bind方法的作用了。
在JavaScript中,bind函数不仅可以设置this对象,还可以设置其他参数。
我们来看一个例子,通过设置bind函数的第二个和第三个参数,将这些参数传递给函数的形参进行验证。首先,我们定义了一个名为greeting的函数,它接受age和height两个参数,并在控制台输出一条带有姓名、年龄和身高的消息。接下来,我们创建了一个名为object的对象,其中包含一个name属性。然后,我们使用bind函数将greeting函数绑定到object对象,并传递了值为30和’180cm’的参数。最后,我们调用新创建的函数new_greeting。
// 创建一个函数greeting,它接受age和height两个参数
const greeting = function(age, height){
console.log(`${this.name}的年龄是${age},身高是${height}。`);
}
// 创建一个名为object的对象,它有一个name属性
const object = {
name: 'zhtbs',
}
// 使用bind函数将greeting函数绑定到object对象,并传递参数30和'180cm'
const new_greeting = greeting.bind(object, 30, '180cm');
new_greeting();
=========== 打印内容 ==============
zhtbs的年龄是30,身高是180cm。
执行上述代码后,参数30和’180cm’将被传递给greeting函数的age和height参数。
3 箭头函数的bind使用
在之前的部分,我们使用了普通函数来展示 bind
方法的用法,现在我们来尝试使用箭头函数 greeting
来执行同样的操作。需要注意的是,箭头函数不仅仅是普通函数的一种简写方式,它们还有其他的差别,需要好好理解。
const greeting = () => {
console.log(this)
console.log(this.name);
}
greeting()
const object = {name:"zht"}
const new_greeting = greeting.bind(object)
new_greeting()
=========== 打印内容 ==============
{}
undefined
{}
undefined
很多人可能认为,即使将普通函数 greeting
改写成箭头函数,结果仍然相同。但实际上,在箭头函数中使用 bind
方法无法改变 this
的指向。无论是否绑定,结果都相同。因为箭头函数中的 this
是指向自身的,所以会显示一个空的对象 {}
。
由于箭头函数中的 this
引用了 greeting
函数本身,所以我们可以在 greeting
函数内部添加一个 name
属性。
const greeting = () => {
this.name = 'kaimi'
console.log(this)
console.log(this.name);
}
greeting()
const object = {name:"zht"}
const new_greeting = greeting.bind(object)
new_greeting()
=========== greeting()打印内容 ==============
{ name: 'kaimi' }
kaimi
=========== new_greeting()打印内容 ==============
{ name: 'kaimi' }
kaimi
因为 this
指向了自身,所以无论是否使用 bind
方法,在 greeting
函数内部设置的 name
属性值 kaimi 都会被显示出来,结果是相同的。如果在编写箭头函数时遇到this
是 undefined
的时候请记住bind
方法无法改变 this
的指向。
4 Fetch 函数的使用
现在你已经开始了解 bind 方法是什么了。在以下的文章中,我们将讨论JavaScript中的bind方法,以及在使用fetch函数获取数据时如何使用它。假设我们有一个ourUsers对象,其中有一个getUsers方法,我们希望通过调用fetch方法从外部获取用户信息并将其保存在一个名为users的数组中。以下是一个使用fetch方法的示例代码,我们想要确定在此示例中的this关键字是什么。
const ourUsers = {
users: [],
getUsers() {
fetch('https://jsonplaceholder.typicode.com/users')
.then(function (response) {
return response.json();
})
.then(function (users) {
this.users = users;
console.log(this)
})
}
}
ourUsers.getUsers()
当我们运行此代码时,将得到以下结果。在这种情况下,this不是ourUsers对象,而是全局对象(在浏览器中是Window对象),因此获取到的数据将保存在全局对象的users中。
如果将显示的 Window 对象进一步展开,您可以在各种属性中找到用户。
我们可以使用bind方法来指定this(即ourUsers对象),以便将数据保存在ourUsers的users中。
const ourUsers = {
users: [],
getUsers() {
fetch('https://jsonplaceholder.typicode.com/users')
.then(function (response) {
return response.json();
})
.then(function (users) {
this.users = users;
console.log(this)
}.bind(this)) //使用bind方法
}
}
ourUsers.getUsers()
通过使用bind方法,this关键字将引用ourUsers对象,从而使数据保存在ourUsers的users中。在浏览器中可以看到这会它没有使用全局变量。
我们也可以使用箭头函数来达到相同的效果,这样代码也会更加简洁。
const ourUsers = {
users: [],
getUsers() {
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => response.json())
.then(users => {
this.users = users;
console.log(this)
})
}
}
ourUsers.getUsers();
如果我们想使用async和await来获取数据,则this关键字也将与箭头函数达到相同的结果。
const ourUsers = {
users: [],
async getUsers() {
const res = await fetch('https://jsonplaceholder.typicode.com/users')
this.users = await res.json();
console.log(this)
}
}
ourUsers.getUsers()
我们已经使用三个简单的例子来说明了bind方法。虽然可能还没有完全理解bind方法,但通过这些例子,我们可以更好地理解this关键字以及如何通过bind方法来指定this。如果在使用this时遇到问题,可以参考这些例子来确定this引用的是什么。
5 call函数与bind函数的区别
call函数和bind函数的区别在于它们的使用方式和功能。在前面的讲解中,我们已经了解了bind函数的用法和功能。现在我们来看一下call函数,call函数的语法如下:call(thisArg, arg1, arg2)。第一个参数是this对象,后续的参数是传递给函数的参数。你可能会注意到,这与bind函数的形式非常相似。
那么call函数和bind函数有什么不同呢?在下面的例子中我们将介绍它们在使用的时候具体区别。具体来说,我们使用bind函数将myButton.click函数绑定到myButton对象,并将其保存在boundClick变量中,然后调用boundClick函数。
const myButton = {
content: 'OK',
click() {
console.log(this);
console.log(this.content + ' clicked');
},
};
const boundClick = myButton.click.bind(myButton);
boundClick();
注意,我们在调用函数时使用了括号()。
而对于call函数,我们直接执行函数,而不是创建一个新的函数。与上述代码相比,区别变得明显。让我们验证一下。
const myButton = {
content: 'OK',
click() {
console.log(this);
console.log(this.content + ' clicked');
},
};
//
myButton.click.call(myButton);
=========== 打印内容 ==============
{ content: 'OK', click: [Function: click] }
OK clicked
结果与使用bind函数时的结果相同。
请注意,调用函数时使用了call函数,并传递了参数30和’180cm’。与之前使用bind函数的代码进行比较,你会发现它们的区别。对于bind函数的使用,我们的代码如下:
const greeting = function(age, height){
console.log(`${this.name}的年龄是${age},身高是${height}。`);
}
const object = {
name: 'zhtbs',
}
const new_greeting = greeting.bind(object, 30, '180cm');
//call函数和bind函数之间的区别在于返回值bind使用函数(),call直接函数进行运行
new_greeting();
greeting.call(object, 30, '180cm'); // 使用call函数
=========== 打印内容 ==============
zhtbs的年龄是30,身高是180cm。
zhtbs的年龄是30,身高是180cm。
区别在于它们的执行方式和返回值:
-
执行方式:
-
bind函数:bind函数会创建一个新的函数,并将绑定了指定this值和参数的函数返回,不会立即执行原函数。返回的新函数可以稍后再调用。
-
call函数:call函数会立即执行原函数,并且可以指定this值和参数,不会创建新的函数。
-
-
返回值:
- bind函数:bind函数返回一个绑定了指定this值和参数的新函数。你可以将其保存在变量中,并稍后再调用。
- call函数:call函数会立即执行原函数,并返回执行结果。不会返回一个新的函数。
在实际使用中,选择使用bind函数还是call函数取决于你的需求。如果你需要延迟执行函数或者将其作为回调函数传递给其他函数,你可以使用bind函数来创建一个新的函数,并在需要的时候再调用它。而如果你想立即执行函数并传递指定的this值和参数,你可以使用call函数。
需要注意的是,bind函数和call函数都是函数的方法,可以在函数对象上直接调用。它们都用于改变函数内部的this指向,使得函数在执行时的上下文环境发生变化。
apply函数与call函数的区别
apply函数与call函数的功能非常相似,它们都可以替换bind函数来使用。apply函数与call函数的区别在于参数的传递方式,通过下面的例子来介绍它们的区别。
const greeting = function(age, height){
console.log(`${this.name}的年龄是${age},身高是${height}。`);
}
const object = {
name: 'zhtbs',
}
greeting.apply(object, [30, '180cm']);
=========== 打印内容 ==============
zhtbs的年龄是30,身高是180cm。
- 参数传递方式:
- apply函数:apply函数接受两个参数,第一个参数是要绑定的this值,第二个参数是一个数组或类数组对象,其中包含要传递给函数的参数。这意味着你可以通过数组一次性传递多个参数给函数。
- call函数:call函数接受的参数是一个个单独的值,按顺序依次传递给函数。
- 使用方式:
- apply函数:apply函数会立即执行原函数,并且可以指定this值和一个数组参数。它将数组中的元素作为单独的参数传递给函数,可以适用于需要一次性传递多个参数的情况。
- call函数:call函数也会立即执行原函数,并且可以指定this值和一个或多个单独的参数。它将每个参数作为单独的参数传递给函数,适用于需要单独传递参数的情况。
在实际使用中,你可以根据参数的形式和传递方式选择使用apply函数或call函数。如果你已经有一个数组或类数组对象,且想将其作为参数传递给函数,那么可以使用apply函数。而如果你已经有一系列单独的参数,想一个个传递给函数,那么可以使用call函数。
需要注意的是,apply函数和call函数都是函数的方法,可以在函数对象上直接调用。它们都用于改变函数内部的this指向,并在执行时传递参数。
我们将通过一个名为add的函数来演示使用bind、call和apply来执行函数的示例。首先,我们定义了一个名为add的函数,它接受两个参数a和b,并将它们相加后打印出结果。
function add(a, b) {
console.log(a + b);
}
add(1, 2);
//使用bind函数时,我们传入null作为this值,然后传入1和2作为参数,最后通过调用返回的绑定函数来执行add函数。
add.bind(null, 1, 2)();
//使用call函数时,同样传入null作为this值,然后依次传入1和2作为参数,直接调用add函数。
add.call(null, 1, 2);
//使用apply函数时,同样传入null作为this值,然后将参数以数组的形式传入,直接调用add函数。
add.apply(null, [1, 2]);
虽然我们使用了非常简单的代码示例,但是通过本文,我们希望您能够了解bind函数、this关键字、call函数和apply函数是什么,以及如何使用它们