生活随笔
收集整理的這篇文章主要介紹了
js中call与apply用法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
來源:http://blog.csdn.net/sunboy_2050/article/details/6592082
前天去面試,有個gg問了一些js知識,其中有一道call與apply用法的題目,盡管在365天前用過call方法,但當時還是沒能答上來,今天深入總結一下
call和apply,它們的作用都是將函數綁定到另外一個對象上去運行
兩者的格式和參數定義:
call( thisArg [,arg1,arg2,… ] ); ? ? ? // 參數列表,arg1,arg2,...
apply(thisArg [,argArray] ); ? ? ? ? ? ? ? ? // 參數數組,argArray
上面兩個函數內部的this指針,都會被賦值為thisArg,這可實現將函數作為另外一個對象的方法運行的目的
一、call 的簡單用法
首先,我們先看個簡單的例子(call):
[html]?view plaincopyprint?
<!doctype?html>?? ?? <html>?? ????<head>?? ????????<title>?call-apply?</title>?? ????</head>?? ?? ????<body>?? ????????<input?type="text"?id="idTxt"?value="input?text">?? ?????????? ????????<script?type="text/javascript">?? ????????????var?value?=?"global?var";?? ?????????????? ????????????function?mFunc()?? ????????????{?? ????????????????this.value?=?"member?var";?? ????????????}?? ?????????????? ????????????function?gFunc()?? ????????????{?? ????????????????alert(this.value);?? ????????????}????????? ?????????????????????????????????????????????????????? ????????????window.gFunc();?????????????????????????????????//?show?gFunc,?global?var?? ????????????gFunc.call(window);?????????????????????????????//?show?gFunc,?global?var?? ????????????gFunc.call(new?mFunc());????????????????????????//?show?mFunc,?member?var?? ????????????gFunc.call(document.getElementById('idTxt'));???//?show?element,?input?text?? ????????</script>?? ?????????? ????????<script?language="javascript">?? ????????????var?func?=?new?function()?? ????????????{?? ????????????????this.a?=?"func";?? ????????????}?? ?????????????? ????????????var?func2?=?function(x)?? ????????????{?? ????????????????var?a?=?"func2";?? ????????????????alert(this.a);???????????????? ????????????????alert(x);?? ????????????}?? ?????????????? ????????????func2.call(func,?"func2");??????????????????????//?show?func?and?func2?? ????????</script>?? ????</body>?? </html>??
然后,運行結果如下:
global var
global var
member var
input text
func
func2
測試環境:Google Chrome?10.0.648.45
最后,分析結果
1、全局對象window調用函數gFunc,this指向window對象,因此this.value為global var
2、函數gFunc調用call方法,this默認指向第一個參數window對象,因此this.value也為global var
3、函數gFunc調用call方法,this默認指向第一個參數new mFunc(),即mFunc的對象,因此this.value為mFunc的成員變量member var
4、函數gFunc調用call方法,this默認指向第一個參數input text控件,即id=‘idTxt’的控件,因此this.value為input控件的value值input text
5、函數func2調用call方法,this默認指向第一個參數func函數對象,因此this.value為this.a,即func
6、函數func2調用call方法,第二個參數屬于函數對象func2的參數,因此alert(x)為第二個參數func2
二、call 繼承用法與改進
js使用call模擬繼承
測試代碼:
[html]?view plaincopyprint?
<!doctype?html>?? ?? <html>?? ????<head>?? ????????<title>?call?-?apply?for?inherit?</title>?? ????</head>?? ?????? ????<body>?? ????????<script?type="text/javascript">?? ????????????function?baseA()????????//?base?Class?A?? ????????????{?? ????????????????this.member?=?"baseA?member";?? ????????????????this.showSelfA?=?function()?? ????????????????{?? ????????????????????window.alert(this.member);?? ????????????????}?? ????????????}?? ?????????????? ????????????function?baseB()????????//?base?Class?B?? ????????????{?? ????????????????this.member?=?"baseB?member";?? ????????????????this.showSelfB?=?function()?? ????????????????{?? ????????????????????window.alert(this.member);?? ????????????????}?? ????????????}?? ?????????????? ????????????function?extendAB()?????//?Inherit?Class?from?A?and?B?? ????????????{?? ????????????????baseA.call(this);???//?call?for?A?? ????????????????baseB.call(this);???//?call?for?B?? ????????????}?? ?????????????? ????????????window.onload?=?function()?? ????????????{?? ????????????????var?extend?=?new?extendAB();?????? ????????????????extend.showSelfA();?????//?show?A?? ????????????????extend.showSelfB();?????//?show?B?? ????????????}?? ????????</script>?? ????</body>?? </html>??
運行結果如下:
baseB member
baseB member
測試環境:Google Chrome?10.0.648.45
結果分析:
預期的結果,應該是輸出?baseA member 和 baseB member,但實際輸出卻是?baseB member 和 baseB member
(已在IE9、8、6,Maxthon、Chrome、FF、Opera、Safari、360等瀏覽器測試過,結果都是后者:baseB member)
至此,機器是不會錯的,這就需要我們深入分析
我們可能會很容易想到是this引起的,this兩次都指向了baseB對象,但是推測真是這樣嗎?
為了探究實質,我們借助chrome瀏覽器的調試工具,下斷點,進行調試,結果發現:
當調用extend.showSelfA();時,此時的this指向extendAB(并不是我們推測的兩次都指向baseB對象)
真實原因是extendAB對象的成員變量member在被baseB.call(this);實例化時,被baseB的成員member覆蓋了,即extendAB的成員member由baseA member賦值成了baseB member
當然,我們也可以對上面baseA代碼稍作修改,來驗證我們調試分析的正確性:
function baseA() // base Class A
{
this.memberA?= "baseA member"; ? // member改成memberA,以區分baseB中的member
this.showSelfA = function()
{
window.alert(this.memberA); ? ?// 顯示memberA
}
}
再次運行chrome等瀏覽器,結果如下:
baseA ?member
baseB member
結果和我們的預期相同,同時chrome調試信息也驗證了我們的正確性:
繼承改進(prototype)
以上模擬繼承方法,仔細分析不是最好的。
因為每次在函數(類)中定義了成員方法,都會導致實例有副本,因此可以借助prototype原型,進行改進
改進舉例如下:
[html]?view plaincopyprint?
<!doctype?html>?? ?? <html>?? ????<head>?? ????????<title>?call?-?apply?for?prototype?</title>?? ????</head>?? ?????? ????<body>?? ????????<script?type="text/javascript">?? ????????????var?Class?=?{?? ????????????????create:?function()??????????????//?create?Function?? ????????????????{?? ????????????????????return?function()?? ????????????????????{?? ????????????????????????this.initialize.apply(this,?arguments);?? ????????????????????}?? ????????????????}?? ????????????};?? ?????????????? ????????????var?Person?=?Class.create();????????//?Create?Class?Person?? ????????????Person.prototype?=?{????????????????//?prototype?initialize?? ????????????????initialize:?function(obj1,?obj2)?? ????????????????{?? ????????????????????this.obj1?=?obj1;?? ????????????????????this.obj2?=?obj2;?? ????????????????},?? ????????????????showSelf:?function()?? ????????????????{?? ????????????????????alert("obj:?"?+?this.obj1?+?"?and?"?+?this.obj2);?? ????????????????}?? ????????????}?? ?????????????? ????????????//?instance?Class?? ????????????var?person?=?new?Person("man",?"women");????//?two?params?? ????????????person.showSelf();??????????????????????????//?show?person?? ????????</script>?? ????</body>?? </html>??
運行結果如下:
obj: man and women
總結
以上是生活随笔為你收集整理的js中call与apply用法的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。