盤點(diǎn)JavaScript中Function三大用途
JavaScript中的Function對象是函數(shù),本文向大家簡單介紹一下Script中的Function(函數(shù))對象的三大用途,相信本文介紹一定會讓你有所收獲。
JavaScript中的Function(函數(shù))對象
JavaScript中的Function對象是函數(shù),函數(shù)的用途分為3類:
作為普通邏輯代碼容器;
作為對象方法;
作為構(gòu)造函數(shù)。
1.作為普通邏輯代碼容器
- functionmultiply(x,y){
- returnx*y;
- }
函數(shù)multiply封裝了兩位數(shù)的乘法運(yùn)算公式:
- varproduct=multiply(128,128);//product=16384
創(chuàng)建函數(shù)實(shí)例的方式有3種。第一種是聲明式,即像聲明變量一樣,將通過function(){}標(biāo)識符創(chuàng)建的匿名函數(shù)直接賦值給變量,以該變量作為調(diào)用時的函數(shù)名稱:
- varmultiply=function(x,y){
- returnx*y;
- }
第二種是定義式,即以function關(guān)鍵字后跟函數(shù)名稱及(){}來直接定義命名函數(shù),前面第一個multiply函數(shù)就是通過定義式創(chuàng)建的。
第三種是構(gòu)造函數(shù)式,即通過new運(yùn)算符調(diào)用構(gòu)造函數(shù)Function來創(chuàng)建函數(shù)。這種方式極不常用,因此就不作介紹了。
在創(chuàng)建函數(shù)的3種方式中,聲明式和定義式還存在細(xì)微的差別。比如下列代碼中的函數(shù)采用聲明式:
- varexample=function(){
- return1;
- }
- example();
- varexample=function(){
- return2;
- }
- example();
執(zhí)行結(jié)果如下:
- 1
- 2
而如果采用定義式,即:
- functionexample(){
- return1;
- }
- example();
- functionexample(){
- return2;
- }
- example();
那么會得到另一種結(jié)果:
- 2
- 2
即,在采用定義式創(chuàng)建同名函數(shù)時,后創(chuàng)建的函數(shù)會覆蓋先創(chuàng)建的函數(shù)。這種差別是由于JavaScript解釋引擎的工作機(jī)制所導(dǎo)致的。JavaScript解釋引擎在執(zhí)行任何函數(shù)調(diào)用之前,首先會在全局作用域中注冊以定義式創(chuàng)建的函數(shù),然后再依次執(zhí)行函數(shù)調(diào)用。由于注冊函數(shù)時,后定義的函數(shù)重寫了先定義的函數(shù),因此無論調(diào)用語句位于何處,執(zhí)行的都是后定義的函數(shù)。相反,對于聲明式創(chuàng)建的函數(shù),JavaScript解釋引擎會像對待任何聲明的變量一樣,等到執(zhí)行調(diào)用該變量的代碼時才會對變量求值。由于JavaScript代碼是從上到下順序執(zhí)行的,因此當(dāng)執(zhí)行第一個example()調(diào)用時,example函數(shù)的代碼就是首先定義代碼;而當(dāng)執(zhí)行第二個example()調(diào)用時,example函數(shù)的代碼又變成了后來定義的代碼。#p#
2.作為對象方法
JavaScript在解析代碼時,會為聲明或定義的函數(shù)指定調(diào)用對象。所謂調(diào)用對象,就是函數(shù)的執(zhí)行環(huán)境。如果函數(shù)體內(nèi)有以關(guān)鍵字this聲明的變量,則this引用的就是調(diào)用對象。
事實(shí)上,在普通的函數(shù)中,也存在調(diào)用對象,只不過這個調(diào)用對象是默認(rèn)的全局window對象而已。例如:
varproduct=window.multiply(128,128);//product=16384
這說明,默認(rèn)情況下,在全局作用域中定義或聲明的函數(shù)的調(diào)用對象就是window。
在面向?qū)ο缶幊讨?,通常將作為對象成員的函數(shù)稱為方法。例如:
- vardog={};
- dog.name=“heibao”;
- dog.age=“3months”;
- dog.shout=function(){
- return“Hello,Mynameis“+this.name+”andIam”+this.age+”old!”;
- }
- dog.shout();//“Hello,MynameisheibaoandIam3monthsold!”
有意思的是,對象也可以借用其他對象的方法:
- varcat={};
- cat.name=“xiaohua”;
- cat.age=“2years”;
- cat.greet=dog.shout;
- cat.greet();//“Hello,MynameisxiaohuaandIam2yearsold!”
另外,使用函數(shù)對象的call和apply方法,還可以動態(tài)指定函數(shù)或方法的調(diào)用對象:
- dog.shout.call(cat);
- //“Hello,MynameisxiaohuaandIam2yearsold!”
- 或者
- dog.shout.apply(cat);
- //“Hello,MynameisxiaohuaandIam2yearsold!”
#p#3.作為構(gòu)造函數(shù)
JavaScript是通過構(gòu)造函數(shù)來模擬面向?qū)ο笳Z言中的類的。例如:
- functionAnimal(sort,character){
- this.sort=sort;
- this.character=character;
- }
以Animal作為構(gòu)造函數(shù),就可以像下面這樣創(chuàng)建一個新對象:
- vardog=newAnimal(”mammal”,”fourlegs”);
創(chuàng)建dog的對象的過程如下:首先,new運(yùn)算符創(chuàng)建一個空對象({}),然后以這個空對象為調(diào)用對象調(diào)用函數(shù)Animal,為這個空對象添加兩個屬性sort和character,接著,再將這個空對象的默認(rèn)constructor屬性修改為構(gòu)造函數(shù)的名稱(即Animal;空對象創(chuàng)建時默認(rèn)的constructor屬性值是Object),并且將空對象的__proto__屬性設(shè)置為指向Animal.prototype——這就是所謂的對象初始化。最后,返回初始化完畢的對象。這里將返回的新對象賦值給了變量dog。
- dog.sort;//mammal
- dog.character;//fourlegs
- dog.constructor;//Animal
聰明的讀者結(jié)合前面介紹的內(nèi)容,可能會認(rèn)為使用new運(yùn)算符調(diào)用構(gòu)造函數(shù)創(chuàng)建對象的過程也可以像下面這樣來實(shí)現(xiàn):
- vardog={};
- Animal.call(dog,“mammal”,”fourlegs”);
表面上看,這兩行代碼與vardog=newAnimal(”mammal”,”fourlegs”);是等價的,其實(shí)卻不是。雖然通過指定函數(shù)的執(zhí)行環(huán)境能夠部分達(dá)到初始化對象的目的,例如空對象dog確實(shí)獲得了sort和character這兩個屬性:
- dog.sort;//mammal
- dog.character;//fourlegs
- dog.constructor;//Object——注意,沒有修改dog對象默認(rèn)的constructor屬性
但是,最關(guān)鍵的是新創(chuàng)建的dog對象失去了通過Animal.prototype屬性繼承其他對象的能力。只要與前面采用new運(yùn)算符調(diào)用構(gòu)造函數(shù)創(chuàng)建對象的過程對比一下,就會發(fā)現(xiàn),new運(yùn)算符在初始化新對象期間,除了為新對象添加顯式聲明的屬性外,還會對新對象進(jìn)行了一番“暗箱操作”——即將新對象的constructor屬性重寫為Animal,將新對象的__proto__屬性設(shè)置為指向Animal.prototype。雖然手工“初始化對象”也可以將dog.constructor重寫為Animal,但根據(jù)ECMA262規(guī)范,對象的__proto__屬性對開發(fā)人員是只讀的,對它的設(shè)置只能在通過new運(yùn)算符創(chuàng)建對象時由JavaScript解釋引擎替我們完成。
JavaScript是基于原型繼承的,如果不能正確設(shè)置對象的__proto__屬性,那么就意味著默認(rèn)的繼承機(jī)制會失效:
- Animal.prototype.greet=“Hi,goodlucky!”;
- dog.greet;//undefined
事實(shí)上,在Firefox中,__proto__屬性也是可寫的:
- Animal.prototype.greet=“Hi,goodlucky!”;
- dog.__proto__=Animal.prototype;
- dog.greet;//Hi,goodlucky!
但這樣做只能在Firefox中行得通。考慮到在兼容多瀏覽器,必須依賴于new運(yùn)算符,才能實(shí)現(xiàn)基于原型的繼承。
【編輯推薦】
- 深入學(xué)習(xí)JavaScript中Function對象語法
- 解析JS中定義Function的兩種實(shí)用方法
- prototype.js的Ajax對IE8兼容問題解決方案
- Javascript數(shù)組創(chuàng)建及其常見操作
- JavaScript調(diào)試工具解決IE6等多版本共存問題