apply 、call 以及 bind 的使用和區別
阿新 • • 發佈:2020-12-01
## 一、被apply和call呼叫的函式中沒有傳遞引數
### (一)不傳引數
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122102630154.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
結果:
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122102610582.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
### (二)傳遞 null
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122103522795.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
結果:
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122103507444.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
>總結:
1.當使用 apply和 call去呼叫函式並且沒有傳遞引數時,前提這個函式中也沒有傳遞引數,我們發現 他們的列印結果和 this 指向是相同的 都是指向window 此時相當於 f1() 呼叫函式 就相當於 f1.apply() 和 f1.call()
2.當傳遞 null 的時候,他們的指向也是相同的 都是指向 window
此時相當於 f1() 呼叫函式 就相當於 f1.apply(null) 和 f1.call(null)
### (三)當傳遞一個具體物件時
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122103731855.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
結果:
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/2020112210380843.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
>我們發現 使用 `f1.apply(stu) ` 和 ` f1.call(stu)` 去呼叫函式的時候,this的指向發生了改變,不再是 window,而是 Object
## 二、被 apply和 call 呼叫的函式中有引數傳遞
### (一)apply和call不傳遞引數
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122104504304.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
結果:
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122104532114.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
>總結:
>apply和call沒有傳遞引數,所以沒有進行引數的運算,值是 NaN ,但是他們的this指向並沒有改變,仍然是 window
### (二)當傳遞null時
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122104745187.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
結果:
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122104734325.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
>總結:
與不傳引數的結果是一樣的,值是 NaN,並且this 指向沒有改變
### (三)當傳入一個具體物件時
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122105046939.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
結果:
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122105030765.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
>總結:
兩個方法傳入具體物件時,都改變了 this的指向,this 指向不是 window ,而是 Object
>思考:
兩者都傳入一個物件改變了 this 指向,但是如何去傳入引數進行函式的運算呢???
### (四)傳入多個引數
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122105502360.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
結果:
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122105447558.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
>總結:
1.apply和call傳入的第一個引數表示 this 指向的物件
2.apply和call可以傳遞多個引數,只是他們傳遞引數的方式不一樣
3.apply是以陣列的方式傳遞引數的
4.call是以引數列表的方式傳遞引數的,也就是通過一個一個的方式傳遞引數
### (五)改變this指向,獲取物件中的屬性值
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122110400673.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122110252203.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
>總結:
>1.f1()函式呼叫時,this的指向是window,而window中沒有定義age這個屬性值,所以是 undefined
>2.apply和call都改變了 this 的指向,this 指向了 stu ,stu這個物件中有 age 這個屬性值 ,所以輸出 age = 18
## 三、被apply和 call 呼叫的函式中有返回值
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122111037710.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122110900429.png#pic_center)
>總結:
>apply 和 call 都使用變數來接收函式的返回值
## 四、原型指向改變案例
```javascript
function Person(food) {
this.food = food
}
// 通過原型來新增方法
Person.prototype.eat = function (x, y) {
console.log('我好想吃 ---->' + this.food)
console.log(x + y)
}
var per = new Person('大豬蹄')
per.eat(100, 100)
//建立 stu 物件,並新增屬性和方法
console.log('============================')
function Student(food) {
this.food = food
}
Student.prototype.study = function () {
console.log('禿頭少女的日常操作,天天敲程式碼')
}
var stu = new Student('大雞腿')
//改變this指向,讓this指向 stu物件
//能呼叫 per物件中的方法
per.eat.apply(stu, [200, 200])
//也能呼叫自己的方法
stu.study()
```
結果:
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122113834558.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
## 五、總結apply與call
- apply 的使用方式
函式名字.apply (物件,[引數1,引數2,...])
方法名字.apply (物件,[引數1,引數2,...])
- call 的使用方式
函式名字.call (物件,引數1,引數2,...)
方法名字.call (物件,引數1,引數2,...)
- 作用:改變this 的指向
- 區別:引數傳遞的方式不一樣
- 使用場景:只要是想使用別的物件的方法,並且希望這個方法是當前物件自己的,那麼就可以使用 apply 或者 call 的方法 改變 this 的指向
## 六、bind 方法的使用
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122120112422.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
結果:
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122120140304.png#pic_center)
>我們發現,雖然使用了bind 方法,但是它並沒有輸出內容,所以,要用一個變數接收一下,然後再呼叫
>
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122120304590.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
結果:
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122120251346.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
還可以寫成:
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122121806802.png#pic_center)
## 七、bind方法的案例
```javascript
function Person(say){
this.say = say
}
Person.prototype.play = function(x,y){
console.log('做人嘛~~最重要的就是要開心吶!!' + this.say )
console.log(x+y)
}
var per = new Person('對呢對呢')
per.play(10,10)
//這是一條華麗的分割線
console.log('==============================================')
function Student(say){
this.say = say
}
Student.prototype.study = function(){
console.log('一根毛,兩根毛,頭上還有幾根毛')
}
var stu = new Student('撒花撒花')
//呼叫別人的方法
var ff = per.play.bind(stu)
ff(20,20)
//呼叫自己的方法
stu.study()
```
結果:
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20201122123430111.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1MTAzNjEy,size_16,color_FFFFFF,t_70#pic_center)
## 八、apply與call與bind之間的區別
**相同點:**
1. 他們的作用都是相同的:改變 this 的指向
2. 當他們不傳引數的時候,就跟直接呼叫函式或者方法的作用一樣,不改變this的指向
3. 當只傳入 null 的,與上面作用也是一樣,不改變this的指向
**不同點:**
1. apply 與 call 直接呼叫即可
2. bind 要使用變數接收一下,然後再呼叫
3. apply與call 是在呼叫的時候直接傳遞引數
4. bind 可以在用變數接收的時候傳遞引數,也可以在接收後在呼叫中傳遞引數
5. 傳遞引數的方式不一樣
- apply 的使用方式
函式名字.apply (物件,[引數1,引數2,...])
方法名字.apply (物件,[引數1,引數2,...])
- call 的使用方式
函式名字.call (物件,引數1,引數2,...)
方法名字.call (物件,引數1,引數2,...)
- bind 的使用方式:
函式名字.bind (物件,引數1,引數2,...)
函式名字. bind (物件),在呼叫時再傳遞引數
方法名字.bind (物件,引數1,引數2,...)
方法名字. bind (物件),在呼叫時再傳