修改this指向(bind、call 和 apply)

1、bind

首先:javascript

var alertWrite = document.write;
alertWrite('who am I?');

這兩行代碼的運行結果是什麼呢?不要急着回答,看完下面的內容再回答。java

bind 的其中一個用法就是:綁定函數,使其不管怎麼樣調用都用相同的 this

看下面的例子:數組

var obj = {
    getThis: function() {
        console.log(this);
    }
};
obj.getThis();
var getThisCopy = obj.getThis; getThisCopy();

運行結果以下:瀏覽器

經過上述例子咱們會發現,雖然是 getThisCopy 是複製了 obj 的 getThis 方法,可是他們所屬的對象卻不同。在對象裏面,全部的 this 都指向對象自己,而在全局做用域定義的變量的 this 指向 Window。app

 因此,下面這段代碼的運行結果,能猜的出來結果嗎?函數

1 var obj = {
2     num: 100,
3     numFun: function() {
4         console.log(this.num);
5     }
6 };
7 var numFunCopy = obj.numFun;
8 numFunCopy();

bind 的存在就是 爲了解決 this 不可以指向原來的問題。this

因此,試試這段代碼:spa

 1 var alertWrite = document.write;
 2 alertWrite.bind(document)('hello');
 

4 var obj = { 5 getThis: function(){ 6 console.log(this); 7 } 8 } 9 var getThisCopy = obj.getThis; 10 getThisCopy.bind(obj)(); 11 12

13 var obj = {
14     num: 100,
15     numFun: function(){
16         console.log(this.num);
17     }
18 }
19 var numFunCopy = obj.numFun;
20 numFunCopy.bind(obj)();

總結bind使用方法:prototype

fun.bind(thisArgument, argument1, argument2, ...)code

thisArgument:在 fun 函數運行時指定的 this 值,若是綁定函數時使用 new 運算符構造的,則該值將被忽略。

argument1, argument2, ...:指定的參數列表。

返回值:具備指定 this 值和初始參數的給定函數的副本

使用1:建立綁定函數,使函數不管怎麼樣調用,都有相同的 this 值

 1 this.x = 9; 
 2 var module = {
 3   x: 81,
 4   getX: function() { return this.x; }
 5 };
 6 
 7 module.getX(); // 返回 81
 8 
 9 var retrieveX = module.getX;
10 retrieveX(); // 返回 9, 在這種狀況下,"this"指向全局做用域
11 
12 // 建立一個新函數,將"this"綁定到module對象
13 // 新手可能會被全局的x變量和module裏的屬性x所迷惑
14 var boundGetX = retrieveX.bind(module);
15 boundGetX(); // 返回 81

使用2:偏函數,使一個函數擁有預設值。

 

可是 bind 是 ES5 的內容,有必定的兼容性問題。

解決bind兼容性方案(1)

 1 //解決IE10如下不支持Function.bind
 2 if (!Function.prototype.bind) {
 3     Function.prototype.bind = function(oThis) {
 4         if (typeof this !== "function") {
 5             throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
 6         }
 7         var aArgs = Array.prototype.slice.call(arguments, 1),
 8             fToBind = this,
 9             fNOP = function() {},
10             fBound = function() {
11                 return fToBind.apply(this instanceof fNOP && oThis ? this : oThis,
12                     aArgs.concat(Array.prototype.slice.call(arguments)));
13             };
14         fNOP.prototype = this.prototype;
15         fBound.prototype = new fNOP();
16         return fBound;
17     };
18 }

解決bind兼容性方案(2)

1 if (!function() {}.bind) {
2     Function.prototype.bind = function(context) {
3         var self = this
4             , args = Array.prototype.slice.call(arguments);     
5         return function() {
6             return self.apply(context, args.slice(1));    
7         }
8     };
9 }

 

2、call

語法:fun.call(thisArgument, argument1, argument2, ...)

thisArgument:在 fun 函數運行時指定的 this 值。在非嚴格模式下,該函數 this 指定爲 null 和 undefined ,則 this 值會自動只想全局對象,同時只爲原始值的 this 會指向該原始值的自動包裝對象。

argument*:指定的參數列表。

返回值:調用該方法的返回值,若是沒有,則返回undefined。

使用1:使用 call 方法來實現繼承

使用2:使用 call 調用匿名函數,方法爲for循環傳入不一樣的對象

使用3:指定上下文 this

 

3、apply

語法:fun.apply(thisArg [, argsArray])

thisArg:可選,在非嚴格模式下,若是 this 值設置爲 null/undefined,則 this 指向去全局對象(瀏覽器中就是 window 對象),同時爲原始值(數字,字符串,布爾值)的 this 會指向該原始的包裝對象。

argsArray:可選。數組或者類數組對象(從ES5開始能夠使用類數組對象)。

返回值:調用有指定this值和參數的函數的結果。

使用:其使用跟 call() 很是類似,只是提供參數的方式不一樣。

相關文章
相關標籤/搜索