国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

javascript函數中的3個高級技巧

2019-11-20 08:55:08
字體:
來源:轉載
供稿:網友

前面的話 

  函數對任何一門語言來說都是一個核心的概念,在javascript中更是如此。前面曾以深入理解函數系列的形式介紹了函數的相關內容,本文將再深入一步,介紹函數的3個高級技巧  

技巧一:作用域安全的構造函數

構造函數其實就是一個使用new操作符調用的函數 

function Person(name,age,job){  this.name=name;  this.age=age;  this.job=job;}var person=new Person('match',28,'Software Engineer');console.log(person.name);//match

如果沒有使用new操作符,原本針對Person對象的三個屬性被添加到window對象 

function Person(name,age,job){  this.name=name;  this.age=age;  this.job=job;}     var person=Person('match',28,'Software Engineer');console.log(person);//undefinedconsole.log(window.name);//match

window的name屬性是用來標識鏈接目標和框架的,這里對該屬性的偶然覆蓋可能會導致頁面上的其它錯誤,這個問題的解決方法就是創建一個作用域安全的構造函數 

function Person(name,age,job){  if(this instanceof Person){    this.name=name;    this.age=age;    this.job=job;  }else{    return new Person(name,age,job);  }}var person=Person('match',28,'Software Engineer');console.log(window.name); // ""console.log(person.name); //'match'var person= new Person('match',28,'Software Engineer');console.log(window.name); // ""console.log(person.name); //'match'

但是,對構造函數竊取模式的繼承,會帶來副作用。這是因為,下列代碼中,this對象并非Polygon對象實例,所以構造函數Polygon()會創建并返回一個新的實例 

function Polygon(sides){  if(this instanceof Polygon){    this.sides=sides;    this.getArea=function(){      return 0;    }  }else{    return new Polygon(sides);  }}function Rectangle(wifth,height){  Polygon.call(this,2);  this.width=this.width;  this.height=height;  this.getArea=function(){    return this.width * this.height;  };}var rect= new Rectangle(5,10);console.log(rect.sides); //undefined

如果要使用作用域安全的構造函數竊取模式的話,需要結合原型鏈繼承,重寫Rectangle的prototype屬性,使它的實例也變成Polygon的實例 

function Polygon(sides){  if(this instanceof Polygon){    this.sides=sides;    this.getArea=function(){      return 0;    }  }else{    return new Polygon(sides);  }}function Rectangle(wifth,height){  Polygon.call(this,2);  this.width=this.width;  this.height=height;  this.getArea=function(){    return this.width * this.height;  };}Rectangle.prototype= new Polygon();var rect= new Rectangle(5,10);console.log(rect.sides); //2

技巧二:惰性載入函數

因為各瀏覽器之間的行為的差異,我們經常會在函數中包含了大量的if語句,以檢查瀏覽器特性,解決不同瀏覽器的兼容問題。比如,我們最常見的為dom節點添加事件的函數 

function addEvent(type, element, fun) {  if (element.addEventListener) {    element.addEventListener(type, fun, false);  }  else if(element.attachEvent){    element.attachEvent('on' + type, fun);  }  else{    element['on' + type] = fun;  }}

每次調用addEvent函數的時候,它都要對瀏覽器所支持的能力進行檢查,首先檢查是否支持addEventListener方法,如果不支持,再檢查是否支持attachEvent方法,如果還不支持,就用dom0級的方法添加事件。這個過程,在addEvent函數每次調用的時候都要走一遍,其實,如果瀏覽器支持其中的一種方法,那么他就會一直支持了,就沒有必要再進行其他分支的檢測了。也就是說,if語句不必每次都執行,代碼可以運行的更快一些。

解決方案就是惰性載入。所謂惰性載入,指函數執行的分支只會發生一次

有兩種實現惰性載入的方式 

【1】第一種是在函數被調用時,再處理函數。函數在第一次調用時,該函數會被覆蓋為另外一個按合適方式執行的函數,這樣任何對原函數的調用都不用再經過執行的分支了

我們可以用下面的方式使用惰性載入重寫addEvent() 

function addEvent(type, element, fun) {  if (element.addEventListener) {    addEvent = function (type, element, fun) {      element.addEventListener(type, fun, false);    }  }  else if(element.attachEvent){    addEvent = function (type, element, fun) {      element.attachEvent('on' + type, fun);    }  }  else{    addEvent = function (type, element, fun) {      element['on' + type] = fun;    }  }  return addEvent(type, element, fun);}

在這個惰性載入的addEvent()中,if語句的每個分支都會為addEvent變量賦值,有效覆蓋了原函數。最后一步便是調用了新賦函數。下一次調用addEvent()時,便會直接調用新賦值的函數,這樣就不用再執行if語句了

但是,這種方法有個缺點,如果函數名稱有所改變,修改起來比較麻煩 

【2】第二種是聲明函數時就指定適當的函數。 這樣在第一次調用函數時就不會損失性能了,只在代碼加載時會損失一點性能

以下就是按照這一思路重寫的addEvent()。以下代碼創建了一個匿名的自執行函數,通過不同的分支以確定應該使用哪個函數實現 

var addEvent = (function () {  if (document.addEventListener) {    return function (type, element, fun) {      element.addEventListener(type, fun, false);    }  }  else if (document.attachEvent) {    return function (type, element, fun) {      element.attachEvent('on' + type, fun);    }  }  else {    return function (type, element, fun) {      element['on' + type] = fun;    }  }})();

技巧三:函數綁定

在javascript與DOM交互中經常需要使用函數綁定,定義一個函數然后將其綁定到特定DOM元素或集合的某個事件觸發程序上,綁定函數經常和回調函數及事件處理程序一起使用,以便把函數作為變量傳遞的同時保留代碼執行環境 

<button id="btn">按鈕</button><script>        var handler={    message:"Event handled.",    handlerFun:function(){      alert(this.message);    }  };btn.onclick = handler.handlerFun;</script>

上面的代碼創建了一個叫做handler的對象。handler.handlerFun()方法被分配為一個DOM按鈕的事件處理程序。當按下該按鈕時,就調用該函數,顯示一個警告框。雖然貌似警告框應該顯示Event handled,然而實際上顯示的是undefiend。這個問題在于沒有保存handler.handleClick()的環境,所以this對象最后是指向了DOM按鈕而非handler

可以使用閉包來修正這個問題 

<button id="btn">按鈕</button><script>      var handler={  message:"Event handled.",  handlerFun:function(){    alert(this.message);  }};btn.onclick = function(){  handler.handlerFun();  }</script>

當然這是特定于此場景的解決方案,創建多個閉包可能會令代碼難以理解和調試。更好的辦法是使用函數綁定
一個簡單的綁定函數bind()接受一個函數和一個環境,并返回一個在給定環境中調用給定函數的函數,并且將所有參數原封不動傳遞過去 

function bind(fn,context){  return function(){    return fn.apply(context,arguments);  }} 

這個函數似乎簡單,但其功能是非常強大的。在bind()中創建了一個閉包,閉包使用apply()調用傳入的函數,并給apply()傳遞context對象和參數。當調用返回的函數時,它會在給定環境中執行被傳入的函數并給出所有參數 

<button id="btn">按鈕</button><script> function bind(fn,context){  return function(){    return fn.apply(context,arguments);  }}     var handler={  message:"Event handled.",  handlerFun:function(){    alert(this.message);  }};btn.onclick = bind(handler.handlerFun,handler);</script>

ECMAScript5為所有函數定義了一個原生的bind()方法,進一步簡化了操作。

只要是將某個函數指針以值的形式進行傳遞,同時該函數必須在特定環境中執行,被綁定函數的效用就突顯出來了。它們主要用于事件處理程序以及setTimeout()和setInterval()。然而,被綁定函數與普通函數相比有更多的開銷,它們需要更多內存,同時也因為多重函數調用稍微慢一點,所以最好只在必要時使用。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 洪泽县| 马关县| 宁津县| 广饶县| 会昌县| 米泉市| 石渠县| 新乡县| 黄大仙区| 榆社县| 西青区| 定陶县| 夏津县| 滨海县| 伊吾县| 新龙县| 凤山县| 安远县| 北京市| 昭平县| 离岛区| 淅川县| 惠东县| 大新县| 宜章县| 湖北省| 临高县| 江达县| 绵竹市| 麻城市| 福鼎市| 南昌县| 长治县| 泽州县| 平武县| 英超| 东阿县| 丹棱县| 措勤县| 阜康市| 晴隆县|