JS中call/apply、arguments、undefined/null方法詳解
a.call和apply方法詳解
--------------------------------------------------------------------------------
call方法:
語法:call([thisObj[,arg1[, arg2[, [,.argN]]]]])
定義:調(diào)用一個(gè)對(duì)象的一個(gè)方法,以另一個(gè)對(duì)象替換當(dāng)前對(duì)象。
說明: call 方法可以用來代替另一個(gè)對(duì)象調(diào)用一個(gè)方法。call 方法可將一個(gè)函數(shù)的對(duì)象上下文從初始的上下文改變?yōu)橛?thisObj 指定的新對(duì)象。如果沒有提供 thisObj 參數(shù),那么 Global 對(duì)象被用作 thisObj。
apply方法:
語法:apply([thisObj[,argArray]])
定義:應(yīng)用某一對(duì)象的一個(gè)方法,用另一個(gè)對(duì)象替換當(dāng)前對(duì)象。
說明:如果 argArray 不是一個(gè)有效的數(shù)組或者不是 arguments 對(duì)象,那么將導(dǎo)致一個(gè) TypeError。如果沒有提供 argArray 和 thisObj 任何一個(gè)參數(shù),那么 Global 對(duì)象將被用作 thisObj, 并且無法被傳遞任何參數(shù)。
實(shí)例學(xué)習(xí):
function add(a,b){ alert(a+b);} function sub(a,b){ alert(a-b);} add.call(sub,3,1);
打印結(jié)果為4。調(diào)用add函數(shù),但是調(diào)用對(duì)象(上下文環(huán)境)不是add對(duì)象,而是sub函數(shù)對(duì)象。注意:js中的函數(shù)其實(shí)是對(duì)象,函數(shù)名是對(duì) Function 對(duì)象的引用。
function Animal(){ this.name = "Animal"; this.showName = function(){ alert(this.name);} } function Cat(){ this.name = "Cat"; } var animal = new Animal(); var cat = new Cat(); animal.showName.call(cat,",");//輸出結(jié)果為"Cat" animal.showName.apply(cat,[]);//輸出結(jié)果為"Cat"
call 的意思是把 animal 的方法放到cat上執(zhí)行,上下文環(huán)境為cat,原來cat是沒有showName() 方法,現(xiàn)在是把a(bǔ)nimal 的showName()方法放到 cat上來執(zhí)行,而cat的this.name是Cat。所以this.name 應(yīng)該是 Cat
實(shí)現(xiàn)繼承
function Animal(name){ this.name = name; this.showName = function(){ alert(this.name);} } function Cat(name){ Animal.call(this, name); } var cat = new Cat("Black Cat"); cat.showName();
Animal.call(this) 的意思就是調(diào)用Animal方法,但是使用 this對(duì)象代替Animal對(duì)象,上下文環(huán)境變成了this。new Cat("Black Cat")中使用Animal.call給當(dāng)前的上下文環(huán)境設(shè)置了屬性name和方法showName。
拓展:多重繼承
function Class10(){ this.showSub = function(a,b){ alert(a-b); } } function Class11(){ this.showAdd = function(a,b){ alert(a+b); } } function Class2(){ Class10.call(this); Class11.call(this); }
備注:js的繼承還有其他方法,例如使用原型鏈,這個(gè)不屬于本文的范疇,只是在此說明call 的用法。說了call ,當(dāng)然還有 apply,這兩個(gè)方法基本上是一個(gè)意思,區(qū)別在于 call 的第二個(gè)參數(shù)可以是任意類型,而apply的第二個(gè)參數(shù)必須是數(shù)組或arguments。
b.arguments使用
--------------------------------------------------------------------------------
什么是arguments
arguments 是是JavaScript里的一個(gè)內(nèi)置對(duì)象,它很古怪,也經(jīng)常被人所忽視,但實(shí)際上是很重要的。所有主要的js函數(shù)庫都利用了arguments對(duì)象。所以agruments對(duì)象對(duì)于javascript程序員來說是必需熟悉的。
所有的函數(shù)都有屬于自己的一個(gè)arguments對(duì)象,它包括了函所要調(diào)用的參數(shù)。他不是一個(gè)數(shù)組,如果用typeof arguments,返回的是'object'。雖然我們可以用調(diào)用數(shù)據(jù)的方法來調(diào)用arguments。比如length,還有index方法。但是數(shù) 組的push和pop對(duì)象是不適用的。
使用arguments創(chuàng)建一個(gè)靈活的函數(shù)
看起來貌似argument對(duì)象使用起來十分有限,但是實(shí)際上它是一個(gè)非常有用的對(duì)象。你可以通過使用argument對(duì)象讓函數(shù)能夠調(diào)用數(shù)量不定 的參數(shù)。在Dean Edwards的base2庫里有個(gè)格式化的函數(shù),展示了這個(gè)靈活性。
function format(string) { var args = arguments; var pattern = new RegExp('%([1-' + arguments.length + '])', 'g'); return String(string).replace(pattern, function(match, index,position,all) { console.log(match + '&' + index + '&' + position + '&' + all); return args[index]; }); };
掉用format('And the %1 want to know whose %2 you %3', 'papers', 'shirt', 'wear');結(jié)果為"And the papers want to know whose shirt you wear";控制臺(tái)打印為
%1&1&8&And the %1 want to know whose %2 you %3
%2&2&30&And the %1 want to know whose %2 you %3
%3&3&37&And the %1 want to know whose %2 you %3
把a(bǔ)rguments對(duì)象轉(zhuǎn)換成一個(gè)真正的數(shù)組
雖然arguments對(duì)象不是一個(gè)真正的javascript數(shù)組,但是我們還是可以輕易的把它轉(zhuǎn)換成標(biāo)準(zhǔn)的數(shù)據(jù) ,然后進(jìn)行數(shù)組操作。
var args = Array.prototype.slice.call(arguments);
那么現(xiàn)在這個(gè)變量args就含有一個(gè)含有函數(shù)所有參數(shù)的標(biāo)準(zhǔn)javascript數(shù)組對(duì)象。
拓展:使用上一節(jié)的format函數(shù),通過預(yù)置的arguments對(duì)象創(chuàng)建函數(shù)
function makeFunc() { var args = Array.prototype.slice.call(arguments); var func = args.shift(); return function() { return func.apply(null, args.concat(Array.prototype.slice.call(arguments))); }; }
該方法會(huì)將第一個(gè)參數(shù)取出來,然后返回一個(gè)curry化函數(shù),該curry化函數(shù)的參數(shù)(第二個(gè)arguments)將和makeFunc的從第二個(gè)參數(shù)開始的參數(shù)組合成新數(shù)組。并返回makeFunc第一個(gè)參數(shù)的apply調(diào)用
執(zhí)行
var majorTom = makeFunc(format, "This is Major Tom to ground control. I'm %1."); majorTom("stepping through the door");
結(jié)果為:"This is Major Tom to ground control. I'm stepping through the door."
控制臺(tái)打印:%1&1&41&This is Major Tom to ground control. I'm %1.
[function.]arguments.callee
說明:arguments.callee方法返回的是正在執(zhí)行的函數(shù)本身。
callee 屬性是 arguments 對(duì)象的一個(gè)成員,它表示對(duì)函數(shù)對(duì)象本身的引用,這有利于匿名函數(shù)的遞歸或者保證函數(shù)的封裝性,例如下邊示例的遞歸計(jì)算1到n的自然數(shù)之和。而該屬性僅當(dāng)相關(guān)函數(shù)正在執(zhí)行時(shí)才可用。還有需要注意的是callee擁有l(wèi)ength屬性,這個(gè)屬性有時(shí)候用于驗(yàn)證還是比較好的。arguments.length是實(shí)參長(zhǎng)度,arguments.callee.length是形參(定義時(shí)規(guī)定的需要的參數(shù))長(zhǎng)度,由此可以判斷調(diào)用時(shí)形參長(zhǎng)度是否和實(shí)參長(zhǎng)度一致。
//用于驗(yàn)證參數(shù) function calleeLengthDemo(arg1, arg2) { if (arguments.length==arguments.callee.length) { window.alert("驗(yàn)證形參和實(shí)參長(zhǎng)度正確!"); return; } else { alert("實(shí)參長(zhǎng)度:" +arguments.length); alert("形參長(zhǎng)度: " +arguments.callee.length); } } //遞歸計(jì)算 var sum = function(n){ if (n <= 0) return 1; else return n +arguments.callee(n - 1) } //比較一般的遞歸函數(shù): var sum = function(n){ if (1==n) return 1; else return n + sum (n-1); }
調(diào)用時(shí):alert(sum(100));其中函數(shù)內(nèi)部包含了對(duì)sum自身的引用,函數(shù)名僅僅是一個(gè)變量名,在函數(shù)內(nèi)部調(diào)用sum即相當(dāng)于調(diào)用一個(gè)全局變量,不能很好的體現(xiàn)出是調(diào)用自身,這時(shí)使用callee會(huì)是一個(gè)比較好的方法。
拓展 functionName.caller
說明: 返回是誰調(diào)用了functionName 函數(shù)。functionName 對(duì)象是所執(zhí)行函數(shù)的名稱。對(duì)于函數(shù)來說,caller 屬性只有在函數(shù)執(zhí)行時(shí)才有定義。如果函數(shù)是由頂層調(diào)用的,那么 caller 包含的就是 null 。如果在字符串上下文中使用 caller 屬性,那么結(jié)果和 functionName.toString 一樣,也就是說,顯示的是函數(shù)的反編譯文本。 下面的例子說明了 caller 屬性的用法:
// caller demo { function callerDemo() { if (callerDemo.caller) { var a= callerDemo.caller.toString(); alert(a); } else { alert("this is a top function"); } } function handleCaller() { callerDemo(); } handleCaller();
執(zhí)行結(jié)果:
c.undefined和null
--------------------------------------------------------------------------------
大多數(shù)計(jì)算機(jī)語言,有且僅有一個(gè)表示"無"的值,比如,C語言的NULL,Java語言的null,Python語言的none,Ruby語言的nil。有點(diǎn)奇怪的是,JavaScript語言居然有兩個(gè)表示"無"的值:undefined和null。這是為什么?
相似性
在JavaScript中,將一個(gè)變量賦值為undefined或null,老實(shí)說,幾乎沒區(qū)別。
代碼如下:
var a = undefined; var a = null;
上面代碼中,a變量分別被賦值為undefined和null,這兩種寫法幾乎等價(jià)。
undefined和null在if語句中,都會(huì)被自動(dòng)轉(zhuǎn)為false,相等運(yùn)算符甚至直接報(bào)告兩者相等。
if (!undefined) console.log('undefined is false'); // undefined is false if (!null) console.log('null is false'); // null is false undefined == null // true
上面代碼說明,兩者的行為是何等相似!但是我們?nèi)ゲ榭磚ndefined和null的各自的類型卻發(fā)現(xiàn)類型是不同的。js基礎(chǔ)類型中沒有null類型
typeof null;//"object" typeof undefined;//"undefined"
既然undefined和null的含義與用法都差不多,為什么要同時(shí)設(shè)置兩個(gè)這樣的值,這不是無端增加JavaScript的復(fù)雜度,令初學(xué)者困擾嗎?Google公司開發(fā)的JavaScript語言的替代品Dart語言,就明確規(guī)定只有null,沒有undefined!
歷史原因
原來,這與JavaScript的歷史有關(guān)。1995年JavaScript誕生時(shí),最初像Java一樣,只設(shè)置了null作為表示"無"的值。
根據(jù)C語言的傳統(tǒng),null被設(shè)計(jì)成可以自動(dòng)轉(zhuǎn)為0。
Number(null) // 0
5 + null // 5
但是,JavaScript的設(shè)計(jì)者Brendan Eich,覺得這樣做還不夠,有兩個(gè)原因。
首先,null像在Java里一樣,被當(dāng)成一個(gè)對(duì)象。
typeof null // "object"
但是,JavaScript的數(shù)據(jù)類型分成原始類型(primitive)和合成類型(complex)兩大類,Brendan Eich覺得表示"無"的值最好不是對(duì)象。
其次,JavaScript的最初版本沒有包括錯(cuò)誤處理機(jī)制,發(fā)生數(shù)據(jù)類型不匹配時(shí),往往是自動(dòng)轉(zhuǎn)換類型或者默默地失敗。Brendan Eich覺得,如果null自動(dòng)轉(zhuǎn)為0,很不容易發(fā)現(xiàn)錯(cuò)誤。因此,Brendan Eich又設(shè)計(jì)了一個(gè)undefined。
最初設(shè)計(jì)
JavaScript的最初版本是這樣區(qū)分的:null是一個(gè)表示"無"的對(duì)象,轉(zhuǎn)為數(shù)值時(shí)為0;undefined是一個(gè)表示"無"的原始值,轉(zhuǎn)為數(shù)值時(shí)為NaN。
Number(undefined) // NaN
5 + undefined // NaN
目前的用法
但是,上面這樣的區(qū)分,在實(shí)踐中很快就被證明不可行。目前,null和undefined基本是同義的,只有一些細(xì)微的差別。
null表示"沒有對(duì)象",即該處不應(yīng)該有值。典型用法是:
(1) 作為函數(shù)的參數(shù),表示該函數(shù)的參數(shù)不是對(duì)象。
?。?) 作為對(duì)象原型鏈的終點(diǎn)。
Object.getPrototypeOf(Object.prototype) // null
undefined表示"缺少值",就是此處應(yīng)該有一個(gè)值,但是還沒有定義。典型用法是:
(1)變量被聲明了,但沒有賦值時(shí),就等于undefined。
?。?) 調(diào)用函數(shù)時(shí),應(yīng)該提供的參數(shù)沒有提供,該參數(shù)等于undefined。
?。?)對(duì)象沒有賦值的屬性,該屬性的值為undefined。
(4)函數(shù)沒有返回值時(shí),默認(rèn)返回undefined。
var i; i // undefined function f(x){console.log(x)} f() // undefined var o = new Object(); o.p // undefined var x = f(); x // undefined
以上所述是小編給大家介紹的JS中call/apply、arguments、undefined/null方法詳解,希望對(duì)大家有所幫助。
- js的隱含參數(shù)(arguments,callee,caller)使用方法
- javascript內(nèi)置對(duì)象arguments詳解
- javascript arguments 傳遞給函數(shù)的隱含參數(shù)
- javascript 利用arguments實(shí)現(xiàn)可變長(zhǎng)參數(shù)
- JS函數(shù)動(dòng)態(tài)傳遞參數(shù)的方法分析【基于arguments對(duì)象】
- javascript arguments使用示例
- Javascript中arguments對(duì)象的詳解與使用方法
- JavaScript中使用arguments獲得函數(shù)傳參個(gè)數(shù)實(shí)例
- 深入理解JS函數(shù)的參數(shù)(arguments)的使用
- JavaScript中arguments的使用方法詳解
相關(guān)文章
HTML5+Canvas調(diào)用手機(jī)拍照功能實(shí)現(xiàn)圖片上傳(上)
這篇文章主要為大家詳細(xì)介紹了HTML5+Canvas,和jquery技術(shù),調(diào)用手機(jī)拍照功能實(shí)現(xiàn)圖片上傳,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04深入理解JavaScript系列(34):設(shè)計(jì)模式之命令模式詳解
這篇文章主要介紹了深入理解JavaScript系列(34):設(shè)計(jì)模式之命令模式詳解,命令模式(Command)的定義是:用于將一個(gè)請(qǐng)求封裝成一個(gè)對(duì)象,從而使你可用不同的請(qǐng)求對(duì)客戶進(jìn)行參數(shù)化,對(duì)請(qǐng)求排隊(duì)或者記錄請(qǐng)求日志,以及執(zhí)行可撤銷的操作,需要的朋友可以參考下2015-03-03js實(shí)現(xiàn)水平滾動(dòng)菜單導(dǎo)航
這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)水平滾動(dòng)菜單導(dǎo)航,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-0712個(gè)非常有創(chuàng)意的JavaScript小游戲
JavaScript 在Web開發(fā)過程中已經(jīng)是必不可少的重要分子,他推動(dòng)著Web的交互性往越來越高的層次發(fā)展,現(xiàn)在的很多Web游戲也基于這類語言開發(fā)。2010-03-03ES6中的Promise對(duì)象與async和await方法詳解
Promise是es6引入的異步編程薪解決方案,語法上promise就是一個(gè)構(gòu)造函數(shù),用來封裝異步操作病可以獲取其成功或失敗的結(jié)果,這篇文章主要介紹了ES6中的Promise對(duì)象與async和await方法,需要的朋友可以參考下2022-12-12JS實(shí)現(xiàn)仿京東淘寶豎排二級(jí)導(dǎo)航
本文給大家分享一段使用原生Javascript實(shí)現(xiàn)的仿京東淘寶豎排二級(jí)導(dǎo)航的代碼,非常的實(shí)用,有需要的小伙伴參考下2014-12-12JS數(shù)組求和的常用方法實(shí)例小結(jié)
這篇文章主要介紹了JS數(shù)組求和的常用方法,結(jié)合實(shí)例形式總結(jié)分析了javascript常見的遍歷、循環(huán)、歸并等數(shù)組操作相關(guān)技巧,需要的朋友可以參考下2019-01-01