忍者祕籍---第四章學習筆記
匿名函式
除去函式宣告外的其他函式建立方式都可以建立匿名函式,如函式方法,物件字面量函式。
JavaScript的強大之處依賴於是否將其作為函式式語言進行使用,所以在大量函式中如果使用匿名函式會節省很多不必要的變數名,方便重要的函式的呼叫。
行內函數:給匿名函式進行命名,也就是在可以命名也可以匿名的函式中選擇匿名的方式。
行內函數的作用域:行內函數只有在自身函式的內部才是可見的,就像作用域裡的變數名稱那樣,他們的作用域僅限於自身函式內。
當物件的a屬性= 物件b的屬性,如果物件b的屬性改變了,物件a的屬性也不會改變。
但是,a=b,如果b改變了那麼a也會改變。
”!!“可以將JavaScript表示式轉化為與其等值的布林值。如!!0===false !!; “help”===true.
對遞迴函式最好給函式命名而不要使用匿名函式,防止非直接的引用導致引用丟失。
將函式視為物件
函式也可以有屬性、有方法,也可以享有所有普通物件所擁有的特性,而且還擁有一個超級特性:它們可以被呼叫。
函式儲存:利用函式的屬性特性給需要新增的函式新增一個附加屬性從而實現快速判斷該函式是否已經存在於陣列中,如果不存在就新增進來,並給他新增一個屬性。
var store={ nextId:1, cache:{}, add:function(fn){ if (!fn.Id){ fn.Id=nextId++; return !!(store.cache[fn.Id]=fn); } } };
自記憶函式:這種函式能夠記憶先前計算的結果。也就是在函式內增加一個數組對已經計算過的內容進行儲存。
如判斷是否是素數的函式
function isPrime(value){ if ( !isPrime.answers) { isPrime.answers={}; } else{ if (isPrime.answers[value]!=null) { return isPrime.answers[value]; } else{ var prime=value!=1; for (var i =2; i<value; i++) { if(prime%i==0){ prime=false; break; } } return isPrime.answers[value]=prime; } } }
建立偽陣列:
var elems={
length:0,
lang:4,
add:function(elem){
Array.prototype.push.call(this,elem);
},
gather : function(id){
this.add(document.getElementById(id));
}
};
elems.gather("first");
這樣就既可以滿足對所需內容的儲存,並且可以給這個陣列新增屬性或者方法非常方便。(這裡的length會預設地在每次add進一個新dom元素後+1)。
使用apply()支援傳入陣列作為引數
比如在使用Math.min()的時候只能傳入引數並且“,”分隔開,Math.min(1,2,3);----1 如果想要傳入引數為一個數組,找出陣列中的最小值的話就可以使用apply()改支援引數型別為陣列。
function smallest(array){
return Math.min.apply(this,array);-----apply第一個引數為this相當於是函式上下文指向不改變,第二個引數為傳入的引數為smalest的引數。
}
var a=[7,1,3,4,5,2];
console.log( smallest(a) );
使用arguments進行函式過載
遍歷可變長度的引數列表:
function merge(root){
for (var i = 1; i<arguments.length; i++) {
for (var key in arguments[i]) {
root[key]=arguments[i][key];----在物件root中新增key對應的屬性名與其屬性值
}
}
return root;
}
var merged=merge({name:"Batou"},{city:"Niihama"});
console.log(merged);------{name: "Batou", city: "Niihama"}
對於檢測已經命名的形參是否已經傳入,可以使用形參名===undefined進行判斷,為true則沒有傳入,為false則已經傳入。
需要注意的是arguments並完全是一個數組,他是一個類陣列的東西,比如他可以像陣列一樣的去被遍歷,但是卻沒有陣列的那些方法,比如slice()。
如果我們需要對arguements使用陣列的那些方法,可以參考以下例子:
function multiMax(multi){
return multi*Math.max.apply(this,Array.prototype.slice.call(arguments,1));
}
console.log(multiMax(5,2,3,4,5,6));----5*6=30;
函式的length屬性:所有的函式都有length屬性
通過length屬性,可以知道聲明瞭多少個命名引數(可以通過名字訪問到的引數,也就是在function後的()裡宣告的引數)
通過arguments.length可以知道在呼叫時一共傳入了多少個引數(包括命名的和未命名的引數)。
利用引數個數進行過載
function addMethod(object,name,fn){
var old =object[name];--------裝載前一個函式,如果不符合要求則使用前一個函式
object[name]=function(){------這是一個判斷函式,判讀:如果需要引數個數等於實際引數個數,則呼叫這個新函式,如果不是那就呼叫●那個判斷函式,類似於遞迴,一層層往回呼叫,直到判斷函式滿足條件為止。
if (fn.length==arguments.length) {--------因為是在另一個函式的作用域內,所以arguments也不再是函式addMethod的arguments,這個應該是fn的arguments。這裡的意思則是如果fn的需要形引數量和實際傳入引數數量相同
return fn.apply(this,arguments);----呼叫新函式
}
else if (typeof old=="function") {-----往回查詢
return old.apply(this,arguments);
}
};
}
var ninja={
values:["Dean","Sam","Alex"]
};
addMethod(ninja,"find",function(name){
var ret ;
for (var i = 0; i<this.values.length; i++) {
if (this.values[i].indexOf(name)==0) {
ret=this.values[i];
}
}
return ret;
});
console.log( ninja.find("Sam") );-----1
很重要的一點是:arguments的指向是:在哪個函式function(){}的裡面就是指向哪個函式的引數。
判斷一個物件是否是函式
function isFunction(fn){
return Object.prototype.toString.call(fn)==="[object Function]";
}
(IE中雖然沒有直接的call和apply方法,但是object上有call)