call apply bind的作用及區別? 應用場景?

Du9191 發表於 2022-06-19

call、apply、bind方法的作用和區別:

這三個方法的作用都是改變函式的執行上下文,換句話說就是改變函式體內部的this指向,以此來擴充函式依賴的作用域

1.call

作用:用於改變方法內部的this指向

格式:xxx.call(物件名,引數1,引數2,...)  即:將 xxx 方法中的 this 指向 物件名

例子:未使用call方法前,test()中的this指向window,使用後指向obj物件

function test(a,b){
        console.log(this);
        console.log(a + b);
}
test(1,2);  //  window  3
var obj = {name:'lqs'};
window.test.call(obj,3,5);  //  {name:'lqs'} 8

2.apply

作用:和call方法一樣是修改內部的 this 指向的,區別在於apply的第二個引數必須是一個陣列(部署了Iterator介面的類陣列物件也是可以的)

格式:xxx.apply(物件名,[...]) 即:將 xxx 方法中的this 指向 物件名,陣列中的元素依次與方法的形參對應

例子:未使用apply方法前,test()中的this指向window,使用後指向obj物件

function test(a,b){
        console.log(this);
        console.log(a + b);
}
test(1,2);  //  window  3
var obj = {name:'lqs'};
window.test.call(obj,[3,5]);  //  {name:'lqs'} 8

3.bind

作用:也是用於改變this的指向

格式:xxx.bind(物件名,引數1,引數2,...)  即:將 xxx 方法中的this 指向 物件名,傳參與call一樣

例子:未使用bind方法前,foo()中的this指向window,使用後指向obj物件

 var obj = {key:"value"}
 var foo = function(){
    console.log(this)
 }
 foo.bind(obj)()  //  obj

區別:

三者的第一個引數都是this需要指向的物件,但在後續的引數上只有apply是接收一個陣列,call和bind用逗號分開

call和apply直接呼叫,返回的是一個值,而bind不直接呼叫,返回的是一個函式形式,執行:foo.bind(obj)()

應用場景:

通常情況下call用於物件的繼承,真偽陣列轉換、apply用於找出陣列中的最大值和最小值以及陣列合並、bind用於vue和react中改變函式this指向

物件繼承:

在建構函式中呼叫父建構函式,但是改變this指向,就可以繼承父屬性

 

function superClass () { 
    this.a = 1; 
    this.print = function () { console.log(this.a); } 
} 
function subClass () { 
    superClass.call(this);  // 執行superClass,並將superClass方法中的this指向subClass
    this.print(); 
}
subClass();

 

類陣列與真陣列的轉換:

類陣列:具有length屬性的物件,且鍵為數字或string型別的數字;例如:元素檢索 api 返回的都是類陣列

document.getElementsByTagNamedocument.querySelectorAll 等等。除了dom api中,常見的 function 中的 arguments 也是類陣列

陣列 ==> 陣列:

var arr = [1,3,5];
var obj = {};
[].push.apply(obj,arr);     // { 0:1, 1:3 , 2:5 , length:3 }

類陣列 ==> 真陣列:

ES5:call、apply、Array API

// 系統自帶類陣列物件
var divs = document.querySelectorAll('div');
// 自定義類陣列物件
var obj = {0:'lqs' , 1:18 , length:2};
var arr = [];   //  真陣列

// 在高階的瀏覽器中使用如下的方法是可以實現類陣列物件轉換為真陣列,但是在 IE8 及其以下是不行的
// [].push.apply(arr,divs);
// [].push.apply(arr,obj);
// 為了相容 IE8 及其以下的瀏覽器,需要使用陣列的 slice 方法
// 陣列的 slice 方法不傳遞引數的時候是將陣列中的元素依次遍歷然後放到一個 新的陣列 中原樣返回
var arr2 = [].slice.call(obj);
// 一切以陣列為輸入,並以陣列為輸出的API都可用來做陣列轉換
Array (借用 arguments)
Array.prototype.concat (借用 arguments)
Array.prototype.slice (借用 this)
Array.prototype.map (借用 this)
Array.prototype.filter (借用 this)
const arrayLike = {0: 3,1: 4,2: 5,length: 3}

Array.prototype.slice.call(arrayLike)

Array.apply(null, arrayLike)

Array.prototype.concat.apply([], arrayLike)

Array.prototype.slice.call(arrayLike)

Array.prototype.map.call(arrayLike, x => x)

Array.prototype.filter.call(arrayLike, x => 1)

ES6:Array.from()、... 擴充套件運算子

// Array.from();方法用於將類陣列物件和可遍歷(Iterator)物件轉換為真陣列
var obj = {0:'lqs' , 1:18 , length:2};
var arr = Array.from(obj)   // ['lqs',18]
// ... 擴充套件運算子
// 適用於 iterable 物件 [...doucmnet.querySelector('div')]
// 但在{length:3}這種情況下會丟擲異常
// Uncaught TypeError: object is not iterable (cannot read property Symperty Symbol(Symbol.iterator))[...{length:3}]

jQuery:.get() .toArray()和$makeArray(obj)

稀疏陣列:

使用Array(n) 將會建立一個稀疏陣列,為了節省空間,稀疏陣列內含非真實元素,在控制檯上將以empty顯示

如下:[,,,]與Array(3) 都將返回稀疏陣列

> [,,,][empty × 3]   > Array(3)[empty × 3]

當類陣列為 { length: 3 } 時,一切將類陣列做為 this 的方法將都返回稀疏陣列,而將類陣列做為 arguments 的方法將都返回密集陣列

陣列中最大最小值及陣列合並:

獲取陣列中最大、最小的一項

let max = Math.max.apply(null, array);

let min = Math.min.apply(null, array);

實現兩個陣列合並

let arr1 = [1, 2, 3];

let arr2 = [4, 5, 6];

Array.prototype.push.apply(arr1, arr2);

console.log(arr1); // [1, 2, 3, 4, 5, 6]

總結:

以上方法中靠譜的陣列轉換方法

Array.from(arrayLike)

Array.apply(null, arrayLike)

Array.prototype.concat.apply([], arrayLike)

需要考慮稀疏陣列轉化

Array.prototype.filter.call(divs, x => 1)

Array.prototype.map.call(arrayLike, x => x)

Array.prototype.filter.call(arrayLike, x => 1)

以下方法要注意是否是 iterable object

[...arrayLike]

 

參考:

https://www.cnblogs.com/deng-jie/p/15038342.html

https://wenku.baidu.com/view/533ab9c6514de518964bcf84b9d528ea80c72f54.html

https://wenku.baidu.com/view/bfd955c1514de518964bcf84b9d528ea81c72f77.html

https://blog.csdn.net/weixin_39828457/article/details/111701235