> call、apply惋砂、bind的作用是改變函數(shù)運行時的this指向
## 關(guān)于this對象
this對象在運行時基于函數(shù)的執(zhí)行環(huán)境綁定的妒挎,在非嚴格模式的全局環(huán)境中,this指向window西饵,而當函數(shù)被作為某個對象的方法調(diào)用時饥漫,this等于那個對象,不過罗标,匿名函數(shù)的執(zhí)行環(huán)境具有全局性庸队,因此其this對象通常指向window(嚴格模式下,在全局環(huán)境中闯割,this指向undefined)彻消。
## 異同
- call, apply, bind 第一個參數(shù)是要綁定給this的值,區(qū)別是傳遞的參數(shù)不同宙拉,call, bind后面?zhèn)魅氲氖且粋€參數(shù)列表宾尚,apply后面?zhèn)魅氲氖且粋€包含多個參數(shù)的數(shù)組 在非嚴格模式中當?shù)谝粋€參數(shù)為null,undefined的時候谢澈,默認指向window煌贴,嚴格模式下,默認指向undefined锥忿。
```js
? var person = {
? ? name: "tjj",
? ? age: 23
? };
? function say(job, hobby){
? ? console.log(this.name + ":" + this.age+ ":" + job + ":" + hobby);
? }
? say.call(person, "Teacher", "Swimming"); // tjj:25:Teacher:Swimming
? say.apply(person, ["Teacher", "Swimming"]); // tjj:25:Teacher:Swimming
? var sayPerson = say.bind(person, "Teacher", "Swimming");
? sayPerson(); // tjj:25:Teacher:Swimming
```
- bind方法與call/apply 最大的不同是前者返回一個綁定上下文的函數(shù)牛郑,后者則是直接執(zhí)行了函數(shù)
```js
? var value = 2;
? var foo = {
? ? ? value: 1
? };
? function bar(name, age) {
? ? ? return {
? ? ? ? value: this.value,
? ? ? ? name: name,
? ? ? ? age: age
? ? ? }
? };
? bar.call(foo, "Jack", 20); // 直接執(zhí)行了函數(shù)
? // {value: 1, name: "Jack", age: 20}
? var bindFoo1 = bar.bind(foo, "Jack", 20); // 返回一個函數(shù)
? bindFoo1();
? // {value: 1, name: "Jack", age: 20}
? var bindFoo2 = bar.bind(foo, "Jack"); // 返回一個函數(shù),并且預(yù)設(shè)了第一個參數(shù)
? bindFoo2(20);
? // {value: 1, name: "Jack", age: 20}
? bindFoo2(40);
? // {value: 1, name: "Jack", age: 40}
```
## call的實現(xiàn)
## 使用場景
```js
? var nickname = "Kitty";
? function Person(name){
? ? ? this.nickname = name;
? ? ? this.distractedGreeting = function() {
? ? ? ? ? setTimeout(function(){
? ? ? ? ? ? ? console.log("Hello, my name is " + this.nickname);
? ? ? ? ? }, 500);
? ? ? }
? }
? var person = new Person('tjj');
? person.distractedGreeting();
? //Hello, my name is Kitty
```
這里輸出的nickname是全局的敬鬓,并不是我們創(chuàng)建的person 時傳入的參數(shù)淹朋,因為setTimeout在全局環(huán)境中執(zhí)行笙各,所以this指向的是window(把this換成異步回調(diào)也是一樣的,比如接口請求回調(diào))
解決辦法:
1. 緩存this 值
```js
? var nickname = "Kitty";
? function Person(name){
? ? ? this.nickname = name;
? ? ? this.distractedGreeting = function() {
? ? ? var self = this;
? ? ? ? ? setTimeout(function(){
? ? ? ? ? ? ? console.log("Hello, my name is " + self.nickname);
? ? ? ? ? }, 500);
? ? ? }
? }
? var person = new Person('tjj');
? person.distractedGreeting();
? // Hello, my name is tjj
```
2. 使用 bind
```js
? var nickname = "Kitty";
? function Person(name){
? ? ? this.nickname = name;
? ? ? this.distractedGreeting = function() {
? ? ? ? ? setTimeout(function(){
? ? ? ? ? ? ? console.log("Hello, my name is " + this.nickname);
? ? ? ? ? }.bind(this), 500);
? ? ? }
? }
? var person = new Person('tjj');
? person.distractedGreeting();
? // Hello, my name is tjj
```
- 其他用法:
```js
? Object.prototype.toString.call(obj) === '[object Array]'? // 判斷數(shù)據(jù)類型
? Array.prototype.slice.call(arguments)? // 類數(shù)組轉(zhuǎn)化為數(shù)組
? Math.max.apply(null, [1, 2, 3]) // 獲取數(shù)據(jù)最大值
? Math.min.apply(null, [1, 2, 3]) // 獲取數(shù)據(jù)最小值
? [].push.apply([1, 2], [3, 4]) // 數(shù)組追加
? // 繼承
? function Person(name,age){
? ? // 這里的this都指向?qū)嵗?/p>
? ? this.name = name
? ? this.age = age
? ? this.sayAge = function(){
? ? ? ? console.log(this.age)
? ? }
? }
? function Female(){
? ? ? Person.apply(this, arguments)//將父元素所有方法在這里執(zhí)行一遍就繼承了
? }
? var dot = new Female('Dot', 2)
```