關於javascript中的call方法,網上查了一些資料老是不得詳解。總結網上的觀點,call有兩個妙用:javascript
1: 繼承。(不太喜歡這種繼承方式。)java
2: 修改函數運行時的this指針。函數
js中關於call的解釋以下:測試
js關於call的這份文檔容易讓人迷糊。而《javascript權威指南》對call的描述就比較容易理解了。this
注意紅色框中的部分,f.call(o)其原理就是先經過 o.m = f 將 f做爲o的某個臨時屬性m存儲,而後執行m,執行完畢後將m屬性刪除。指針
如 function f(){對象
var a = "name";blog
this.b = "test1";繼承
this.add = function (){ return "add" }ip
}
function o(){
this. c = "c";
}
f.all(o);
圖 1
圖1中 f.call(o)其實至關於: function o(){
this.c = "c" ;
var a = "name";
this.b = "test1";
this.add = function (){ return "add" }
}
說白了,就是把f的方法在o中走一遍,但不作保存。既然不作保存,那麼如何經過call實現繼承和修改函數運行時的this指針等妙用?關鍵在於this,對,關鍵仍是在於this的做用域。在以前的文章反覆說過,this的做用域不是定義它的函數的做用域,而是執行時的做用域。
以下例子:
圖 2
如圖2, 在執行A.call(this)以前,輸出的this 不包含任何屬性和方法,以後則繼承了A的屬性和方法。仍是按照上面的方法解釋,執行完A.call(this) (this此時表明執行時的做用域,即B)後,B構造函數以下:
function B()
{
console.log(this);
this.test1 = "test1";
this.test2 = "test2";
this.add = function(){ return this.test1 + this.test2 ; }
console.log(this);
}
由於調用A.call(this)的時候,this做用域已經發生改變了,表明的都是B(),哪怕執行A中的方法和屬性的時候,this也是表明着執行時的做用域B();因此如此才能實現繼承,即將A()中的屬性賦值和方法定義在B()中再走一遍。其實此時也修改了函數運行時的this指針。
關於call的第二個妙用,修改函數運行時的this指針:
這裏採用一位貼吧大神的回答,作了一個測試例子,其實應該也是js中關於each遍歷的定義。
圖 3
如圖3,第一個中直接調用fn方法,其中由於沒有定義函數做用域,輸出的this表示window對象,即全局對象。而第二個中經過fn.call(array[index] , index , array[index] )將fn方法放到array[index]做用域中執行,輸出的this表示的是array[index]對象。
換一個視角:
圖 4
如圖 4 , 經過each方法中調用call方法能夠實現遍歷。咱們假設array[index]是DOM元素集合,如標籤爲li的全部集合,假設fn是咱們自定義實現的方法,不就是咱們用的each遍歷DOM元素的方法嗎?
圖 5
如圖5,簡單的代碼即實現了遍歷DOM元素的each方法。