一:理解call和apply 及arguments.callee
ECMAScript3給Function的原型定義了兩個方法嘱么,他們是Function.prototype.call
和 Function.prototype.apply
. 其實他們的作用是一樣的尺上,只是傳遞的參數不一樣而已陡厘;
1. apply; 接受2個參數,第一個參數指定了函數體內this對象的指向,第二個參數為一個類似數組的集合探入,比如如下代碼:
var yunxi = function(a,b){
console.log([a,b]); // [1,2]
console.log(this === window); // true
};
yunxi.apply(null,[1,2]);
如上代碼,我們第一個參數傳入null懂诗,函數體內默認會指向與宿主對象蜂嗽,即window對象;因此我們可以在yunxi函數內打印下值為true即可看到:
下面我們來看看使用call方法的實例如下:
var yunxi = function(a,b){
console.log([a,b]); // [1,2]
console.log(this === window); // true
};
yunxi.call(null,1,2);
可以看到 call方法的第二個參數是以逗號隔開的參數殃恒;
那么call和apply用在什么地方呢植旧?
1.call和apply 最常見的用途是改變函數體內的this指向,如下代碼:
var longen = {
name:'yunxi'
};
var longen2 = {
name: '我叫涂根華'
};
var name = "我是來測試的";
var getName = function(){
return this.name;
};
console.log(getName()); // 打印 "我是來測試的";
console.log(getName.call(longen)); // 打印 yunxi
console.log(getName.call(longen2)); // 打印 "我叫涂根華"
第一次調用 getName()
方法离唐,因為它是普通函數調用隆嗅,所以它的this指向與window,因此打印出全局對象的name的值侯繁;
第二次調用getName.call(longen);
執(zhí)行這句代碼后胖喳,getName這個方法的內部指針this指向于longen這個對象了,因此打印this.name
實際上是longen.name贮竟,因此返回的是name=”yunxi”;
但是this指針也有列外的情況丽焊,比如一個點擊元素,當我們點擊一個元素的時候咕别,this指針就指向與那個點擊元素技健,但是當我們在內部再包含一個函數后,在函數內再繼續(xù)調用this的話惰拱,那么現在的this指針就指向了window了雌贱;比如如下代碼:
document.getElementById("longen").onclick = function(){
console.log(this); // this 就指向于div元素對象了
var func = function(){
console.log(this); // 打印出window對象
}
func();
}
如上代碼。可以看到外部this指向與被點擊的那個元素欣孤,內部普通函數調用馋没,this指針都是指向于window對象。但是我們可以使用call或者apply方法來改變this的指針的降传;如下代碼:
document.getElementById("longen").onclick = function(){
console.log(this); // this 就指向于div元素對象了
var func = function(){
console.log(this); // 就指向于div元素對象了
}
func.call(this);
}
如上代碼我們使用call方法調用func函數篷朵,使this指向與func這個對象了痢站,當然上面的方法我們還可以不使用call或者apply方法來改變this的指針糖驴,我們可以在外部先使用一個變量來保存this的指針,在內部調用的時候我們可以使用哪個變量即可舰蟆,如下代碼演示:
document.getElementById("longen").onclick = function(){
console.log(this); // this 就指向于div元素對象了
var self = this;
var func = function(){
console.log(self); // 就指向于div元素對象了
}
func();
}
arguments.callee的理解
callee是arguments的一個屬性段只,它可以被用作當前函數或函數體執(zhí)行的環(huán)境中腮猖,或者說調用一個匿名函數;返回的是當前正在被執(zhí)行的Function對象赞枕;簡單的來說就是當前執(zhí)行環(huán)境的函數被調用時候缚够,arguments.callee對象會指向與自身,就是當前的那個函數的引用鹦赎;
如下代碼:
var count = 1;
var test = function() {
console.log(count + " -- " + (test.length == arguments.callee.length) );
// 打印出 1 -- true 2 -- true 3 -- true
if (count++ < 3) {
// 調用test()函數自身
arguments.callee();
}
};
test();
arguments.callee()
的含義是調用當前正在執(zhí)行的函數自身谍椅,比如上面的test的匿名函數;
Function.prototype.bind介紹
目前很多高級瀏覽器都支持Function.prototype.bind
方法古话,該方法用來指定函數內部的this指向雏吭。為了支持各個瀏覽器,我們也可以自己來簡單的模擬一個~
如下代碼:
Function.prototype.bind = function(context) {
var self = this;
return function(){
return self.apply(context,arguments);
}
}
var yunxi = {
name: 'yunxi'
};
var func = function(){
console.log(this.name); // yunxi
}.bind(yunxi);
func();
如上代碼所示:func這個函數使用調用bind這個方法陪踩,并且把對象yunxi作為參數傳進去杖们,然后bind函數使用return返回一個函數,當我們調用func()
執(zhí)行這個方法的時候肩狂,其實我們就是在調用bind方法內的return返回的那個函數摘完,在返回的那個函數內context的上下文其實就是我們以參數yunxi對象傳進去的,因此this指針指向與yunxi這個對象了~ 所以打印出this.name
就是yunxi那個對象的name了;
除了上面我們看到的介紹apply或者call方法可以改變this指針外傻谁,我們還可以使用call或者apply來繼承對象的方法孝治;實質也就是改變this的指針了;
比如有如下代碼:
var Yunxi = function(name){
this.name = name;
};
var Longen = function(){
Yunxi.apply(this,arguments);
};
Longen.prototype.getName = function(){
return this.name;
};
var longen = new Longen("tugenhua");
console.log(longen.getName()); // 打印出tugenhua
如上代碼:我先實例化Longen這個對象审磁,把參數傳進去谈飒,之后使用Yunxi.apply(this,arguments)
這句代碼來改變Longen這個對象的this的指針,使他指向了Yunxi這個對象态蒂,因此Yunxi這個對象保存了longen這個實例化對象的參數tugenhua杭措,因此當我們調用longen.getName
這個方法的時候,我們返回this.name
钾恢,即我們可以認為返回的是Yunxi.name
因此返回的是 tugenhua手素,我們只是借用了下Yunxi這個對象內的this.name
來保存Longen傳進去的參數而已鸳址;
二:閉包的理解
閉包的結構有如下2個特性
1.封閉性:外界無法訪問閉包內部的數據,如果在閉包內聲明變量泉懦,外界是無法訪問的稿黍,除非閉包主動向外界提供訪問接口;
2.持久性:一般的函數祠斧,調用完畢之后,系統(tǒng)自動注銷函數拱礁,而對于閉包來說琢锋,在外部函數被調用之后,閉包結構依然保存在
系統(tǒng)中呢灶,閉包中的數據依然存在吴超,從而實現對數據的持久使用。
缺點:
使用閉包會占有內存資源鸯乃,過多的使用閉包會導致內存溢出等.
如下代碼:
function a(x) {
var a = x;
var b = function(){
return a;
}
return b;
}
var b = a(1);
console.log(b()); // 1
首先在a函數內定義了2個變量鲸阻,1個是存儲參數,另外一個是閉包結構缨睡,在閉包結構中保存著b函數內的a變量鸟悴,默認情況下,當a函數調用完之后a變量會自動銷毀的奖年,但是由于閉包的影響细诸,閉包中使用了外界的變量,因此a變量會一直保存在內存當中陋守,因此變量a參數沒有隨著a函數銷毀而被釋放震贵,因此引申出閉包的缺點是:過多的使用閉包會占有內存資源,或內存溢出等肯能性水评;
// 經典的閉包實列如下:
function f(x){ //外部函數
var a = x; // 外部函數的局部變量猩系,并傳遞參數
var b = function(){ // 內部函數
return a; // 訪問外部函數中的局部變量
};
a++; // 訪問后,動態(tài)更新外部函數的變量
return b; // 返回內部函數
}
var c = f(5); // 調用外部函數并且賦值
console.log(c()); // 調用內部函數中燥,返回外部函數更新后的值為6
下面我們來看看如下使用閉包的列子
在如下代碼中有2個函數寇甸,f函數的功能是:把數組類型的參數中每個元素的值分別封裝在閉包結構中,然后把閉包存儲在一個數組中疗涉,并返回這個數組幽纷,但是在函數e中調用函數f并向其傳遞一個數組["a","b","c"]
,然后遍歷返回函數f返回數組,我們運行打印后發(fā)現都是c undefined博敬,那是因為在執(zhí)行f函數中的循環(huán)時候友浸,把值雖然保存在temp中,但是每次循環(huán)后temp值在不斷的變化偏窝,當for循環(huán)結束后收恢,此時temp值為c武学,同時i變?yōu)?,因此當調用的時候 打印出來的是temp為3伦意,arrs[3]變?yōu)閡ndefined火窒;因此打印出 c undefined
解決閉包的缺陷我們可以再在外面包一層函數,每次循環(huán)的時候驮肉,把temp參數和i參數傳遞進去 如代碼二
// 代碼一
function f(x) {
var arrs = [];
for(var i = 0; i < x.length; i++) {
var temp = x[i];
arrs.push(function(){
console.log(temp + ' ' +x[i]); // c undefined
});
}
return arrs;
}
function e(){
var ar = f(["a","b","c"]);
for(var i = 0,ilen = ar.length; i < ilen; i++) {
ar[i]();
}
}
e();
// 代碼二:
function f2(x) {
var arrs = [];
for(var i = 0; i < x.length; i++) {
var temp = x[i];
(function(temp,i){
arrs.push(function(){
console.log(temp + ' ' +x[i]); // c undefined
});
})(temp,i);
}
return arrs;
}
function e2(){
var ar = f2(["a","b","c"]);
for(var i = 0,ilen = ar.length; i < ilen; i++) {
ar[i]();
}
}
e2();
三:javascript中的this詳解
this的指向常見的有如下幾點需要常用到:
- 全局對象的this是指向與window熏矿;
- 作為普通函數調用。
- 作為對象方法調用离钝。
- 構造器調用票编。
-
Function.prototype.call
或Function.prototype.apply
調用。
下面我們分別來介紹一下
1.全局對象的this卵渴;
console.log(this); // this指向于window
setTimeout() 和 setInterval()函數內部的this指針是指向于window的慧域,如下代碼:
function test(){
console.log(11);
}
setTimeout(function(){
console.log(this === window); // true
this.test(); // 11
});
2.作為普通函數調用;
如下代碼:
var name = "longen";
function test(){
return this.name;
}
console.log(test()); // longen
當作為普通函數調用時候浪读,this總是指向了全局對象昔榴,在瀏覽器當中,全局對象一般指的是window碘橘;
3.作為對象的方法調用互订。
如下代碼:
var obj = {
"name": "我的花名改為云溪了,就是為了好玩",
getName: function(){
console.log(this); // 在這里this指向于obj對象了
console.log(this.name); // 打印 我的花名改為云溪了痘拆,就是為了好玩
}
};
obj.getName(); // 對象方法調用
但是呢屁奏,我們不能像如下一樣調用對象了,如下調用對象的話错负,this還是執(zhí)行了window坟瓢,如下代碼:
var name = "全局對象名字";
var obj = {
"name": "我的花名改為云溪了,就是為了好玩",
getName: function(){
console.log(this); // window
console.log(this.name); // 全局對象名字
}
};
var yunxi = obj.getName;
yunxi();
運行yunxi()函數犹撒,還是會像調用普通函數一樣折联,this指向了window的;
4.構造器調用识颊。
Javascript中不像Java一樣诚镰,有類的概念,而JS中只能通過構造器創(chuàng)建對象祥款,通過new 對象清笨,當new運算符調用函數時候,該函數會返回一個對象刃跛,一般情況下抠艾,構造器里面的this就是指向返回的這個對象;
如下代碼:
var Obj = function(){
this.name = "yunxi";
};
var test = new Obj();
console.log(test.name); // yunxi
注意:構造器函數第一個字母需要大寫桨昙,這是為了區(qū)分普通函數還是構造器函數而言检号;
如上代碼:通過調用new Obj()
方法 返回值保存到test變量中腌歉,那么test就是那個對象了,所以內部的this就指向與test對象了齐苛,因此test.name
就引用到了內部的this.name
即輸出 “yunxi”字符串翘盖;
但是也有例外的情況,比如構造器顯示地返回了一個對象的話凹蜂,那么這次繼續(xù)調用的話馍驯,那么會最終會返回這個對象,比如如下代碼:
var obj = function(){
this.name = "yunxi";
return {
"age": "27"
}
};
var test = new obj();
console.log(test.name); // undefined
那么繼續(xù)調用的話玛痊,會返回unedfined汰瘫,因為返回的是那個對象,對象里面沒有name這個屬性卿啡,因此值為undefined吟吝;
四:理解函數引用和函數調用的區(qū)別
看下面的代碼分析:
// 函數引用 代碼一
function f(){
var x = 5;
return x;
}
var a = f;
var b = f;
console.log(a===b); // true
// 函數調用 代碼二
function f2() {
var x = 5;
return x;
}
var a2 = f2();
var b2 = f2();
console.log(a2 === b2);
// 函數調用 代碼三
function f3(){
var x = 5;
return function(){
return x;
}
}
var a3 = f3();
var b3 = f3();
console.log(a3 === b3); // false
如上的代碼:代碼一和代碼二分部是函數引用和函數調用的列子菱父,返回都為true颈娜,代碼三也是函數調用的列子,返回且為false
我們現在來理解下函數引用和函數調用的本質區(qū)別:當引用函數時候浙宜,多個變量內存存儲的是函數的相同的入口指針官辽,因此對于同一個函數來講,無論多少個變量引用粟瞬,他們都是相等的同仆,因為對于引用類型(對象,數組裙品,函數等)都是比較的是內存地址俗批,如果他們內存地址一樣的話,說明是相同的市怎;但是對于函數調用來講岁忘,比如代碼三;每次調用的時候,都被分配一個新的內存地址区匠,所以他們的內存地址不相同干像,因此他們會返回false,但是對于代碼二來講驰弄,我們看到他們沒有返回函數麻汰,只是返回數值,他們比較的不是內存地址戚篙,而是比較值五鲫,所以他們的值相等,因此他們也返回true岔擂,我們也可以看看如下實列化一個對象的列子臣镣,他們也被分配到不同的內存地址辅愿,因此他們也是返回false的;如下代碼測試:
function F(){
this.x = 5;
}
var a = new F();
var b = new F();
console.log(a === b); // false
五:理解js中的鏈式調用
我們使用jquery的時候忆某,jquery的簡單的語法及可實現鏈式調用方法点待,現在我們自己也封裝一個鏈式調用的方法,來理解下 jquery中如何封裝鏈式調用 無非就是每次調用一個方法的時候 給這個方法返回this即可弃舒,this指向該對象自身癞埠,我們看看代碼:
// 定義一個簡單的對象,每次調用對象的方法的時候聋呢,該方法都返回該對象自身
var obj = {
a: function(){
console.log("輸出a");
return this;
},
b:function(){
console.log("輸出b");
return this;
}
};
console.log(obj.a().b()); // 輸出a 輸出b 輸出this指向與obj這個對象
// 下面我們再看下 上面的通過Function擴展類型添加方法的demo如下:
Function.prototype.method = function(name,func) {
if(!this.prototype[name]) {
this.prototype[name] = func;
return this;
}
}
String.method('trim',function(){
return this.replace(/^\s+|\s+$/g,'');
});
String.method('log2',function(){
console.log("鏈式調用");
return this;
});
String.method('r',function(){
return this.replace(/a/,'');
});
var str = " abc ";
console.log(str.trim().log2().r()); // 輸出鏈式調用和 bc
六:理解使用函數實現歷史記錄--提高性能
函數可以使用對象去記住先前操作的結果苗踪,從而避免多余的運算。比如我們現在測試一個費波納茨的算法削锰,我們可以使用遞歸函數計算fibonacci數列通铲,一個fibonacci數字是之前兩個fibonacci數字之和,最前面的兩個數字是0和1器贩;代碼如下:
var count = 0;
var fibonacci = function(n) {
count++;
return n < 2 ? n : fibonacci(n-1) + fibonacci(n-2);
};
for(var i = 0; i <= 10; i+=1) {
console.log(i+":"+fibonacci(i));
}
console.log(count); // 453
我們可以看到如上 fibonacci函數總共調用了453次颅夺,for循環(huán)了11次,它自身調用了442次蛹稍,如果我們使用下面的記憶函數的話吧黄,那么就可以減少他們的運算次數,從而提高性能唆姐;
思路:先使用一個臨時數組保存存儲結果拗慨,當函數被調用的時候,先看是否已經有存儲結果 如果有的話奉芦,就立即返回這個存儲結果赵抢,否則的話,調用函數運算下声功;代碼如下:
var count2 = 0;
var fibonacci2 = (function(){
var memo = [0,1];
var fib = function(n) {
var result = memo[n];
count2++;
if(typeof result !== 'number') {
result = fib(n-1) + fib(n-2);
memo[n] = result;
}
return result;
};
return fib;
})();
for(var j = 0; j <= 10; j+=1) {
console.log(j+":"+fibonacci2(j));
}
console.log(count2); // 29
這個函數也返回了同樣的結果烦却,但是只調用了函數29次,循環(huán)了11次减噪,也就是說函數自身調用了18次短绸,從而減少無謂的函數的調用及運算,下面我們可以把這個函數進行抽象化筹裕,以構造帶記憶功能的函數醋闭,如下代碼:
var count3 = 0;
var memoizer = function(memo,formula) {
var recur = function(n) {
var result = memo[n];
count3++; // 這句代碼只是說明運行函數多少次,在代碼中并無作用朝卒,實際使用上可以刪掉
if(typeof result !== 'number') {
result = formula(recur,n);
memo[n] = result;
}
return result;
};
return recur;
};
var fibonacci3 = memoizer([0,1],function(recur,n){
return recur(n-1) + recur(n-2);
});
// 調用方式如下
for(var k = 0; k <=10; k+=1) {
console.log(k+":"+fibonacci3(k));
}
console.log(count3); // 29
如上封裝 memoizer 里面的參數是實現某個方法的計算公式证逻,具體的可以根據需要自己手動更改,這邊的思路無非就是想習慣使用對象去保存臨時值抗斤,從而減少不必要的取值存儲值的操作囚企;
七:理解通過Function擴展類型
javascript 允許為語言的基本數據類型定義方法丈咐。通過Object.prototype
添加原型方法,該方法可被所有的對象使用龙宏。
這對函數棵逊,字符串,數字银酗,正則和布爾值都適用辆影,比如如下現在給Function.prototype
增加方法,使該方法對所有函數都可用黍特,代碼如下:
Function.prototype.method = function(name,func) {
if(!this.prototype[name]) {
this.prototype[name] = func;
return this;
}
}
Number.method('integer',function(){
return Math[this < 0 ? 'ceil' : 'floor'](this);
});
console.log((-10/3).integer()); // -3
String.method('trim',function(){
return this.replace(/^\s+|\s+$/g,'');
});
console.log(" abc ".trim()); // abc
八:理解使用模塊模式編寫代碼
使用函數和閉包可以構建模塊蛙讥,所謂模塊,就是一個提供接口卻隱藏狀態(tài)與實現的函數或對象灭衷。使用函數構建模塊的優(yōu)點是:減少全局變量的使用次慢;
比如如下:我想為String擴展一個方法,該方法的作用是尋找字符串中的HTML字符字體并將其替換為對應的字符翔曲;
// 如下代碼:
Function.prototype.method = function(name,func) {
if(!this.prototype[name]) {
this.prototype[name] = func;
return this;
}
}
String.method('deentityify',function(){
var entity = {
quot: '"',
It: '<',
gt: '>'
};
return function(){
return this.replace(/&([^&;]+);/g,function(a,b){
var r = entity[b];
return typeof r === 'string' ? r : a;
});
}
}());
console.log("&It;">".deentityify()); // <">
模塊模式利用函數作用域和閉包來創(chuàng)建綁定對象與私有成員的關聯迫像,比如在上面的deentityify()方法才有權訪問字符實體表entity這個數據對象;
模塊開發(fā)的一般形式是:定義了私有變量和函數的函數部默,利用閉包創(chuàng)建可以訪問到的私有變量和函數的特權函數侵蒙,最后返回這個特權函數造虎,或把他們保存到可以訪問的地方傅蹂。
模塊模式一般會結合實例模式使用。javascript的實例就是使用對象字面量表示法創(chuàng)建的算凿。對象的屬性值可以是數值或者函數份蝴,并且屬性值在該對象的生命周期中不會發(fā)生變化;比如如下代碼屬于模塊模式:定義了一個私有變量name屬性氓轰,和一個實例模式(對象字面量obj)并且返回這個對象字面量obj婚夫,對象字面量中的方法與私有變量name進行了綁定;
// 比如如下經典的模塊模式
var MODULE = (function(){
var name = "tugenhua";
var obj = {
setName: function() {
this.name = name;
},
getName: function(){
return this.name;
}
};
return obj;
})();
MODULE.setName()
console.log(MODULE.getName()); // tugenhua
九:理解惰性實列化
在頁面中javascript初始化執(zhí)行的時候就實例化類署鸡,如果在頁面中沒有使用這個實列化的對象案糙,就會造成一定的內存浪費和性能損耗;這時候靴庆,我們可以使用惰性實列化來解決這個問題时捌,惰性就是把實列化推遲到需要使用它的時候才去做,做到 "按需供應";
// 惰性實列化代碼如下
var myNamespace = function(){
var Configure = function(){
var privateName = "tugenhua";
var privateGetName = function(){
return privateName;
};
var privateSetName = function(name) {
privateName = name;
};
// 返回單列對象
return {
setName: function(name) {
privateSetName(name);
},
getName: function(){
return privateGetName();
}
}
};
// 存儲Configure實列
var instance;
return {
init: function(){
// 如果不存在實列炉抒,就創(chuàng)建單列實列
if(!instance) {
instance = Configure();
}
// 創(chuàng)建Configure單列
for(var key in instance) {
if(instance.hasOwnProperty(key)) {
this[key] = instance[key];
}
}
this.init = null;
return this;
}
}
}();
// 調用方式
myNamespace.init();
var name = myNamespace.getName();
console.log(name); // tugenhua
如上代碼是惰性化實列代碼:它包括一個單體Configure實列奢讨,直接返回init函數,先判斷該單體是否被實列化焰薄,如果沒有被實列化的話拿诸,則創(chuàng)建并執(zhí)行實列化并返回該實列化扒袖,如果已經實列化了,則返回現有實列亩码;執(zhí)行完后季率,則銷毀init方法,只初始化一次
十:推薦分支函數(解決兼容問題的更好的方法)
分支函數的作用是:可以解決兼容問題if或者else的重復判斷的問題描沟,我們一般的做法是:根據兼容的不同寫if蚀同,else等,這些判斷來實現兼容啊掏,但是這樣明顯就有一個缺點蠢络,每次執(zhí)行這個函數的時候,都需要進行if和else的檢測迟蜜,效率明顯不高刹孔,我們現在使用分支函數來實現當初始化的時候進行一些檢測,在之后的運行代碼過程中娜睛,代碼就無需檢測了髓霞;
// 我們先來看看傳統(tǒng)的封裝ajax請求的函數
//創(chuàng)建XMLHttpRequest對象:
var xmlhttp;
function createxmlhttp(){
if (window.XMLHttpRequest){
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else{
// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
}
// 下面我們看看分支函數代碼如下:
var XHR = (function(){
var standard = {
createXHR : function() {
return new XMLHttpRequest();
}
};
var oldActionXObject = {
createXHR : function(){
return new ActiveXObject("Microsoft.XMLHTTP");
}
};
var newActionXObject = {
createXHR : function(){
return new ActiveXObject("Msxml2.XMLHTTP");
}
};
if(standard.createXHR) {
return standard;
}else {
try{
newActionXObject.createXHR();
return newActionXObject;
}catch(e){
oldActionXObject.createXHR();
return oldActionXObject;
}
}
})();
console.log(XHR.createXHR()); //xmlHttpRequest對象
上面的代碼就是分支函數,分支的原理是:聲明幾個不同名稱的對象畦戒,且為該不同名稱對象聲明一個相同的方法方库,然后根據不同的瀏覽器設計來實現,接著開始進行瀏覽器檢測障斋,并且根據瀏覽器檢測來返回哪一個對象纵潦,不論返回的是哪一個對象,最后它一致對外的接口都是createXHR方法的垃环;
十一:惰性載入函數(也是解決兼容問題的)
和上面分支的原理是一樣的邀层,代碼也可以按照上面的推薦分支風格編碼的;解決的問題也是解決多個if條件判斷的遂庄;代碼如下:
// 代碼如下:
var addEvent = function(el,type,handler){
addEvent = el.addEventListener ? function(el,type,handler){
el.addEventListener(type,handler,false);
} : function(el,type,handler) {
el.attachEvent("on" + type,handler);
}
addEvent(el,type,handler);
};
惰性載入函數也是在函數內部改變自身的一種方式寥院,在重復執(zhí)行的時候就不會再進行檢測的;惰性載入函數的分支只會執(zhí)行一次涛目,即第一次調用的時候秸谢,其優(yōu)點如下:
要執(zhí)行的適當代碼只有在實際調用函數時才執(zhí)行。
第一次調用該函數的時候霹肝,緊接著內部函數也會執(zhí)行估蹄,但是正因為這個,所以后續(xù)繼續(xù)調用該函數的話阿迈,后續(xù)的調用速度會很快元媚;因此避免了多重條件;
十二:理解函數節(jié)流
DOM操作的交互需要更多的內存和CPU時間,連續(xù)進行過多的DOM相關的操作可能會導致瀏覽器變慢甚至崩潰刊棕,函數節(jié)流的設計思想是讓某些代碼可以在間斷的情況下連續(xù)重復執(zhí)行炭晒,實現該方法可以使用定時器對該函數進行節(jié)流操作;
比如:第一次調用函數的時候,創(chuàng)建一個定時器甥角,在指定的時間間隔下執(zhí)行代碼网严。當第二次執(zhí)行的時候,清除前一次的定時器并設置另一個嗤无,將其替換成一個新的定時器;
// 如下簡單函數節(jié)流代碼演示
var throttle = {
timeoutId: null,
// 需要執(zhí)行的方法
preformMethod: function(){
},
// 初始化需要調用的方法
process: function(){
clearTimeout(this.timeoutId);
var self = this;
self.timeoutId = setTimeout(function(){
self.preformMethod();
},100);
}
};
// 執(zhí)行操作
throttle.process();
函數節(jié)流解決的問題是一些代碼(比如事件)無間斷的執(zhí)行震束,這可能會影響瀏覽器的性能,比如瀏覽器變慢或者直接崩潰当犯。比如對于mouseover事件或者click事件垢村,比如點擊tab項菜單,無限的點擊嚎卫,有可能會導致瀏覽器會變慢操作嘉栓,這時候我們可以使用函數節(jié)流的操作來解決;
作者:涂根華
原文地址:http://www.cnblogs.com/tugenhua0707/p/5046854.html