bind,call,以及apply的理解與使用
技術標籤:javascript
bind的理解:
官方原話/作用:
bind() 方法建立一個新的函式,在 bind() 被呼叫時,
這個新函式的 this 被指定為 bind() 的第一個引數,而其餘引數將作為新函式的引數,
供呼叫時使用。
返回值:返回一個原函式的"拷貝",並擁有指定的 this 值和初始引數。
//例子
function demoBind(x){
console.log('我是第一個demoBind===>',this,x.into);
}
demoBind ({into:"未繫結bind"}); //window,未繫結bind
console.log('-------------------->分割線');
/*
利用bind建立一個“新的函式”
const newBind = demoBind.bind("這個新函式的 this 被指定為 bind() 的第一個引數","其餘引數將作為新函式的引數,供呼叫時使用")
# 這裡也就是說bind的第一個引數將作為新函式的this指向,而bind的其他引數將是新函式的其他引數、
下方例子(拷貝場景):
*/
const newBind = demoBind.bind({_this:1},{into:"繫結bind"});
newBind(); //{_this:1},繫結bind
/*
應用場景:需要讓this指定自己需要物件的this就可以使用bind方法
*/
var application = {
b: function() {
console.log('b的this指向不出意外是application===>',this); // {c: "hello", b: ƒ}
const func =function(){
/*
在不使用bind的情況下,函式在獨立呼叫時,函式內部的this是指向window的
console.log(this); // window
*/
/*
假設我在func裡面需要得到c定義的hello,那麼在這裡就能使用bind來指定this
*/
console.log(this); //使用了bind之後這裡的this就指向了{c: "hello", b: ƒ}
}.bind(this) //bind的第一個引數將作為新函式的this指向,我這裡傳入b的this指向也就是application,所以func的this也就指向了application
func();
},
c: 'hello'
}
application.b();
/*
- 引用與拷貝的區別
引用:二者的引用是同一個物件,並沒有創建出一個新的物件
因為是同一個物件的引用,所以兩者改一個,另一個物件的值也隨之改變
拷貝:簡單來講就是會建立一個新的物件,改變新的物件的值並不會影響到原物件
*/
call的理解:
作用:
call() 可以允許為不同的物件分配和呼叫屬於一個物件的函式/方法/屬性。
call() 提供新的 this 值給當前呼叫的函式/方法。你可以使用 call 來實現繼承:寫一個方法,然後 讓另外一個新的物件來繼承它(而不是在新物件中再寫一次這個方法)。
官方原話:
call() 方法使用一個指定的 this 值和單獨給出的一個或多個引數來呼叫一個函式
語法引數:function.call(thisArg, arg1, arg2, …)
thisArg:
可選的。在 function 函式執行時使用的 this 值。
請注意,this可能不是該方法看到的實際值:如果這個函式處於非嚴格模式下,
則指定為 null 或 undefined 時會自動替換為指向全域性物件,原始值會被包裝。
arg1, arg2, …:
指定的引數列表。
返回值: 得到使用呼叫者提供的 this 值和引數呼叫該函式的返回值。若該方法沒有返回值,則返回 undefined
//'use strict'; 開啟嚴格模式
//例子
function Person(...x) {
console.log(this,x);
}
Person("張三","張三"); //window,["張三","張三"]
//在thisArg指定為null或undefined的情況下會自動替換為指向全域性物件也就是window
const _call = Person.call(null,"張三","張三","張三") //window,["張三","張三","張三"]
//person函式沒有返回值,_call為undefined
console.log(_call);
//應用例子
//呼叫父建構函式的 call 方法來實現繼承
//假設這是一個父物件
function Product(name, price) {
console.log('Product====>',this); //Food
this.name = name;
this.price = price;
}
function Food(name, price) {
/*
這裡把this分配到Product裡面之後,Product的this就指向了Food
*/
Product.call(this, name, price); //call() 可以允許為不同的物件分配和呼叫屬於一個物件的函式/方法/屬性。
this.category = 'food';
this.log =function(){
console.log(this);//Food {name: "feta", price: 5, category: "food", log: ƒ}
console.log(name,price,this.category); //feta 5 food
}
}
function Toy(name, price) {
Product.call(this, name, price);
this.category = 'toy';
}
var cheese = new Food('feta', 5);
cheese.log();
var fun = new Toy('robot', 40);
/*
要知道如果這個函式處於非嚴格模式下,
則指定為 null 或 undefined 時會自動替換為指向全域性物件,原始值會被包裝。
但是在嚴格模式下,this 的值將會是 undefined
例子:
*/
var sData = 'Wisen';
function display() {
console.log(this);// undefined
console.log('sData value is %s ', this.sData); //報錯
}
display.call();
apply的理解:
作用:
可以用 apply 將陣列各項新增到另一個數組
官方原話:
apply() 方法呼叫一個具有給定this值的函式,以及以“一個數組(或類陣列物件)”的形式提供的引數
thisArg:
同call()的thisArg
argsArray:
可選的。一個數組或者類陣列物件,其中的陣列元素將作為單獨的引數傳給 func 函式。
如果該引數的值為 null 或 undefined,則表示不需要傳入任何引數。
從ECMAScript 5 開始可以使用類陣列物件。
返回值:呼叫有指定this值和引數的函式的結果 (大概意思同call()方法)
function PersonApply(...x) {
console.log(this,x);
}
PersonApply("張三","張三"); //window,["張三","張三"]
//在thisArg指定為null或undefined的情況下會自動替換為指向全域性物件也就是window
const _apply = PersonApply.apply({a:1},["張三","張三","張三"])//{a:1},["張三","張三","張三"]
console.log(_apply); //沒有返回值 返回undefined
//作用同call
//用 apply 將陣列各項新增到另一個數組
/*
官方例子原話:
我們可以使用push將元素追加到陣列中。由於push接受可變數量的引數,所以也可以一次追加多個元素。
但是,如果push的引數是陣列,它會將該陣列作為單個元素新增,而不是將這個陣列內的每個元素新增進去,
因此我們最終會得到一個數組內的陣列。如果不想這樣呢?concat符合我們的需求,
但它並不是將元素新增到現有陣列,而是建立並返回一個新陣列。
然而我們需要將元素追加到現有陣列......那麼怎麼做好?難道要寫一個迴圈嗎?別當然不是!
apply正派上用場
由於push可以一次追加多個元素然後在利用apply的特點:
apply()會將引數陣列轉換為一個接一個的引數方式傳遞給方法
類似一個迴圈,在迴圈apply的陣列引數,把它拆成一個一個的item
*/
var array = ['a', 'b'];
var elements = [0, 1, 2];
//array作為this的指向
array.push.apply(array, elements);
console.info(array); // ["a", "b", 0, 1, 2]
/*
concat也是可以將兩個數組合併成為一個數組,但是它並不是將元素新增到現有陣列,而是建立並返回一個新陣列
*/
總結:
1,call方法和apply方法是函式的引用
2,bind方法是函式的拷貝
3,this指向:
- call,bind,apply的第一個引數都是this的指向,並且第一個引數如果為null或undefined的話都會預設指向全域性物件
4,引數:
- call()方法以及bind()接受的是引數列表,而apply()方法接受的是一個引數陣列
5,返回值:
- bind返回一個原函式的"拷貝",並擁有指定的 this 值和初始引數
- call方法和apply方法得到使用呼叫者提供的 this 值和引數呼叫該函式的返回值。若該方法沒有返回值,則返回 undefined
6,call()和apply()會直接呼叫函式,bind()不會
7,apply()會將引數陣列轉換為一個接一個的引數方式傳遞給方法
/*
類似一個迴圈,在迴圈apply的陣列引數,把它拆成一個一個的item
*/