call(),apply(),bind()
函數你們可能都有所瞭解,可是在平時搬磚過程當中極可能或者基本沒用過,學過但都淡忘了。前端
可是在大量第三方的框架(庫),甚至js本身都在 源碼中大量使用 call,apply
函數。因此今天和你們仔細討論下它們在 開發中的應用場景 。jquery
this
。函數對象
的方法,也就是說只有函數才能夠直接調用這些方法。ps:call,apply,bing屬於this顯示綁定,還有好幾種其餘的this綁定方式,感興趣的能夠點這裏。程序員
this
。call
: 能夠有n個參數,從第二個參數開始的全部參數都是原函數的參數。數組
`apply`:只有兩個參數,而且第二個參數必須爲數組,數組中的全部元素一一對應原函數的參數。 `bind`: 只有一個參數,即要綁定的this。
call 語法: foo.call(this, arg1,arg2, ... ,argn ); apply 語法: foo.apply(this, [ arg1,arg2, ... ,argn ] ); bind 語法: foo.bind(this);
call,apply
: 調用後當即執行原函數。安全
`bind`: 調用後返回已經綁定好this的函數。
小例子一枚:app
function foo(a,b){ console.log(a+b); } foo.call(null,'海洋','餅乾'); // 海洋餅乾 這裏this指向不重要就寫null了 foo.apply(null, ['海洋','餅乾'] ); // 海洋餅乾 var fun = foo.bind(null); fun('海洋','餅乾'); // 海洋餅乾
這是咱們今天討論的主題,這三個函數如何應用?什麼狀況下使用?能改變this
指向又能咋滴?框架
先考慮一個問題,若是你使用var arr = document.getElementsByTagName('li')
獲取了5個li
元素,你如今須要獲取其中的第2,3,4三個元素,你會怎麼作?函數
這樣arr.slice(1,4);
? 啊哦,TypeError -- arr.slice is not a function(slice不是函數)
,數組操做在平常搬磚中很是常見,我見過最傻的解決這個問題的方式是使用循環,將須要的元素一個個添加到一個新數組裏0.0,下面我介紹的方法徹底能夠在實戰中使用,能夠給你的代碼加分哦,很是方便簡潔(中高級前端程序員中,算是基本操做了)。優化
先要介紹一個概念( 僞數組 ),這也是爲何咱們剛剛slice切割數組時出錯的緣由: (對新手來講算是乾貨了,知道的能夠跳過)this
什麼是僞數組?( 字面的意思已經呼之欲出了 )
push()、slice()
等方法簡單來講就是能夠像數組同樣操做的對象,可是沒有數組的方法。
js中存在大量僞數組,如 :
1. function的arguments對象。 2. getElementsByName(),getElementsByTagName(),childNodes/children 等方法的返回值。 3. 還有比較常見的jquery,使用它獲取的元素也是僞數組。
回到原來的問題,如何截取僞數組中的元素:僞數組沒有這些方法,咱們'借用'Array的slice不就好了
[].slice.call(arr,1,4); // 推薦寫法
不想借用你能夠直接給僞數組添加一個slice函數,如
arr.slice = [].slice; arr.slice(1,4);
固然,'借用' 更方便,直接添加會致使僞數組對象'污染'。
若是能夠隨意改變原對象,能夠 直接將其轉成真正的數組對象。
[].slice.call(arr);
繼承方式多種多樣,咱們如今討論的這種是其中很重要的一種實現方式,用call
實現 js 構造函數繼承 。
function person(name){ this.name = name } function man(name){ this.age = '男'; person.call(this,name); // 繼承 man } var me = new man('海洋餅乾'); console.log(me.name,me.age); // '海洋餅乾' '男'
function person(name){ this.name = name } function man(name){ this.age = '男'; } function manProgrammer(name){ this.girlfriend = null; person.call(this,name); // 繼承 person man.call(this,name); // 繼承 man } var me = new manProgrammer('海洋餅乾'); console.log(me.name,me.age,me.girlfriend); // '海洋餅乾' '男' null
將一個對象強制且永久性綁定到函數的this上,使用call,apply或者其餘的綁定方式都沒法改變(除了new綁定,固然,能夠手動擼一個new都沒法改變的硬綁定)
直接看例子:
var fun ; var obj = { a : 1, foo : function(){ var _this = this; //平時有沒有過這種寫法? 爲了防止this指向問題 //將this賦值給一個變量,間接維持了this的安全性 fun = function(){ console.log(_this.a); } } } obj.foo(); fun(); // 1 var obj1 = { a : 2} obj.foo.call(obj1); // 直接修改_this所綁定的值,boom了 fun(); // 2
可是這種方法感受上是在逃避問題,直接不使用this了 ? 這真的不是什麼好的解決問題的態度。下面使用咱們的bind來優化一下:
var fun ; var obj = { a : 1, foo : function(){ // 不使用 _this, 避免無謂的變量聲明 fun = function(){ console.log(this.a); }.bind(this); // 代碼很簡潔,很漂亮(b格) } } var obj1 = { a : 2} obj.foo(); fun(); // 1 fun.call(obj1); // 1 call ,apply等綁定 沒法修改 // 這裏和上面call的位置不一樣是由於this所處於不一樣的位置
這樣替代 _this
很規(zhuang)範(b)呢
ps:call,apply,bing屬於this顯示綁定,還有好幾種其餘的this綁定方式,感興趣的能夠點這裏。
Math.max和min方法,接收多個參數,比較出極值,這裏用到apply的一個默認功能:展開數組,傳入一個數組參數就能夠默認將這個數組轉成一個個參數的形式賦給原函數
var num = [6,9,-3,-5]; console.log(Math.max.apply(Math,num)); // 9 等價 console.log(Math.max(6,9,-3,-5)); console.log(Math.min.apply(Math,num)); // -5 等價 console.log(Math.min(6,9,-3,-5));
合併數組常見有三種方式,1.循環 2.Array的concat() 3. 使用apply()合併
這裏是使用最簡便的apply
var a = [1,2,3]; var b = [4,5,6]; [].push.apply(a,b); // 借用數組的push方法 等價 a.push(4,5,6); console.log(a); // [1, 2, 3, 4, 5, 6]
以爲對你有幫助點個讚唄555
你們有什麼實用點的黑科技歡迎私信評論 分享,我會貼上id和你的分享 >_<