知道了js中的this的具體用法之后譬巫,感覺還是總結(jié)一下bind call apply的使用吧,算是一個知識整合的過程嘿嘿~~
這三個堪稱js中的神器,可以改變this的指向吁断,實現(xiàn)函數(shù)的“借用”僻他。畢竟js還是挺悶騷的萧朝,動不動就出現(xiàn)函數(shù)執(zhí)行環(huán)境的改變,所以我們需要強行把this的指向重新掰過來鹿蜀,這個時候就需要用到這個神器了箕慧。
- bind 的使用;
- call和apply的使用茴恰;
- apply的一點使用小技巧(參數(shù)為數(shù)組颠焦,好好利用)
js中的this很重要(可以先看一下這一篇):http://www.reibang.com/p/adaf787a0d4d#
bind
1 bind 可以設置函數(shù)調(diào)用的this指向
?var user = {
data :[
{name:"T. Woods", age:37},
{name:"P. Mickelson", age:43}
],
clickHandler:function (event) {
var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1?
?
//隨機生成一個數(shù),來調(diào)用data
$ ("input").val (this.data[randomNum].name + " " + this.data[randomNum].age);
}
?
}
?// 給按鈕添加點擊事件
$ ("button").click (user.clickHandler);
如果看過前面的this的文章往枣,應該知道這樣調(diào)用伐庭,其實this不再指向user粉渠,而是指向 $ ("button").
。所以可以借用bind更改圾另;
$ ("button").click (user.clickHandler);
更改如下(此時this就重新指向了user了)
$ ("button").click (user.clickHandler.bind (user));
2 bind可以借用函數(shù)
var user = {
// local data variable?
data :[
{name:"T. Woods", age:37},
{name:"P. Mickelson", age:43}
],
showData:function (event) {
var randomNum = ((Math.random () * 2 | 0) + 1) - 1; // random number between 0 and 1?
?
console.log (this.data[randomNum].name + " " + this.data[randomNum].age);
}
?
}
var cars = {
data:[
{name:"Honda Accord", age:14},
{name:"Tesla Model S", age:2}
]
?
}
?
// 我們可以借用我們這個例子中user的方法
//現(xiàn)在我們可以使用bind來將this的指向更改為cars霸株,函數(shù)將會調(diào)用里面的方法
cars.showData = user.showData.bind (cars);
cars.showData (); // Honda Accord 14?
2 call 和 apply的使用
相同點:
call和apply都可以修改this的指向,第一個參數(shù)是要引用的對象集乔,第二個參數(shù)是要傳進函數(shù)的變量不同點:
call的變量參數(shù)是一個個參數(shù)去件;
apply的變量參數(shù)是數(shù)組;
call和bind 都可以設置 this
// 設置一個全局變量
var avgScore = "global avgScore";
?
//全局函數(shù)
function avg (arrayOfScores) {
// 添加所有的分數(shù)并返回總數(shù)
var sumOfScores = arrayOfScores.reduce (function (prev, cur, index, array) {
return prev + cur;
});
?
// 這里的this指向的是全局global除非我們用call將其進行更改
this.avgScore = sumOfScores / arrayOfScores.length;
}
?
var gameController = {
scores :[20, 34, 55, 46, 77],
avgScore:null?
}
?
// 這樣執(zhí)行的話扰路,this就是指向全局的window
avg (gameController.scores);
// 以下的輸出可以證明this是指向全局的this的尤溜,后面的還是輸出null
console.log (window.avgScore); // 46.4?
console.log (gameController.avgScore); // null?
?
// reset the global avgScore?
avgScore = "global avgScore";
?
//設置this值,此時this就綁定給了gameController
// 使用call方法
avg.call (gameController, gameController.scores);
?
console.log (window.avgScore); //global avgScore?
console.log (gameController.avgScore); // 46.4?
還有一點汗唱,就是可以用這兩個方法來調(diào)用 Array
的一些自帶的方法靴跛,我們都知道js
里有一些神奇的變量,就是 類數(shù)組
.格式上很像數(shù)組渡嚣,但是沒有數(shù)組的一些基本方法梢睛。slice
等方法。
這個時候识椰,我們可以通過 call apply
的方法绝葡,來借用Array.prototype
的方法。
看個栗子吧腹鹉。
類數(shù)組:
//這是類數(shù)組的定義方法藏畅,需要給定一個lenth的屬性來表示該數(shù)組的長度才有效。
var anArrayLikeObj = {0:"Martin", 1:78, 2:67, 3:["Letta", "Marieta", "Pauline"], length:4 };
現(xiàn)在這個變量是沒有數(shù)組中的原生方法的功咒,那么怎么去調(diào)用呢愉阎?這個時候就可以用call和bind了
Array.prototype是數(shù)組的原型,數(shù)組的基本方法都是從原型繼承而來力奋。
var newArray = Array.prototype.slice.call (anArrayLikeObj, 0);
?
console.log (newArray); // ["Martin", 78, 67, Array[3]]?
?
// 可以使用數(shù)組中的indexOf方法榜旦,來查找對應的元素
console.log (Array.prototype.indexOf.call (anArrayLikeObj, "Martin") === -1 ? false : true); // true?
?
// 不要使用call試一下,發(fā)現(xiàn)報錯了景殷,因為沒有該方法
console.log (anArrayLikeObj.indexOf ("Martin") === -1 ? false : true); // Error: Object has no method 'indexOf'?
?
// 反轉(zhuǎn)
console.log (Array.prototype.reverse.call (anArrayLikeObj));
// {0: Array[3], 1: 67, 2: 78, 3: "Martin", length: 4}?
?
// 太棒了溅呢,我們還可以使用pop方法
console.log (Array.prototype.pop.call (anArrayLikeObj));
console.log (anArrayLikeObj); // {0: Array[3], 1: 67, 2: 78, length: 3}?
?
// 再試一下push
console.log (Array.prototype.push.call (anArrayLikeObj, "Jackie"));
console.log (anArrayLikeObj); // {0: Array[3], 1: 67, 2: 78, 3: "Jackie", length: 4}?
那再來一個,我們都知道猿挚,傳入function的變量是一個類數(shù)組咐旧,叫
arguments
.我們可以用相關的函數(shù)對傳入的參數(shù)進行操作。
// 我們沒有設置參數(shù)的數(shù)目绩蜻,可以對參數(shù)進行操作铣墨。
function doSomething () {
var args = Array.prototype.slice.call (arguments);
console.log (args);
}
doSomething ("Water", "Salt", "Glue"); // ["Water", "Salt", "Glue"]?
靈活應用apply的參數(shù)為數(shù)組的屬性,因為apply的參數(shù)是數(shù)組办绝,所以特別適用于可變函數(shù)的應用伊约。就是函數(shù)的參數(shù)不固定的情況下词顾;
當我們傳入一個數(shù)組的時候,其實函數(shù)會像這樣去執(zhí)行函數(shù),將數(shù)組中的一個個變量傳入碱妆;
createAccount (arrayOfItems[0], arrayOfItems[1], arrayOfItems[2], arrayOfItems[3]);
Math.max() 就是一個可變參數(shù)函數(shù)肉盹;
console.log (Math.max (23, 11, 34, 56)); // 56
但是我們不能把數(shù)組傳給Math.max() ;
var allNumbers = [23, 11, 34, 56];
//我們不能把數(shù)組傳給該方法?
console.log (Math.max (allNumbers)); // NaN
可以這么做疹尾;
var allNumbers = [23, 11, 34, 56];
//使用apply方法上忍,我們可以傳遞數(shù)組給該方法
console.log (Math.max.apply (null, allNumbers)); // 56
因為不需要更改this的指向,所以可以把第一個參數(shù)設置成null纳本。
####最后的最后窍蓝,我們再來理一理;先看一下這個例子繁成;
看看apply和call的真正區(qū)別吓笙;
//下面兩種方法其實就是等同的;
var s1 = ["lili","小明"巾腕,"小紅","彤彤"]
function welcomeStudents () {
console.log(arguments)
}
welcomeStudents.call(null, "lili","小明"面睛,"小紅","彤彤");
welcomeStudents.apply(null, s1);
那我們可以有什么應用場景呢?apply的參數(shù)是數(shù)組尊搬,其實可以做很多的事情叁鉴,我們不用像使用call那樣,一個一個的傳入?yún)?shù)佛寿,只需要將參數(shù)存放在一個數(shù)組里就可以。
如果現(xiàn)在讓你定義一個welcome的函數(shù)冀泻,該函數(shù)的作用是對輸入的名字,做一定的操作弹渔;
>像輸入 var s1 = ["lili","小明","小紅","彤彤"]捞附,可以相對應的輸出.
```歡迎 lili,小明巾乳,小紅和彤彤。```
你會怎么做呢鸟召?
var students = ["lili","小明"氨鹏,"小紅","彤彤"];
?
// 我們沒有設置參數(shù),因為參數(shù)的長度沒有被限制
function welcomeStudents () {
var args = Array.prototype.slice.call (arguments);
?
var lastItem = args.pop ();
console.log ("歡迎" + args.join (", ") + ", 和 " + lastItem + ".");
}
?
welcomeStudents.apply (null, students);
// 歡迎 lili,小明仆抵,小紅和彤彤跟继。
//如果你一定要用call方法种冬,那你就得這么做;
welcomeStudents.call (null, "lili","小明"舔糖,"小紅","彤彤");
最后的最后,細心的你也應該會發(fā)現(xiàn)金吗,這三個還有一點點區(qū)別就是,bind不是立即執(zhí)行的摇庙,call和apply的使用則是立即執(zhí)行的;
可以回去看看前面我提到的bind 的那個例子卫袒,綁定按鈕的點擊事件的時候,使用bind來綁定user宝穗,因為事件是在點擊之后才觸發(fā),所以這個時候用bind會比較好讽营。使用call和apply的話,則在還沒有點擊的時候就執(zhí)行了橱鹏。
$ ("button").click (user.clickHandler.bind (user));
//平時我們定義的時候堪藐,也是只寫函數(shù)名的,$ ("button").click (函數(shù)名);而不是$ ("button").click (函數(shù)名());
總結(jié)一下吧:
- call apply 立即執(zhí)行函數(shù)礁竞,apply的參數(shù)是數(shù)組,call的參數(shù)是參數(shù)變量
- bind 返回函數(shù)名模捂,非立即執(zhí)行
showData = user.showData.bind (cars);
cars.showData ();
等效于:
user.showData.call (cars);
user.showData.apply(cars);
>啊,原來整理知識這么不容易综看;休息會了;今天在咖啡廳呆了一天了红碑,五一還是不想出去呀,