###** arguments** 廢話很少說,直接先看一段最簡單的函數:數組
function getSum(a,b,c,d){ return a+b+c+d }
啥意思?教你求和?app
答案就是求和,你沒看錯。求4個5個數的和還能夠這樣寫,要是10個呢?a+b+c+d+e.....函數
那要是100個呢?完了,字母都不夠用了。其實你能夠這樣寫:this
function getSum(){ var sum = 0 for(var i=0;i<arguments.length;i++){ sum += arguments[i] } return sum } console.log(getSum(1,2,3,4)) //輸出10
函數內部的arguments是什麼?也沒有聲明,也沒有傳參。其實它是函數的隱式參數,每一個函數都會有,而且arguments是一個僞數組,用來代替不肯定個數的參數的,能夠用arguments加下標的方式獲取傳給getSum函數的參數,它還有length屬性,這些都與真正的數組類似,但它沒有數組的方法,好比push、jion等。prototype
除了arguments,函數還有個隱式參數,即this。有函數的地方就會有this,this指向的是函數調用的上下文,上下文?啥意思?記得初中高中作語文閱讀題最怕的一句話就是:聯繫上下文理解某句話或某個詞語的意思。code
可是若是咱們明白了函數的四種調用方式,對應this有四種指向,就不怕不清楚this的指向了。對象
1. 函數做爲普通函數被調用;作用域
2. 函數做爲對象的方法被調用;get
3. 函數做爲構造器被調用;回調函數
4. 使用apply()和call()進行調用;
第一種:
var name = "cat" function fun(){ var name = "dog" console.log(this.name) //cat console.log(this==window) //true } fun()
函數做爲普通函數被調用,this指向全局做用域,即window對象,將這種調用方式與下面第二種會更加清楚。
第二種
var name = "cat" var obj={ name:"dog", getName:function(){ console.log(this.name) } } obj.getName() //dog
這種,函數 function ( ){ console.log(this.name) }做爲objde方法getName被調用,因此this指向調用對象,即obj,因此this.name就是obj.name。
第三種
function Cat(name){ this.name = name } var cat1 = new Cat("小黃") console.log(cat1.name) //小黃
當Cat函數被運用關鍵字new調用時,就是被當作構造器調用的,這時會發生:
1.建立一個空對象{ }
2.讓this指向這個空對象,那麼這個空對象將被增長一個name屬性,而且賦值爲「小黃」,即{name:"小黃"}
3.最後讓cat1指向這個對象,即cat1={name:"小黃"}
4.因此cat1.name值爲「小黃」
這種方式this指向的是對象的實例。
第四種
每一個函數都有call()或apply()方法,能夠運用他們來強制改變this的指向,語法爲:函數名.call(指向對象,參數)。好比下面咱們能夠限制讓fun函數中的this指向對象obj或者fun本身。
var name = "cat" function fun(){ console.log(this.name) } var obj={ name:"pig" } fun() //cat
改造後爲
var name = "cat" function fun(){ console.log(this.name) } var obj={ name:"pig" } fun.call(obj) //pig fun.call(fun) //fun 由於函數都有name屬性,函數fun的name就是fun
再看下面的實際例子,或許會更加清楚:
document.getElementById("div").onclick=function(){ console.log(this) //div的DOM對象 function fun(){ console.log(this) //window } fun() }
上面這個例子其實就是第一種和第二種的結合,首先div被點擊後,回調函數將被執行,其實在內部這個函數被賦值給了div對象的onclick屬性,這就對應第二種,函數被當作對象的方法被調用,因此內部的this執行div對象。 可是其內部又還有一個內部函數fun,它被當作普通函數調用,對應第一種,因此this指向window,但咱們有時還想讓這時的this指向div對象,能夠有兩種改造方式,that=this和call或者apply:
document.getElementById("div").onclick=function(){ console.log(this) //div的DOM對象 var that = this function fun(){ console.log(that) //div的DOM對象 } fun() }
document.getElementById("div").onclick=function(){ console.log(this) //div的DOM對象 function fun(){ console.log(this) //div的DOM對象 } fun.call(this) }
call和apply的做用
1. 如上面所述,call和apply能夠用來強制改變this指向
2. 用來借用其餘對象的方法
在講第2個做用以前先來看看call和apply的區別,它們的做用是同樣的,惟一區別就在於參數的傳遞形式。
call傳入的參數個數不固定,第一個參數是this的強制指向對象,第二個參數開始日後就是做爲參數傳給函數:
var fun=function(a,b,c){ console.log([a,b,c]) } fun.call(null,1,2,3) // [1,2,3]
而apply的參數就是兩個,第一個與call同樣表明this的強制指向對象,第二個能夠爲數組,也能夠爲僞數組arguments:
var fun=function(a,b,c){ console.log([a,b,c]) } fun.apply(null,[1,2,3]) // [1,2,3]
爲何咱們兩次傳的參數不一樣,call傳1,2,3, apply傳[1,2,3],卻輸出相同的結果,這是由於js函數內部的實現運用了arguments,當運用call時,即爲正常狀況,函數內部讓第一個參數對應arguments[0],第二個參數對應arguments[1],以此類推.......,當運用apply時,函數內部直接讓arguments等於數組[1,2,3]。
Math.max()方法用來獲取幾個數中的最大值,如Math.max(1,2,3)==3,可是不能用於獲取數組中的最大值,因此能夠利用apply來將這個方法運用於數組:
function getMax(array){ return Math.max.apply(null,array) } getMax([1,2,3]) // 3
如今再來看看call和apply的第二個做用:借用別人的方法。 咱們想讓一個空對象{ }也有數組的push方法,實現以下:
function fnn(){ var obj={} Array.prototype.push.apply(obj,arguments) console.log(obj) } fnn(1,2,3)
apply和call能夠借用別人的方法的祕密就在於:函數內部運用了大量的this和arguments。正常狀況下push的用法爲
var arr=[ ] arr.push(1);
push對應的函數,做爲方法被空數組arr調用(第二種調用),因此其內部的this指向arr,可是call和apply卻能夠改變this指向,使得this指向obj,那麼此後,arguments[0]將被賦值給obj[0],而不是arr[0],而arguments[1]將被賦值給obj[1],而不是arr[1],以此類推..........以此達到借用的目的。