js中call與apply的用法小結(jié)
前天去面試,有個(gè)gg問(wèn)了一些js知識(shí),其中有一道call與apply用法的題目,盡管在365天前用過(guò)call方法,但當(dāng)時(shí)還是沒(méi)能答上來(lái),今天深入總結(jié)一下
call和apply,它們的作用都是將函數(shù)綁定到另外一個(gè)對(duì)象上去運(yùn)行
兩者的格式和參數(shù)定義:
call( thisArg [,arg1,arg2,… ] ); // 參數(shù)列表,arg1,arg2,...
apply(thisArg [,argArray] ); // 參數(shù)數(shù)組,argArray
上面兩個(gè)函數(shù)內(nèi)部的this指針,都會(huì)被賦值為thisArg,這可實(shí)現(xiàn)將函數(shù)作為另外一個(gè)對(duì)象的方法運(yùn)行的目的
一、call 的簡(jiǎn)單用法
首先,我們先看個(gè)簡(jiǎn)單的例子(call):
<!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>
然后,運(yùn)行結(jié)果如下:
global varglobal var
member var
input text
func
func2
測(cè)試環(huán)境:Google Chrome 10.0.648.45
最后,分析結(jié)果
1、全局對(duì)象window調(diào)用函數(shù)gFunc,this指向window對(duì)象,因此this.value為global var
2、函數(shù)gFunc調(diào)用call方法,this默認(rèn)指向第一個(gè)參數(shù)window對(duì)象,因此this.value也為global var
3、函數(shù)gFunc調(diào)用call方法,this默認(rèn)指向第一個(gè)參數(shù)new mFunc(),即mFunc的對(duì)象,因此this.value為mFunc的成員變量member var
4、函數(shù)gFunc調(diào)用call方法,this默認(rèn)指向第一個(gè)參數(shù)input text控件,即id=‘idTxt'的控件,因此this.value為input控件的value值input text
5、函數(shù)func2調(diào)用call方法,this默認(rèn)指向第一個(gè)參數(shù)func函數(shù)對(duì)象,因此this.value為this.a,即func
6、函數(shù)func2調(diào)用call方法,第二個(gè)參數(shù)屬于函數(shù)對(duì)象func2的參數(shù),因此alert(x)為第二個(gè)參數(shù)func2
二、call 繼承用法與改進(jìn)
js使用call模擬繼承
測(cè)試代碼:
<!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
測(cè)試環(huán)境:Google Chrome 10.0.648.45
結(jié)果分析:
預(yù)期的結(jié)果,應(yīng)該是輸出 baseA member 和 baseB member,但實(shí)際輸出卻是 baseB member 和 baseB member
(已在IE9、8、6,Maxthon、Chrome、FF、Opera、Safari、360等瀏覽器測(cè)試過(guò),結(jié)果都是后者:baseB member)
至此,機(jī)器是不會(huì)錯(cuò)的,這就需要我們深入分析
我們可能會(huì)很容易想到是this引起的,this兩次都指向了baseB對(duì)象,但是推測(cè)真是這樣嗎?
為了探究實(shí)質(zhì),我們借助chrome瀏覽器的調(diào)試工具,下斷點(diǎn),進(jìn)行調(diào)試,結(jié)果發(fā)現(xiàn):

當(dāng)調(diào)用extend.showSelfA();時(shí),此時(shí)的this指向extendAB(并不是我們推測(cè)的兩次都指向baseB對(duì)象)
真實(shí)原因是extendAB對(duì)象的成員變量member在被baseB.call(this);實(shí)例化時(shí),被baseB的成員member覆蓋了,即extendAB的成員member由baseA member賦值成了baseB member
當(dāng)然,我們也可以對(duì)上面baseA代碼稍作修改,來(lái)驗(yàn)證我們調(diào)試分析的正確性:
function baseA() // base Class A
{
this.memberA = "baseA member"; // member改成memberA,以區(qū)分baseB中的member
this.showSelfA = function()
{
window.alert(this.memberA); // 顯示memberA
}
}
再次運(yùn)行chrome等瀏覽器,結(jié)果如下:
baseA member
baseB member
結(jié)果和我們的預(yù)期相同,同時(shí)chrome調(diào)試信息也驗(yàn)證了我們的正確性:

繼承改進(jìn)(prototype)
以上模擬繼承方法,仔細(xì)分析不是最好的。
因?yàn)槊看卧诤瘮?shù)(類)中定義了成員方法,都會(huì)導(dǎo)致實(shí)例有副本,因此可以借助prototype原型,進(jìn)行改進(jìn)
改進(jìn)舉例如下:
<!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>
運(yùn)行結(jié)果如下:
obj: man and women
相關(guān)文章
JavaScript實(shí)現(xiàn)tab欄切換的效果
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)tab欄切換的效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
js獲取元素相對(duì)窗口位置的實(shí)現(xiàn)代碼
這篇文章主要介紹了js獲取元素相對(duì)窗口位置的實(shí)現(xiàn)代碼,需要的朋友可以參考下2014-09-09
JavaScript 存在陷阱 刪除某一區(qū)域所有節(jié)點(diǎn)
實(shí)現(xiàn)功能:刪除某一區(qū)域中所有節(jié)點(diǎn)。2010-05-05
JavaScript實(shí)現(xiàn)刷新不重記的倒計(jì)時(shí)
網(wǎng)上關(guān)于JavaScript實(shí)現(xiàn)倒計(jì)時(shí)的文章有很多,但是一般都是刷新后會(huì)重新開(kāi)始計(jì)時(shí),可是我們有的時(shí)候會(huì)需要刷新卻不重新計(jì)算的倒計(jì)時(shí),這該怎么做呢?下面我們一起來(lái)看看這種倒計(jì)時(shí)怎么實(shí)現(xiàn)吧。2016-08-08
webpack中splitChunks分包策略的實(shí)現(xiàn)
splitChunks是 webpack 中用于分包的配置選項(xiàng)之一,本文主要介紹了webpack中splitChunks分包策略的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2024-06-06
JS中的JSON對(duì)象的定義和取值實(shí)現(xiàn)代碼
這篇文章主要介紹了JS中的JSON對(duì)象的定義和取值實(shí)現(xiàn)代碼,也是json的入門(mén)知識(shí),需要的朋友可以參考下2018-05-05
JavaScript監(jiān)聽(tīng)觸摸事件代碼實(shí)例
這篇文章主要介紹了JavaScript監(jiān)聽(tīng)觸摸事件代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
javascript獲取四位數(shù)字或者字母的隨機(jī)數(shù)
這篇文章主要介紹了javascript獲取四位數(shù)字或者字母的隨機(jī)數(shù),需要的朋友可以參考下2015-01-01
手機(jī)端點(diǎn)擊圖片放大特效PhotoSwipe.js插件實(shí)現(xiàn)
這篇文章主要為大家詳細(xì)介紹了手機(jī)端點(diǎn)擊圖片放大特效PhotoSwipe.js插件實(shí)現(xiàn)方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-08-08
JS實(shí)現(xiàn)基于Sketch.js模擬成群游動(dòng)的蝌蚪運(yùn)動(dòng)動(dòng)畫(huà)效果【附demo源碼下載】
這篇文章主要介紹了JS實(shí)現(xiàn)基于Sketch.js模擬成群游動(dòng)的蝌蚪運(yùn)動(dòng)動(dòng)畫(huà)效果,涉及Sketch.js插件的使用及HTML5元素的應(yīng)用技巧,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下2017-08-08

