apply()javascript
Function.apply()
是JS的一個OOP特性,通常用來模擬繼承和擴展this的用途,對於上面這段代碼,能夠這樣去理解: XXX.apply()
是一個調用函數的方法,其參數爲:apply(Function, Args)
,Function爲要調用的方法,Args是參數列表,當Function爲null時,默認爲上文,php
Math.max.apply(null, arr)
複製代碼
可認爲是html
apply(Math.max, arr)
複製代碼
而後,arr是一個參數列表,對於max方法,其參數是若干個數,即:java
arr = [a, b, c, d, ...]
複製代碼
代入原式中:數組
Math.max.apply(null, [a, b, c, d, ...])
複製代碼
等同於:bash
Math.max(a, b, c, d, ...)
複製代碼
區別:app
Math.math()
方法能夠求出給定參數中最大的數,可是參數不能是數組。函數
例如:ui
> Math.max('1','2','3.1','3.2')
< 3.2
> Math.min(1,0,-1)
< -1
複製代碼
此時可用 apply()
解決(第一個參數爲null,第二個參數爲數組; apply()
如何實現的參見上文 apply()
的轉換介紹):this
> Math.max.apply(null, ['1','2','3.1','3.2'])
< 3.2
> Math.min.apply(null, [1,0,-1])
< -1
複製代碼
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指向的調用函數的對象。
使用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對象的打印。
<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(貓,小怪獸)