如何編寫高質(zhì)量JS代碼(續(xù))
繼續(xù)上一篇文章《如何編寫高質(zhì)量JS代碼》今次整理一下javascript函數(shù)知識(shí)點(diǎn)。
2.使用函數(shù)
函數(shù)給程序員提供了主要的抽象功能,又提供實(shí)現(xiàn)機(jī)制。函數(shù)可以獨(dú)立實(shí)現(xiàn)其他語(yǔ)言中的多個(gè)不同的特性,例如,過(guò)程、方法、構(gòu)造函數(shù),甚至類或模塊。
2.1 理解函數(shù)調(diào)用、方法調(diào)用以及構(gòu)造函數(shù)調(diào)用之間的不同
針對(duì)面向?qū)ο缶幊?,函?shù)、方法和類的構(gòu)造函數(shù)是三種不同的概念。
使用模式:
1,函數(shù)調(diào)用
function hello(username){
return "hello" + username;
}
2,方法調(diào)用
var obj = {
hello : function(){
return "hello , " + this.username;
},
username : "floraLam"
};
ohj.hello();//"hello , floraLam"
this變量被綁定到對(duì)象是由于hello方法被定義在obj對(duì)象中,我們也可以子啊另外一個(gè)對(duì)象中賦值一份相同的函數(shù)引用,并得到相同的答案。
var obj2 = {
hello : obj.hello(),
username : "floraLam"
};
3,構(gòu)造函數(shù)使用
function User(name,passwordHash){
this.name = name;
this.passwordHash = passwordHash;
}
使用new操作符來(lái)調(diào)用User則視為構(gòu)造函數(shù)。
var u = new User("floraLam","123");
與函數(shù)調(diào)用和方法調(diào)用不同的是,構(gòu)造函數(shù)調(diào)用將一個(gè)全新的對(duì)象作為this變量的值,并隱式返回這個(gè)新對(duì)象作為調(diào)用結(jié)果。構(gòu)造函數(shù)的主要職責(zé)是初始化該新對(duì)象。
2.2 熟練掌握高階函數(shù)
高階函數(shù)無(wú)非是那些將函數(shù)作為參數(shù)或返回值的函數(shù),將函數(shù)作為參數(shù)(通常稱為回調(diào)函數(shù),因?yàn)楦唠A函數(shù)"隨后調(diào)用"它)是一種特別強(qiáng)大、富有表現(xiàn)力的慣用法,也在js程序中被大量使用。
考慮數(shù)組的標(biāo)準(zhǔn)sort方法,為了對(duì)所有數(shù)組都能工作,sort方法需要調(diào)用者決定如何比較數(shù)組中的任意兩個(gè)元素。
function compareNumber(x,y){
if(x < y){
return -1;
}
if(x > y){
return 1;
}
return 0;
}
[3,1,4,1,5,9].sort(compareNumbers);//[1,1,3,4,5,9]
[3,1,4,1,5,9].sort(function(x,y){
if(x < y){
return -1;
}
if(x > y){
return 1;
}
return 0;
});//[1,1,3,4,5,9]
上述例子使用一個(gè)匿名函數(shù)進(jìn)一步簡(jiǎn)化。
學(xué)會(huì)使用高階函數(shù)通常可以簡(jiǎn)化代碼并消除繁瑣的樣板代碼。簡(jiǎn)單的轉(zhuǎn)換字符串?dāng)?shù)組的操作我們可以使用循環(huán)這樣實(shí)現(xiàn):
var names = ["Fred","Wilma","Pebbles"];
var upper = [];
for(var i = 0,n = names.length ;i< n;i++){
upper[i] = names[i].toUpperCase();
}
upper;//["FRED","WILMA","PEBBLES"];
使用數(shù)組便利的map方法,可以消除循環(huán),僅僅使用一個(gè)局部函數(shù)就可以對(duì)元素的逐個(gè)轉(zhuǎn)換。
var names = ["Fred","Wilma","Pebbles"];
var upper = names.map(function(name){
return name.toUpperCase();
});
upper;//["FRED","WILMA","PEBBLES"];
另外,例如我們想創(chuàng)建若干個(gè)方法創(chuàng)建不同的字符串,具有共同的實(shí)現(xiàn)邏輯,每個(gè)循環(huán)通過(guò)連接每個(gè)獨(dú)立部分的計(jì)算結(jié)果來(lái)創(chuàng)建一個(gè)字符串。
function bulidString(n,callback){
var result = "";
for(var i = 0 ; i < n ;i++){
result += callback(i);
}
return result;
}
var alphabet = bulidString(26,function(i){
return String.fromCharCode(aIndex + i);
});
alphabet;//"abcdefghijklmnopqrxtuvwxyz";
var digits = buildString(10,function(i){ return i;})
digits;//"0123456789"
var random = buildString(9,function(){
random += String.fromCharCode(Math.floor(Math.random()*26)+aIndex
});
random;//"yefjmcef"(隨機(jī))
這樣能夠使得讀者更清晰了解該代碼能做什么,無(wú)須深入實(shí)現(xiàn)細(xì)節(jié)。
備注
javascript返回指定范圍的隨機(jī)數(shù)(m-n之間)的公式:Math.random()*(n-m)+m
同時(shí)要注意題目要求,是否要求返回正整數(shù)
2.3調(diào)用模式
調(diào)用一個(gè)函數(shù)將會(huì)暫停當(dāng)前函數(shù)的執(zhí)行,傳遞控制權(quán)與參數(shù)給新的函數(shù)。 除了聲明時(shí)定義的形式參數(shù),每個(gè)函數(shù)會(huì)接收到兩個(gè)新的附加參數(shù):this和arguments。
this是個(gè)很重要的參數(shù),并且它的值是由調(diào)用模式?jīng)Q定的。
以下是JavaScript中很重要的4個(gè)調(diào)用模式:
a. 方法調(diào)用模式the method invocation pattern
b. 函數(shù)調(diào)用模式the function invocation pattern
c. 構(gòu)造器調(diào)用模式the constructor invocation pattern
d. Apply調(diào)用模式the apply invocation pattern
這些模式在如何初始化關(guān)鍵參數(shù)this上存在差異
1. 方法調(diào)用模式the method invocation method
當(dāng)函數(shù)作為對(duì)象的方法的時(shí)候,我們就叫函數(shù)為方法。當(dāng)一個(gè)方法被調(diào)用的時(shí)候,this綁定到調(diào)用的對(duì)象。
var myObj={
val:0,
increment:function(inc){
this.val+=typeof inc ==="number"? inc:1;
},
get_val:function(){return this.val;}
}
myObj.increment();// 1
myObj["increment"](2);//3
小結(jié):
1、通過(guò)this可取得它們所屬對(duì)象的上下文的方法稱為公共方法
2、當(dāng)用 .或者下標(biāo)表達(dá)式 來(lái)使用一個(gè)函數(shù)的時(shí)候,就是方法調(diào)用模式,this對(duì)象綁定到前面的對(duì)象。
3,一個(gè)函數(shù)可以使用this來(lái)訪問(wèn)對(duì)象,所以它能檢索對(duì)象的值或者更改對(duì)象的值。綁定this到對(duì)象發(fā)生在調(diào)用的時(shí)候。
2. 函數(shù)調(diào)用模式the function invocation pattern
當(dāng)一個(gè)函數(shù)不是一個(gè)對(duì)象的屬性,那么它就是作為函數(shù)來(lái)調(diào)用的。當(dāng)一個(gè)函數(shù)作為函數(shù)調(diào)用模式來(lái)調(diào)用的時(shí)候,this綁定到全局對(duì)象。這是JavaScript設(shè)計(jì)時(shí)的錯(cuò)誤并延續(xù)了下來(lái)。
function add(x,y){
return x+y;
}
myObj.double=function(){
var that=this;
var helper=function(){
that.val=add(that.value,that.value);
//錯(cuò)誤的寫法可能是這樣,為什么錯(cuò)呢?因?yàn)楹瘮?shù)作為內(nèi)部函數(shù)調(diào)用的時(shí)候,this已經(jīng)綁定到了錯(cuò)誤的對(duì)象,全局對(duì)象并沒(méi)有val屬性,所以返回不正確的值。
//this.val = this.val+this.val;
}
helper();
}
myObj.double();//6
3. 構(gòu)造器調(diào)用模式the constructor invocation pattern
JavaScript是一門基于原型繼承的語(yǔ)言,這意味著對(duì)象可以直接繼承屬性從其它的對(duì)象,該語(yǔ)言是無(wú)類別的。
如果在一個(gè)函數(shù)前面帶上new來(lái)調(diào)用,那么將得到一個(gè)隱藏連接到該函數(shù)的prototype成員的新對(duì)象,同時(shí)this也將會(huì)綁定到該新對(duì)象。
new前綴也會(huì)改變r(jià)eturn語(yǔ)句的行為。這也不是推薦的編程方式。
var Foo = function(status){
this.status = status;
}
Foo.prototype.get_status = function(){
return this.status;
}
//構(gòu)造一個(gè)Foo實(shí)例
var myFoo = new Foo("bar");
myFoo.get_status();//"bar"
4. Apply調(diào)用模式the apply invocation pattern
因?yàn)镴avaScript是一個(gè)函數(shù)式的面向?qū)ο笳Z(yǔ)言,所以函數(shù)可以擁有方法。
Apply方法擁有兩個(gè)參數(shù),第一個(gè)是將綁定到this的值,第二個(gè)是參數(shù)數(shù)組,也就是說(shuō)Apply方法讓我們構(gòu)建一個(gè)數(shù)組并用其去調(diào)用函數(shù),即允許我們選擇this的值,也允許我們選擇數(shù)組的值。
var array = [3,4];
var sum = add.apply(null,array); // 7
var statusObj = {status:"ABCDEFG"};
Foo.prototype.pro_get_status = function(prefix){
return prefix +"-"+this.status;
}
var status = Foo.prototype.get_status.apply(statusObj);// "ABCDEFG"
var pro_status = Foo.prototype.get_status.apply(statusObj,["prefix"]);// "prefix -ABCDEFG"
通常情況下,函數(shù)或方法的接收者(級(jí)綁定到特殊關(guān)鍵字this的值)是由調(diào)用者的語(yǔ)法決定性的。特別地,方法調(diào)用語(yǔ)法將方法被查找對(duì)象綁定到this變量。然而,有時(shí)需要使用自定義接收者來(lái)調(diào)用函數(shù)。這時(shí)候就需要使用call方法或者bind方法自定義接收者來(lái)調(diào)用方法
2.4 使用bind方法提取具有確定接受者的方法
由于方法與值為函數(shù)的屬性沒(méi)有區(qū)別,因此也容易提取對(duì)象的方法并提取出函數(shù)作為回調(diào)函數(shù)直接傳遞給高階函數(shù)。
但這也很容易忘記將提取出來(lái)的函數(shù)的接受著綁定到該函數(shù)被提取出的對(duì)象上。
var buffer = {
entries: [],
add :function(s){
this.entries.push(s);
}
}
var source = ["867","-","5309"];
source.forEach(butter.add);//error:entries is undefined
這個(gè)時(shí)候butter.add的接受者不是butter對(duì)象。函數(shù)的接收者取決于它是如何被調(diào)用的,forEach方法在全局作用域中被調(diào)用,因此forEach方法的實(shí)現(xiàn)使用全局對(duì)象作為默認(rèn)的接收者,由于全局對(duì)象中沒(méi)有entries屬性,因此這段代碼拋出錯(cuò)誤。
forEach方法允許調(diào)用者提供一個(gè)可選的參數(shù)作為回調(diào)函數(shù)的接收者。
var source = ["867","-","5309"];
source.forEach(butter.add,butter);
但并非所有高階函數(shù)都細(xì)心周到為使用者提供回調(diào)函數(shù)的接收者。
解決方法有兩種:
1)創(chuàng)建一個(gè)顯式地一buffer對(duì)象方法的方式調(diào)用add的封裝函數(shù)。不管封裝函數(shù)如何被調(diào)用,它總能確保將其參數(shù)推送到目標(biāo)數(shù)組中。
var source = ["867","-","5309"];
source.forEach(function(s){
butter.add(s);
});
2)函數(shù)對(duì)象的bind方法需要一個(gè)接收者對(duì)象,并產(chǎn)生一個(gè)以該接收者對(duì)象的方法調(diào)用的方法調(diào)用原來(lái)的函數(shù)的封裝函數(shù)。
var source = ["867","-","5309"];
source.forEach(butter.add.bind(buffer));
備注
buffer.add.bind(buffer)創(chuàng)建一個(gè)新函數(shù)而不是修改buffer.add函數(shù):
buffer.add === buffer.add.bind(buffer); //false
以上就是本文的全部?jī)?nèi)容了,希望大家能夠喜歡。
相關(guān)文章
JavaScript獲取圖片像素顏色并轉(zhuǎn)換為box-shadow顯示
這篇文章主要介紹了JavaScript獲取圖片像素顏色并轉(zhuǎn)換為box-shadow顯示的方法,用到了HTML5中的FileReader API和getImageData,轉(zhuǎn)換為的CSS3 box-shadow也要注意瀏覽器的兼容問(wèn)題,需要的朋友可以參考下2016-03-03js Math數(shù)學(xué)簡(jiǎn)單使用操作示例
這篇文章主要介紹了js Math數(shù)學(xué)簡(jiǎn)單使用,結(jié)合實(shí)例形式分析了js Math數(shù)學(xué)相關(guān)函數(shù)的基本用法與操作注意事項(xiàng),需要的朋友可以參考下2020-03-03javascript實(shí)現(xiàn)的textarea運(yùn)行框效果代碼 不用指定id批量指定
今天在寫一個(gè)網(wǎng)頁(yè)的時(shí)候用到了N多嵌套在textarea標(biāo)簽里的代碼,定義雙擊運(yùn)行其內(nèi)的代碼段。但是每次創(chuàng)建一個(gè)這樣的可運(yùn)行的實(shí)例都要給textarea元素自定義一個(gè)id值和寫入雙擊事件,好不麻煩。2009-12-12javascript 讀取內(nèi)聯(lián)之外的樣式(style、currentStyle、getComputedStyle區(qū)別介紹
最常用的是style屬性,在JavaScript中,通過(guò)document.getElementById(id).style.XXX就可以獲取到XXX的值,但意外的是,這樣做只能取到通過(guò)內(nèi)嵌方式設(shè)置的樣式值,即style屬性里面設(shè)置的值。2010-05-05JS中使用textPath實(shí)現(xiàn)線條上的文字
最近項(xiàng)目經(jīng)理交給我一下新項(xiàng)目,要實(shí)現(xiàn)關(guān)系圖,需要在線條上繪制文字。下面小編把使用textPath實(shí)現(xiàn)線條上的文字功能分享到腳本之家平臺(tái)供大家參考2017-12-12Javascript 代碼也可以變得優(yōu)美的實(shí)現(xiàn)方法
Javascript 代碼也可以變得優(yōu)美的一些經(jīng)驗(yàn)小結(jié)。2009-06-06