js中apply和Math.max()函式(原文)
-
apply()
Function.apply()
是JS的一個OOP特性,一般用來模擬繼承和擴充套件this的用途,對於上面這段程式碼,可以這樣去理解:XXX.apply()
是一個呼叫函式的方法,其引數為:apply(Function, Args)
,Function為要呼叫的方法,Args是引數列表,當Function為null時,預設為上文,Math.max.apply(null, arr) 複製程式碼
可認為是
apply(Math.max, arr) 複製程式碼
然後,arr是一個引數列表,對於max方法,其引數是若干個數,即:
arr = [a, b, c, d, ...] 複製程式碼
代入原式中:
Math.max.apply(null, [a, b, c, d, ...]) 複製程式碼
等同於:
Math.max(a, b, c, d, ...) 複製程式碼
-
區別:
Math.math()
方法可以求出給定引數中最大的數,但是引數不能是陣列。例如:
> Math.max('1','2','3.1','3.2') < 3.2 > Math.min(1,0,-1) < -1 複製程式碼
此時可用
apply()
解決(第一個引數為null,第二個引數為陣列;apply()
如何實現的參見上文apply()
的轉換介紹):> Math.max.apply(null, ['1','2','3.1','3.2']) < 3.2 > Math.min.apply(null, [1,0,-1]) < -1 複製程式碼
JavaScript中的this(原文)
-
this
在 JavaScript 中,處處使用者 this ,但是,很多時候 this 指向並不固定,而是隨著它的執行環境的改變而改變。總結一句:this總是指向呼叫它所在方法的物件。
-
this 在函式裡
這種方式也稱為“全域性性的函式呼叫”,例如:
<script type='text/javascript'> var name='Hello_World'; function test(){ this.name='Hello_JavaScript'; } test(); console.log(this.name); //Hello_JavaScript console.log(window.name); //Hello_JavaScript console.log(name); //Hello_JavaScript <script> 複製程式碼
通過結果可以更加證明了全域性的name在函式內部被修改了,因為這個函式內部的this指的就是window。
總結:對於全域性性函式呼叫,函式內部的this就是指的全域性物件window,即是:this是呼叫函式所在的物件。實際上這個test()函式是由全域性物件window來去呼叫的,那麼函式內部的this當然就指的是window。
-
this 在建構函式裡
<script type='text/javascript'> var name='Hello_World'; function test(){ this.name='Hello_JavaScript'; } var person = new test(); console.log(person.name); //Hello_JavaScript console.log(window.name); //Hello_World <script> 複製程式碼
分析:我們通過new關鍵字建立一個物件的例項,可以發現new關鍵字改變了this的指向,將這個this指向了物件person。在建構函式內部,我們對this.name=“HelloWorld”進行重新賦值,並沒有改變全域性變數name的值。
總結:宣告一個建構函式的例項物件時,建構函式內部的this都會指向新的例項物件,或者說,建構函式內部的this指向的是新建立的物件本身。
-
在物件的方法中呼叫
<script type='text/javascript'> var name='Hello_World'; var person= { name:'Hello_JavaScript', info:function(){ alert(this.name); } } person.info(); //Hello_JavaScript <script> 複製程式碼
總結:當person物件呼叫info()函式時,info函式內部的this指向的就是person物件。即,當this出現在物件的方法中時,那麼該方法內部的this指向的就是這個物件本身,也就是說this指向的呼叫函式的物件。
JavaScript之call和apply(原文)
-
使用call和apply的作用
上文提到 this 的出現的三種方式,總結為兩種:
-
直接呼叫
test()
, 此種呼叫方式中,函式內部的this指向的window -
建構函式形式的呼叫
var person = new test(); 此種方式呼叫中,函式內部的this指向的是person
以上兩種方式,實際上可以這麼說,函式內部的this都是代表當前物件,只不過是JavaScript中函式內部的this會隨著程式而指向不同的物件。
那麼我的問題是:我們能不能手動修改this的指向呢?
答案:可以的,使用call或者apply。這個也就是call和apply的作用 → 改變函式內部this的指向。
-
-
應用場景
//程式碼一 <script type='text/javascript'> function Person(name,age){ this.name=name; this.age=age; } function info(){ alert(this.name +','+this.age); } var p1=new Person('jack','20'); <script> 複製程式碼
問題:我現在想借用這個info方法來去實現對p1物件的列印,怎麼做?
方案一:直接呼叫info函式,即:
info()
;通過上面的講解,仔細想想,肯定不行,因為這樣呼叫的話,info函式內部的this其實是指向的window。方案二:通過物件呼叫,即
p1.info()
;其實也不行,因為p1物件壓根就沒有info這個方法,p1物件只有name和age屬性。解決方法如下:
//程式碼二 <script type='text/javascript'> function Person(name,age){ this.name=name; this.age=age; } function info(){ alert(this.name +','+this.age); } var p1=new Person('jack','20'); p1.show=info; p1.show(); <script> 複製程式碼
可以發現我們通過向p1物件新增了一個show屬性,而這個show屬性的值其實是一個函式的地址,是一個函式物件,然後通過p1.show()就可以實現列印了。此種方法確實可以實現功能,但是這種方法是通過為p1物件新增屬性完成的,如果仍然有類似的需求,是不是都要向p1物件新增屬性來完成需求呢,這樣就會導致p1物件的佔用空間越來越大,所以方式並不優雅。
針對上面的問題,本質上就是想通過修改info函式內部的this指標的問題來完成對當前物件的一個列印,那麼我們可以在不增加屬性的方式上來完成功能,這個就需要使用到了call和apply。
-
call和apply的使用
-
功能:改變this指向,使用指定的物件呼叫當前函式
-
語法:
call([thisObj[,arg1[, arg2[, [,.argN]]]]]) 複製程式碼
apply(thisObj[,argArray]) 複製程式碼
-
說明:
-
兩個方法的功能完全一樣,唯一區別就是引數。
對於第一個引數來說thisObj,作用是一樣的,用作代表當前物件的物件,說白了就表示的是函式執行時,this指向誰。
對於 第二個引數 ,apply要求傳入的是一個引數陣列 ,也就是說將一系列引數組成一個陣列傳入,而 對於call來說,引數以雜湊的值的方式傳入 。例如,func(thisObj,arg1,arg2,arg3...)對應的apply用法就是func(thisObj,[arg1,arg2,arg3...])。本文以call方法為例
-
這兩個方法都是Function物件中的方法,因為我們定義的每個物件都擁有該方法。
-
call 方法可以用來代替另一個物件呼叫一個方法。call 方法可將一個函式的物件上下文從初始的上下文改變為由 thisObj 指定的新物件,如果沒有提供 thisObj 引數,那麼 Global 物件被用作 thisObj。(?)
-
使用call和apply解決上面程式碼的問題
//程式碼三 <script type='text/javascript'> function Person(name,age){ this.name=name; this.age=age; } function info(){ alert(this.name +','+this.age); } var p1=new Person('jack','20'); info.call(p1); //或者 info.apply(p1) <script> 複製程式碼
分析:
當在函式中呼叫call方法時,函式內部的this會自動指向call方法中的第一個引數。上面的例子中,當執行info.call(p1)時,info函式內部的this則會自動指向p1物件,所以當然就可以call這種方式來完成對p1物件的列印。
- call()重寫
<script type='text/javascript'> function Person(){ this.name = 'Hello_World'; this.info=function(){ alert(this.name) } } function Cat(){ this.name='貓'; } var cat =new Cat(); Person.call(cat); cat.info(); //Hello_World <script> 複製程式碼
上面程式碼最終會列印:‘Hello_World’,這個答案最關鍵是
Person.call(cat)
這一行程式碼,仔細去想想究竟發生了什麼事情,當呼叫call方法時,函式Person內部的this其實已經自動的指向了cat物件,相當於就是給cat物件執行了下面的兩行程式碼:this.name='Hello_World', this.info=function(){ alert(this.name) } 複製程式碼
然後重寫了原來cat物件中的name屬性,把name由“貓”改成了“ Hello_World ”,而且並獲得了一個新的info方法(可以這麼理解,相當於給cat物件新增了一個info屬性),所以cat物件當然可以呼叫info方法了,所以結果就是“ Hello_World ”。apply的使用和call的功能相同,使用方式也很類似。
-
關於call和apply的使用,剛好在 知乎 看到一個很生動形象的比喻,放在這裡希望有助於記憶。
貓吃魚,狗吃肉,奧特曼打小怪獸。
有天狗想吃魚了
貓.吃魚.call(狗,魚)
狗就吃到魚了
貓成精了,想打怪獸
奧特曼.打小怪獸.call(貓,小怪獸)
-