在js中萧求,函數(shù)本身屬于對(duì)象的一種,因此可以定義顶瞒、賦值夸政,作為對(duì)象的屬性或者成為其他函數(shù)的參數(shù)。函數(shù)名只是函數(shù)這個(gè)對(duì)象類的引用榴徐。
函數(shù)定義
3種函數(shù)定義的方式
1.函數(shù)聲明語(yǔ)句
使用function關(guān)鍵字守问,后跟一組參數(shù)以及函數(shù)體
function funcname(args1,args2){
statement;
}
2.函數(shù)表達(dá)式
以表達(dá)式方式定義的函數(shù),函數(shù)的名稱是可選的
var funcname=function(args1,args2){
statement;
}
var funcname=function funcname(args1,args2){
statement;
}
匿名函數(shù)也叫拉姆達(dá)函數(shù)坑资,是function關(guān)鍵字后面沒(méi)有標(biāo)識(shí)符的函數(shù)耗帕。
通常而言,以表達(dá)式定義函數(shù)時(shí)都不需要名稱袱贮,這會(huì)讓定義它們的代碼更加緊湊仿便。函數(shù)表達(dá)式特別適合用來(lái)定義那些只會(huì)使用一次的函數(shù)
var ten=(function(x){return x*x}(10));//定義同時(shí)進(jìn)行調(diào)用
一個(gè)函數(shù)定義表達(dá)式包含名稱,函數(shù)的局部作用域?qū)?huì)包含一個(gè)綁定到函數(shù)對(duì)象的名稱攒巍。實(shí)際上嗽仪,函數(shù)的名稱將成為函數(shù)內(nèi)部的一個(gè)局部變量。
var test=function fn(){
return fn;
}
console.log(test);//fn(){return fn;}
console.log(test());//fn(){return fn;}
console.log(test()());//fn(){return fn;}
對(duì)于有具體名字的函數(shù)表達(dá)式來(lái)說(shuō)柒莉,函數(shù)名稱相當(dāng)于函數(shù)對(duì)象的形參闻坚,自能在函數(shù)內(nèi)部使用;而變量名稱相當(dāng)于函數(shù)對(duì)象的實(shí)參兢孝,在函數(shù)內(nèi)部和函數(shù)外部都可以使用窿凤。
var test=function fn(){
return fn===test;
}
console.log(test());//true
console.log(test===fn);//fn is not defined
函數(shù)定義了一個(gè)非標(biāo)準(zhǔn)的name屬性,通過(guò)這個(gè)屬性可以訪問(wèn)到給定函數(shù)指定的名字跨蟹,這個(gè)屬性的值永遠(yuǎn)等于跟在function關(guān)鍵字后面的標(biāo)識(shí)符雳殊,匿名函數(shù)的name屬性為空。
//ie-11瀏覽器無(wú)效喷市,輸出undefined
//chrome在處理匿名函數(shù)時(shí)有問(wèn)題相种,會(huì)顯示函數(shù)表達(dá)式的名字
function fn(){}
console.log(fn.name);//fn
var fn=function(){};//''在chrome瀏覽器會(huì)顯示fn
var fn=function abc(){}
console.log(fn.name);//abc
3.function構(gòu)造函數(shù)
Function構(gòu)造函數(shù)接收任意數(shù)量的參數(shù),但是最后一個(gè)參數(shù)始終都被看成是函數(shù)體品姓,而前面的參數(shù)則枚舉出了新函數(shù)的參數(shù)
var funcname=new Function(args1,args2,'statement')
注意:Function構(gòu)造函數(shù)無(wú)法指定函數(shù)名稱寝并,它創(chuàng)建的是一個(gè)匿名函數(shù)。
從技術(shù)上講腹备,這是一個(gè)函數(shù)表達(dá)式衬潦。但是不推薦使用這種方式聲明函數(shù),這種語(yǔ)法會(huì)導(dǎo)致解析兩次代碼植酥。第一次是解析常規(guī)js代碼镀岛,第二次解析傳入構(gòu)造函數(shù)中的字符串弦牡,影響性能。
var sum=new Function('num1','num2','return num1+num2')
//等價(jià)于
var sum=function(num1,num2){
return num1+num2;
}
Function()構(gòu)造函數(shù)創(chuàng)建的函數(shù)漂羊,其函數(shù)體的編譯總是會(huì)在全局作用域中執(zhí)行驾锰。于是,F(xiàn)unction()構(gòu)造函數(shù)類似于在全局作用域中執(zhí)行的eval()
var test=0;
functoin fn(){
var test=1;
return new Function('return test')
}
console.log(fn()());//0
并不是所有的函數(shù)都可以成為構(gòu)造函數(shù)
var a=new Math.min();//報(bào)錯(cuò)
函數(shù)聲明順序
函數(shù)聲明走越,相對(duì)于變量會(huì)優(yōu)先加載椭豫。所以不用擔(dān)心函數(shù)聲明在調(diào)用前還是調(diào)用后。
調(diào)用函數(shù)時(shí)會(huì)在本機(jī)活動(dòng)對(duì)象中查詢旨指,即當(dāng)前js文件中查詢赏酥,如果沒(méi)有才會(huì)向上查詢
,所以要是在兩個(gè)js文件中定義相同的函數(shù)名谆构,這兩個(gè)js文件內(nèi)部調(diào)用各自的函數(shù)裸扶,其他js文件調(diào)用最后聲明的函數(shù)。
重復(fù)
變量的重復(fù)聲明是無(wú)用的搬素,不會(huì)覆蓋同一作用域聲明的變量呵晨,但是函數(shù)的重復(fù)聲明會(huì)覆蓋前面的同名函數(shù)或同名變量。
//變量的重復(fù)聲明無(wú)用
var a=1;
var a;
console.log(a);//1
//覆蓋同名變量
var a;
function a(){
console.log(1)
}
a();//1
//覆蓋同名函數(shù)
a();//2
function a(){
console.log(a)
}
function a(){
console.log(2)
}
刪除
函數(shù)聲明語(yǔ)句創(chuàng)建的變量無(wú)法刪除蔗蹋,這一點(diǎn)和變量聲明一樣何荚。
function foo(){
console.log(1)
}
delete foo;
console.log(foo());//1
函數(shù)返回值
所有函數(shù)都有返回值,沒(méi)有return語(yǔ)句時(shí)猪杭,默認(rèn)返回內(nèi)容是undefined餐塘,和其他面向?qū)ο蟮木幊陶Z(yǔ)言一樣,return語(yǔ)句不會(huì)阻止finally子句的執(zhí)行皂吮。
function test(){
try{
return 2;
}catch(error){
return 1;
}finally{
return 0;
}
}
test();//0
如果函數(shù)調(diào)用時(shí)在前面加上了new前綴戒傻,且返回值不是一個(gè)對(duì)象,則返回this(該新對(duì)象)
function fn(){
this.a=2;
return 1;
}
var test=new fn();
console.log(test);//{a:2}
console.log(test.constructor);//fn(){this.a=2;return 1;}
如果返回值是一個(gè)對(duì)象蜂筹,則返回該對(duì)象需纳。
function fn(){
this.a=2;
return {a:1}
}
var test=new fn();
console.log(test);//{a:1}
console.log(test.constructor);//Object
函數(shù)調(diào)用
js一共有四種調(diào)用模式:函數(shù)調(diào)用模式,方法調(diào)用模式艺挪,構(gòu)造器調(diào)用模式和間接調(diào)用模式不翩。
1.函數(shù)調(diào)用模式
當(dāng)一個(gè)函數(shù)并非一個(gè)對(duì)象的屬性時(shí),那么他就是被當(dāng)作一個(gè)函數(shù)來(lái)調(diào)用的麻裳。對(duì)于普通的函數(shù)調(diào)用來(lái)說(shuō)口蝠,函數(shù)的返回值就是調(diào)用表達(dá)式的值。
function add(x,y){
return x+y;
}
var sum=add(3,4)
console.log(sum);//7
使用函數(shù)調(diào)用模式調(diào)用函數(shù)時(shí)津坑。非嚴(yán)格模式下妙蔗,this被綁定到全局對(duì)象;在嚴(yán)格模式下疆瑰,this是undefined
function add(x,y){
console.log(this);//window
}
function add(x,y){
'use strict';
console.log(this);//undefined
}
因此眉反,this可以用來(lái)判斷當(dāng)前是否是嚴(yán)格模式昙啄。
var strict=(functioon(){return !this;}())
重寫(xiě):因?yàn)楹瘮?shù)調(diào)用模式的函數(shù)中的this綁定到全局對(duì)象,所以會(huì)發(fā)生全局屬性被重寫(xiě)的現(xiàn)象
var a=0;
function fn(){
this.a=1;
}
fn();
console.log(this,this.a,a);//window 1 1
2.方法調(diào)用模式
當(dāng)一個(gè)函數(shù)被保存為對(duì)象的一個(gè)屬性時(shí)寸五,我們稱它為一個(gè)方法梳凛。當(dāng)一個(gè)方法被調(diào)用時(shí),this被綁定到該對(duì)象播歼。如果調(diào)用表達(dá)式包含一個(gè)提取屬性的動(dòng)作伶跷,那么它就是被當(dāng)作一個(gè)方法來(lái)調(diào)用掰读。
var o={
m:function(){
console.log(1)
}
}
o.m();//1
方法可以使用this訪問(wèn)自己所屬的對(duì)象秘狞,所以它能從對(duì)象中取值或?qū)?duì)象進(jìn)行修改。this到對(duì)象的綁定發(fā)生在調(diào)用的時(shí)候蹈集。通過(guò)this可取的它們所屬對(duì)象的上下文的方法稱為公共方法烁试。
var o={
a:1,
m:function(){
return this;
},
n:function(){
this.a=2;
}
}
console.log(o.m().a);//1
o.n();
console.log(o.m().a);//2
任何函數(shù)只要作為方法調(diào)用實(shí)際上都會(huì)傳入一個(gè)隱式的實(shí)參--這個(gè)參數(shù)是一個(gè)對(duì)象,方法調(diào)用的母體就是這個(gè)對(duì)象拢肆,通常來(lái)講减响,基于那個(gè)對(duì)象的方法可以執(zhí)行多次操作,方法調(diào)用的語(yǔ)法已經(jīng)清晰的表明了函數(shù)將基于一個(gè)對(duì)象進(jìn)行操作郭怪。
rect.setSize(width,height);
setRectSize(rect,width,height);
假設(shè)上面兩行代碼的功能完全一樣支示,它們都作用于一個(gè)假定的對(duì)象rect”刹牛可以看出颂鸿,第一行的方法調(diào)用語(yǔ)句非常清晰的表明這個(gè)函數(shù)執(zhí)行的載體是rect對(duì)象,函數(shù)中的所有操作將會(huì)基于這個(gè)對(duì)象攒庵。
和變量不同嘴纺,關(guān)鍵字this沒(méi)有作用域的限制,嵌套的函數(shù)不會(huì)調(diào)用它的函數(shù)中繼承this浓冒,如果嵌套函數(shù)作為方法調(diào)用栽渴,其this的值指向調(diào)用它的對(duì)象。如果嵌套函數(shù)作為函數(shù)調(diào)用稳懒,其this的值不是全局對(duì)象就是undefined
var o={
m:function(){
function n(){
return this;
}
return n();
}
}
console.log(o.m());//window
var o={
m:function(){
function n(){
'use strict'
return this;
}
return n()
}
}
console.log(o.m());//undefined
如果想訪問(wèn)這個(gè)外部函數(shù)的this值闲擦,需要將this的值保存在一個(gè)變量里,這個(gè)變量和內(nèi)部函數(shù)都同在一個(gè)作用域內(nèi)场梆。通常使用變量self或that來(lái)保存this.
var o={
m:function(){
var self=this;
console.log(this===o);//true
function n(){
console.log(this===o);//false
console.log(self===o);//true
return self;
}
return n()
}
}
console.log(o.m()===o);//true
3.構(gòu)造函數(shù)調(diào)用模式
如果函數(shù)或者方法調(diào)用之前帶有new關(guān)鍵字墅冷,它就構(gòu)成構(gòu)造函數(shù)調(diào)用。
function fn(){
this.a=1;
}
var obj=new fn();
console.log(obj.a);//1
如果構(gòu)造函數(shù)調(diào)用在圓括號(hào)內(nèi)包含一組實(shí)參列表辙谜,先計(jì)算這些實(shí)參表達(dá)式俺榆,然后傳入函數(shù)內(nèi)
function fn(x){
this.a=x;
}
var obj=new fn(2);
console.log(obj.a);//2
如果構(gòu)造函數(shù)沒(méi)有形參,js構(gòu)造函數(shù)調(diào)用的語(yǔ)法是允許省略實(shí)參列表和圓括號(hào)的装哆。凡是沒(méi)有形參的構(gòu)造函數(shù)都可以省略圓括號(hào)罐脊。
var o=new Object();
//等價(jià)于
var o=new Object;
注意:盡管構(gòu)造函數(shù)看起來(lái)像是一個(gè)方法調(diào)用定嗓,他依然會(huì)使用新對(duì)象作為調(diào)用上下文。也就是說(shuō):在表達(dá)式new o.m()中萍桌,調(diào)用上下文并不是o
var o={
m:function(){
return this;
}
}
var obj=new o.m();
console.log(obj,obj===o);//{},false
console.log(obj.constructor===o.m);//true
構(gòu)造函數(shù)通常不使用return關(guān)鍵字宵溅,他們通常初始化新對(duì)象,當(dāng)構(gòu)造函數(shù)的函數(shù)體執(zhí)行完畢時(shí)上炎,它會(huì)顯式返回恃逻。在這種情況下,構(gòu)造函數(shù)調(diào)用表達(dá)式的計(jì)算結(jié)果就是這個(gè)新對(duì)象的值藕施。
function fn(){
this.a=2;
}
var test=new fn();
console.log(test);//{a:2}
如果構(gòu)造函數(shù)使用return語(yǔ)句但沒(méi)有指定返回值寇损,或者返回一個(gè)原始值,那么這時(shí)將忽略返回值裳食,同時(shí)使用這個(gè)新對(duì)象作為調(diào)用結(jié)果
function fn(){
this.a = 2;
return;
}
var test = new fn();
console.log(test);//{a:2}
如果構(gòu)造函數(shù)顯式地使用return語(yǔ)句返回一個(gè)對(duì)象矛市,那么調(diào)用表達(dá)式的值就是這個(gè)對(duì)象
var obj = {a:1};
function fn(){
this.a = 2;
return obj;
}
var test = new fn();
console.log(test);//{a:1}
4.間接調(diào)用模式
js中函數(shù)也是對(duì)象,函數(shù)對(duì)象也可以包含方法诲祸,call()和apply()方法可以用來(lái)間接的調(diào)用函數(shù)浊吏。
這兩個(gè)方法都允許顯式指定調(diào)用所需的this值,也就是所救氯,任何函數(shù)可以作為任何對(duì)象的方法來(lái)調(diào)用找田,哪怕這個(gè)函數(shù)不是對(duì)象的方法。兩個(gè)方法都可以指定調(diào)用的實(shí)參着憨。call()方法使用它自有的實(shí)參列表作為函數(shù)的實(shí)參墩衙。apply()方法則要求以數(shù)組的形式傳入?yún)?shù)。
var obj={};
function sun(x,y){
return x+y;
}
console.log(sun.call(obj,1,2));//3
console.log(sun.apply(obj,[1,2]));//3
函數(shù)參數(shù)
arguments:js中的函數(shù)定義并未指明函數(shù)形參的類型享扔,函數(shù)調(diào)用也未對(duì)傳入的實(shí)參值做任何類型檢查底桂。實(shí)際上,js函數(shù)調(diào)用甚至不檢查傳入形參的個(gè)數(shù)惧眠。
function add(x){
return x+1;
}
console.log(add(1));//2
console.log(add("1"));//11
console.log(add());//NaN
console.log(add(1,2));//2
同名形參:在非嚴(yán)格模式下籽懦,函數(shù)中可以出現(xiàn)同名形參,且只能訪問(wèn)最后出改名稱的形參氛魁。
function add(x,x,x){
return x;
}
console.log(add(1,2,3));//3
而在嚴(yán)格模式下暮顺,出現(xiàn)同名形參拋出語(yǔ)法錯(cuò)誤。
function add(x,x,x){
'use strict';
return x;
}
console.log(add(1,2,3));//出現(xiàn)錯(cuò)誤
參數(shù)個(gè)數(shù):當(dāng)實(shí)參比函數(shù)聲明指定的形參個(gè)數(shù)少秀存,剩下的形參都將設(shè)置為undefined值捶码。
function add(x,y){
console.log(x,y);
}
add(1);//1,undefined
常常使用邏輯或運(yùn)算符給省略的參數(shù)設(shè)置一個(gè)合理的默認(rèn)值。
function add(x,y){
y=y||2;
console.log(x,y)
}
add(1)
注意:實(shí)際上或链,使用y=y||2是不嚴(yán)謹(jǐn)?shù)谋鼓眨@示的設(shè)置值(undefined,null,false,0,-0,NaN)也會(huì)得到相同的結(jié)果。所以應(yīng)該根據(jù)實(shí)際場(chǎng)景進(jìn)行合理設(shè)置澳盐。
當(dāng)實(shí)參比形參個(gè)數(shù)要多時(shí)祈纯,剩下的實(shí)參沒(méi)有辦法直接獲得令宿,需要使用即將提到的arguments對(duì)象。
js中的參數(shù)在內(nèi)部用一個(gè)數(shù)組表示腕窥。函數(shù)接收到的始終都是這個(gè)數(shù)組粒没,而不關(guān)心數(shù)組中包含哪些參數(shù)。在函數(shù)體內(nèi)可以通過(guò)arguments對(duì)象來(lái)訪問(wèn)這個(gè)參數(shù)數(shù)組簇爆,從而獲得傳遞給參數(shù)的每一個(gè)參數(shù)癞松。arguments對(duì)象并不是array的實(shí)例,他是一個(gè)類數(shù)組對(duì)象入蛆,可以使用方括號(hào)訪問(wèn)它的每一個(gè)元素响蓉。
function add(x){
console.log(arguments[0],arguments[1],arguments[2]);
return x+1;
}
add(1,2,3)
arguments對(duì)象的length屬性顯示實(shí)參的個(gè)數(shù),函數(shù)的length屬性顯示形參的個(gè)數(shù)安寺。
function add(x,y){
console.log(arguments.length) //3
return x+1;
}
add(1,2,3);
console.log(add.length); //2
形參只是提供便利厕妖,但不是必需的
function add(){
return arguments[0]+arguments[1];
}
console.log(add(1,2));//3
對(duì)象參數(shù):當(dāng)一個(gè)函數(shù)包含超過(guò)3個(gè)形參時(shí),要記住調(diào)用函數(shù)中實(shí)參的正確順序?qū)嵲谧屓祟^疼挑庶。
function arraycopy(/*array*/from,/*index*/form_start,/*array*/to,/*index*/to_start,/*integer*/length){
//todo
}
通過(guò)鍵值對(duì)的形式來(lái)傳入?yún)?shù),這樣參數(shù)的順序就無(wú)關(guān)緊要了软能。定義函數(shù)的時(shí)候迎捺,傳入的實(shí)參都寫(xiě)入一個(gè)單獨(dú)的對(duì)象之中,在調(diào)用的時(shí)候傳入一個(gè)對(duì)象查排,對(duì)象中的名值對(duì)是真正需要的實(shí)參數(shù)據(jù)凳枝。
function easycopy(args){
arraycopy(args.from,args.from_start||0,args.to,args.to_start||0,args.length);
}
var a=[1,2,3,4],b=[];
easycopy({from:a,to:b,length:4})
以參數(shù)為參數(shù)
函數(shù)本身是一個(gè)對(duì)象,因此可以將函數(shù)作為另一個(gè)函數(shù)的參數(shù)跋核,進(jìn)而實(shí)現(xiàn)函數(shù)回調(diào)岖瑰,功能等同于c++中的函數(shù)指針
function printf(str){
dom1.innerText+=str.toString()+"\n";//設(shè)置dom1顯示的文字。變量也可以自動(dòng)調(diào)用其他js文件中的dom1變量砂代。dom1會(huì)先在當(dāng)前文件中查詢蹋订,然后向之前引用的js文件查詢,再向之后引用的js文件查詢
}
function callfunction(myfunction,myargument){ //函數(shù)作為其他函數(shù)的參數(shù)
return myfunction(myargument); //調(diào)用回調(diào)函數(shù)
}
callfunction(printf,"hello world");
同步:當(dāng)形參與實(shí)參的個(gè)數(shù)相同時(shí)刻伊,arguments對(duì)象的值和對(duì)應(yīng)形參的值保持同步露戒。
function test(num1,num2){
console.log(num1,arguments[0]);//1,1
arguments[0]=2;
console.log(num1,arguments[0]);//2,2
num1=10;
console.log(num1,arguments[0]);//10,10
}
test(1)
注意:雖然命名參數(shù)和對(duì)應(yīng)arguments對(duì)象的值相同,但并不是相同的命名空間捶箱。他們的命名空間是獨(dú)立的智什,但值是同步的
在嚴(yán)格模式下,arguments對(duì)象的值和參數(shù)的值都是獨(dú)立的丁屎。
function test(num1,num2){
'use strict';
console.log(num1,arguments[0]);1,1
arguments[0]=2;
console.log(num1,arguments[0]);1,2
num1=10;
console.log(num1,arguments[0]);10,2
}
test(1)
當(dāng)形參并沒(méi)有對(duì)應(yīng)的實(shí)參時(shí)荠锭,arguments對(duì)象的值和形參的值并不對(duì)應(yīng)。
function test(num1,num2){
console.log(num1,arguments[0]);//undefined,undefined
num1=10;
arguments[0]=5;
console.log(num1,arguments[0]);//10,5
}
test()
內(nèi)部屬性:callee
arguments對(duì)象有一個(gè)名為callee的屬性晨川,該屬性是一個(gè)指針证九,指向擁有這個(gè)arguments對(duì)象的函數(shù)
下面是經(jīng)典的階乘函數(shù)
function factorial(num){
if(num<=1){
return 1;
}else{
return num*factorial(num-1)
}
}
console.log(factorial(5));//120
但是键思,上面這個(gè)函數(shù)的執(zhí)行與函數(shù)名字緊緊耦合在了一起,可以使用arguments.callee可以消除函數(shù)解耦
function fact(num){
if(num<=1){
return 1;
}else{
return num*arguments.callee(num-1);
}
}
console.log(fact(5));//120
但是在嚴(yán)格模式下甫贯,訪問(wèn)這個(gè)屬性會(huì)拋出typeerror錯(cuò)誤
function factorial(num){
'use strict';
if(num <=1){
return 1;
}else{
return num* arguments.callee(num-1);
}
}
//TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
console.log(factorial(5));
這時(shí)吼鳞,可以使用具名的函數(shù)表達(dá)式
var fact=function fn(num){
if(num<=1){
return 1;
}else{
return num*fn(num-1)
}
}
console.log(fact(5))
caller:實(shí)際上,有兩個(gè)caller屬性
1:函數(shù)的caller
函數(shù)的caller屬性保存著調(diào)用當(dāng)前函數(shù)的函數(shù)的引用叫搁,如果實(shí)在全局作用域中調(diào)用當(dāng)前函數(shù)赔桌,它的值是null
function outer(){
inner()
}
function inner(){
console.log(inner.caller)//outer(){inner();}
}
outer()
function inner(){
console.log(inner.caller);//null
}
inner()
在嚴(yán)格模式下,訪問(wèn)這個(gè)屬性會(huì)拋出typeerror錯(cuò)誤
function inner(){
'use strict';
console.log(inner.caller);
}
inner()
2:arguments對(duì)象的caller
該屬性始終是undefined渴逻,定義這個(gè)屬性是為了分清arguments.caller和函數(shù)的caller屬性
function inner(x){
console.log(arguments.caller);//undefined
}
inner(1);
同樣地疾党,在嚴(yán)格模式下,訪問(wèn)這個(gè)屬性會(huì)拋出TypeError錯(cuò)誤
function inner(x){
'use strict';
//TypeError: 'caller' and 'arguments' are restricted function properties and cannot be accessed in this context
console.log(arguments.caller);
}
inner(1);
函數(shù)重載
js函數(shù)不能像傳統(tǒng)意義上那樣實(shí)現(xiàn)重載惨奕。而在其他語(yǔ)言中雪位,可以為一個(gè)函數(shù)編寫(xiě)兩個(gè)定義,只要這兩個(gè)定義的簽名(接受的參數(shù)的類型和數(shù)量)不同即可梨撞。
js函數(shù)沒(méi)有簽名雹洗,因?yàn)槠鋮?shù)是由包含0個(gè)或者多個(gè)值得數(shù)組來(lái)表示的。而沒(méi)有函數(shù)簽名卧波,真正的重載是不可能做到的时肿。
//后面的聲明覆蓋了前面的聲明
function a(num){
retun num+100;
}
functiona (num){
return num+200;
}
var result=a(100);//300
只能通過(guò)檢查傳入函數(shù)中參數(shù)的類型和數(shù)量并做出不同的反應(yīng),來(lái)模仿方法的重載
function doAdd(){
if(arguments.length==1){
alert(arguments[0]+10)
}else if(arguments.length==2){
alert(arguments[0]+arguments[2])
}
}
doAdd(10);//20
doAdd(30,20);//50
參數(shù)傳參
js中所有函數(shù)的參數(shù)都是按值傳遞的港粱,也就是說(shuō)螃成,把函數(shù)外部的值復(fù)制到函數(shù)內(nèi)部的參數(shù),就和把值從一個(gè)變量復(fù)制到另一個(gè)變量一樣查坪。
1.基本類型值
在向參數(shù)傳遞基本類型的值時(shí)寸宏,被傳遞的值會(huì)被復(fù)制給一個(gè)局部變量(同名參數(shù)或arguments對(duì)象的一個(gè)元素)
function addTen(num){
num+=10;
return num;
}
var count=20;
var result=addTen(count);
console.log(count);//20
console.log(result);//30
2.引用類型值
在向參數(shù)傳遞引用類型的值時(shí),會(huì)把這個(gè)值在內(nèi)存中的地址復(fù)制給一個(gè)局部變量偿曙,因此這個(gè)局部變量的變化會(huì)反應(yīng)在函數(shù)的外部氮凝。
function setName(obj){
obj.name="test"
}
var person=new Object();
setName(person)
console.log(person.name);//test
當(dāng)在函數(shù)內(nèi)部重寫(xiě)引用類型的參數(shù)時(shí),這個(gè)變量的引用就是一個(gè)局部對(duì)象了遥昧。而這個(gè)局部對(duì)象會(huì)在函數(shù)執(zhí)行完畢后立即被銷毀覆醇。
function setName(obj){
obj.name="test";
console.log(person.name);//test
obj=new Object();
obj.name="white";
console.log(person.name);//test
}
var person=new Object();
setName(person)
函數(shù)屬性
length屬性
arguments對(duì)象的length屬性表示實(shí)參個(gè)數(shù),而函數(shù)的length屬性則表示形參個(gè)數(shù)炭臭。
function add(x,y){
console.log(arguments.length)//3
console.log(add.length)//2
}
add(1,2,3)
name屬性
函數(shù)定義了一個(gè)非標(biāo)準(zhǔn)的name屬性永脓,通過(guò)這個(gè)屬性可以訪問(wèn)到給定函數(shù)指定的名字,這個(gè)屬性的值永遠(yuǎn)等于跟在function關(guān)鍵字后面的標(biāo)識(shí)符鞋仍,匿名函數(shù)的name屬性為空
//IE11-瀏覽器無(wú)效常摧,均輸出undefined
//chrome在處理匿名函數(shù)的name屬性時(shí)有問(wèn)題,會(huì)顯示函數(shù)表達(dá)式的名字
function fn(){};
console.log(fn.name);//'fn'
var fn = function(){};
console.log(fn.name);//'',在chrome瀏覽器中會(huì)顯示'fn'
var fn = function abc(){};
console.log(fn.name);//'abc'
注意:name屬性早就被瀏覽器廣泛支持落午,但是直到es6才將其寫(xiě)入標(biāo)準(zhǔn)
es6對(duì)這個(gè)屬性的行為做出了一些修改谎懦,如果將一個(gè)匿名函數(shù)賦值給一個(gè)變量,es5的name屬性會(huì)返回空字符串溃斋,而es6的name屬性會(huì)返回實(shí)際的函數(shù)名
var fun=function(){}
fun.name;//es5 ""
fun.name;//es6 fun
如果將一個(gè)具名函數(shù)賦值給一個(gè)變量界拦,則es5和es6的name屬性都返回這個(gè)具名函數(shù)原本的名字
var bar=function baz(){}
bar.name;//es5 baz
bar.name;//es6 baz
Function構(gòu)造函數(shù)返回的函數(shù)實(shí)例,name屬性的值是“anonymous”
(new Function).name;//anonymous
bind返回的函數(shù)梗劫,name屬性值會(huì)加上“bound”前綴
function foo(){}
foo.bind({}).name;//bound foo
(function (){}).bind({}).name;//bound
prototype屬性
每一個(gè)函數(shù)都有一個(gè)prototype屬性享甸,這個(gè)屬性指向一個(gè)對(duì)象的引用,這個(gè)對(duì)象稱作原型對(duì)象梳侨。每一個(gè)函數(shù)都包含不同的原型對(duì)象蛉威。將函數(shù)用作構(gòu)造函數(shù)時(shí),新創(chuàng)建的對(duì)象會(huì)從原型對(duì)象上繼承屬性
function fn(){}
var obj=new fn;
fn.prototype.a=1;
console.log(obj.a);//1
函數(shù)方法
apply()和call()
每個(gè)函數(shù)都包含兩個(gè)非繼承而來(lái)的方法走哺,apply()和call().這兩個(gè)方法的用途都是在特定的作用域中調(diào)用函數(shù)蚯嫌,實(shí)際上等于函數(shù)體內(nèi)this對(duì)象的值。
要想以函數(shù)對(duì)象o的方法來(lái)調(diào)用函數(shù)f(),可以這樣使用call()和apply()
f.call(o)
f.apply(o)
假設(shè)o中不存在m方法丙躏,則等價(jià)于
o.m = f; //將f存儲(chǔ)為o的臨時(shí)方法
o.m(); //調(diào)用它择示,不傳入?yún)?shù)
delete o.m; //將臨時(shí)方法刪除
下面是一個(gè)實(shí)際的例子
window.color="red";
var o={color:"blue"};
function saycolor(){
console.log(this.color)
}
sayColor()//red
sayColor.call(this);//red
sayColor.call(window);//red
sayColor.call(o);//blue
//sayColor.call(o)等價(jià)于
o.sayColor=sayColor;
o.sayColor();//blue
delete o.sayColor;
apply()方法接收兩個(gè)參數(shù):一個(gè)是在其中運(yùn)行函數(shù)的作用域(或者可以說(shuō)是要調(diào)用函數(shù)的母對(duì)象,它是調(diào)用上下文彼哼,在函數(shù)體內(nèi)通過(guò)this來(lái)獲得對(duì)他的引用)对妄,另一個(gè)是參數(shù)數(shù)組。其中敢朱,第二個(gè)參數(shù)可以是array的實(shí)例,也可以是arguments對(duì)象
function sum(num1,num2){
return num1+num2;
}
//因?yàn)檫\(yùn)行函數(shù)的作用域是全局作用域摩瞎,所以this代表的是window對(duì)象
function callSum(num1,num2){
return sum.apply(this,arguments)
}
function callSum2(num1,num2){
return sum.apply(this,[num1,num2])
}
console.log(callSum(10,10));//20
console.log(callSum2(10,10));//20
call()方法與apply()方法的作用相同拴签,它們的區(qū)別僅僅在于接收參數(shù)的方式不同,對(duì)于call方法而言旗们,第一個(gè)參數(shù)是this值沒(méi)有變化蚓哩,變化的是其余參數(shù)都直接傳遞給函數(shù)。換句話說(shuō)上渴,在使用call()方法時(shí)岸梨,傳遞給函數(shù)的參數(shù)必須逐個(gè)列舉出來(lái)
function sum(num1, num2){
return num1 + num2;
}
function callSum(num1, num2){
return sum.call(this, num1, num2);
}
console.log(callSum(10,10)); //20
至于是使用apply()還是call(),完全取決于采取哪種函數(shù)傳遞參數(shù)的方式最方便。如果打算直接傳入arguments對(duì)象稠氮,或者包含函數(shù)中先接收到的也是一個(gè)數(shù)組曹阔,那么使用apply()肯定更方便,否則隔披,選擇call()可能更合適
在非嚴(yán)格模式下赃份,使用函數(shù)的call()或apply()方法時(shí),null或undefined值會(huì)被轉(zhuǎn)換為全局對(duì)象。而在嚴(yán)格模式下抓韩,函數(shù)的this值始終是指定的值
var color = 'red';
function displayColor(){
console.log(this.color);
}
displayColor.call(null);//red
var color = 'red';
function displayColor(){
'use strict';
console.log(this.color);
}
displayColor.call(null);//TypeError: Cannot read property 'color' of null
應(yīng)用
1.調(diào)用對(duì)象的原生方法
var obj={};
obj.hasOwnProperty("toString");//false
obj.hasOwnProperty=function(){
return true;
}
obj.hasOwnProperty("toString");//true
Object.prototype.hasOwnProperty.call(obj,"toString");false
2.找出數(shù)組中的最大值
js不提供找出數(shù)組最大元素的函數(shù)纠永,結(jié)合使用apply方法和math.max方法,就可以返回?cái)?shù)組的最大元素
var a=[1,33,2,4,5,6];
Math.max.apply(null,a)
3.將數(shù)組對(duì)象轉(zhuǎn)換成真正的數(shù)組
Array.prototype.slice.apply({0:1,length:1})//[1]
或者
[].prototype.slice.apply({0:1,length:1})
4.將一個(gè)數(shù)組的值push到另一個(gè)數(shù)組中
var a=[];
Array.prototype.push.apply(a,[1,2,3])
console.log(a);//[1,2,3]
Array.prototype.push.apply(a,[2,3,4]);
console.log(a);//[1,2,3,2,3,4]
5.綁定回調(diào)函數(shù)的對(duì)象
由于apply方法或者call方法不僅綁定函數(shù)執(zhí)行時(shí)所在的對(duì)象谒拴,還會(huì)立即執(zhí)行函數(shù)尝江,因此不得不把綁定語(yǔ)句寫(xiě)在函數(shù)體內(nèi),更簡(jiǎn)潔的寫(xiě)法是采用下面的bind方法
var o={};
o.f=function(){
console.log(this===o)
}
var f=function(){
o.f.apply(o)
}
bind()方法
bind()是es5新增的方法英上,這個(gè)方法的主要作用是將函數(shù)綁定到某個(gè)對(duì)象上
當(dāng)在函數(shù)f()上調(diào)用bind()方法并傳入一個(gè)對(duì)象o作為參數(shù)炭序,這個(gè)方法將返回一個(gè)新的對(duì)象。以函數(shù)調(diào)用的方式調(diào)用新的函數(shù)將會(huì)把原始的函數(shù)f()當(dāng)作o的方法調(diào)用善延,傳入新函數(shù)的任何實(shí)參都將傳入原始函數(shù)
function f(y){
return this.x+y;
}
var o={x:1};
var g=f.bind(o);
g(2)
兼容代碼
function bind(f,o){
if(f.bind){
return f.bind(o)
}else{
return function(){
return f.apply(o,arguments)
}
}
}
bind方法不僅是將函數(shù)綁定到一個(gè)對(duì)象上少态,它還附帶一些其他應(yīng)用:除了第一個(gè)實(shí)參外,傳入bind的實(shí)參也會(huì)綁定到this易遣,這個(gè)附帶的應(yīng)用是一種常見(jiàn)的函數(shù)式編程及時(shí)彼妻,稱柯里化
var sum=function(x,y){
return x+y;
}
var succ=sum.bind(null,1);
succ(2);//3,x綁定到1,并傳入2作為實(shí)參y
function f(y,z){
return this.x+y+z;
}
var g=f.bind({x:1},2)
g(3);//6,this.x綁定到1豆茫,y綁定到2,z綁定到3
function getConfig(colors,size,other){
console.log(colors,size,other)
}
var default=getConfig.bind(null,"#000","1024*234");
default("123")
default("456")
toString()
函數(shù)的toString()實(shí)例方法返回函數(shù)代碼的字符串侨歉,而靜態(tài)的toString()方法返回一個(gè)類似’[native code]’的字符串作為函數(shù)體
function test(){
alert(1)
}
test.toString()
Function.toString()
toLocalString()
toLocalString()方法和toString()方法返回的結(jié)果相同
function test(){
alert(1);//test
}
test.toLocaleString();/*"function test(){
alert(1);//test
}"*/
Function.toLocaleString();//"function Function() { [native code] }"
valueOf()
函數(shù)的valueOf()方法返回函數(shù)本身
function test(){
alert(1);//test
}
test.valueOf();/*function test(){
alert(1);//test
}*/
typeof test.valueOf();//'function'
Function.valueOf();//Function() { [native code] }