成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

忍者級(jí)別的JavaScript函數(shù)操作

suemi / 1968人閱讀

摘要:我們需要知道的是,對(duì)于而言,匿名函數(shù)是一個(gè)很重要且具有邏輯性的特性。通常,匿名函數(shù)的使用情況是創(chuàng)建一個(gè)供以后使用的函數(shù)。截圖自忍者秘籍通過(guò)完善之前對(duì)匿名函數(shù)的粗略定義,我們可以修復(fù)解決這個(gè)問(wèn)題。

從名字即可看書(shū),此篇博客總結(jié)與《JavaScript忍者秘籍》。對(duì)于JavaScript來(lái)說(shuō),函數(shù)為第一類(lèi)型對(duì)象。所以這里,我們主要是介紹JavaScript中函數(shù)的運(yùn)用。

系列博客地址:https://github.com/Nealyang/YOU-SHOULD-KNOW-JS

匿名函數(shù)

對(duì)于什么是匿名函數(shù),這里就不做過(guò)多介紹了。我們需要知道的是,對(duì)于JavaScript而言,匿名函數(shù)是一個(gè)很重要且具有邏輯性的特性。通常,匿名函數(shù)的使用情況是:創(chuàng)建一個(gè)供以后使用的函數(shù)。

簡(jiǎn)單的舉個(gè)例子如下:

window.onload = function() {
  alert("hello");
}
var templateObj = {
    shout:function() {
      alert("作為方法的匿名函數(shù)")
    }
}
templateObj.shout();

setTimeout(function() {
  alert("這也是一個(gè)匿名函數(shù)");
},1000)

上面的一個(gè)代碼片段我就不做過(guò)多無(wú)用解釋了,比較常規(guī)。

遞歸

遞歸,說(shuō)白了,就是自己調(diào)用自己,或者調(diào)用另外一個(gè)函數(shù),但是這個(gè)函數(shù)的調(diào)用樹(shù)的某一個(gè)地方又調(diào)用了自己。所以遞歸,就產(chǎn)生了。

普通命名函數(shù)的遞歸

拿普通命名函數(shù)的遞歸最好的舉例就是用最簡(jiǎn)單的遞歸需求:檢測(cè)回文。

回文的定義如下:一個(gè)短語(yǔ),不管從哪一個(gè)方向讀,都是一樣的。檢測(cè)的工作當(dāng)然方法多樣,我們可以創(chuàng)建一個(gè)函數(shù),用待檢測(cè)的回文字符逆序生成出一個(gè)字符,然后檢測(cè)二者是否相同,如果相同,則為回文字符。

但是這種方法并不是很有逼格,確切的說(shuō),代價(jià)比較大,因?yàn)槲覀冃枰峙洳?chuàng)建新的字符。

所以,我們可以整理出如下簡(jiǎn)潔的辦法:

單個(gè)和零個(gè)字符都是回文

如果字符串的第一個(gè)字符和最后一個(gè)字符相同,并且除了兩個(gè)字符以外,別的字符也滿足該要求,那么我們就可以檢測(cè)出來(lái)了這個(gè)是回文了

function isPalindrome(txt) {
  if(txt.length<=1){
      return true;
  }
  if(txt.charAt(0)!= txt.charAt(txt.length-1)) return false;
  return isPalindrome(txt.substr(1,txt.length-2));
}

上面的代碼我們并沒(méi)有做txt的一些類(lèi)型檢測(cè),undefined、null等。

方法中的遞歸

所謂的方法,自然離不開(kāi)對(duì)象,直接看例子:

var ninja = {
    chirp:function(n) {
      return n>1?ninja.chirp(n-1)+"-chirp":"chirp";
    }
}
console.log(ninja.chirp(3))//chirp-chirp-chirp

在上述代碼中,我們通過(guò)對(duì)象ninja.chirp方法的遞歸調(diào)用了自己。但是,因?yàn)槲覀冊(cè)诤瘮?shù)上s會(huì)用了非直接引用,也就是ninja對(duì)象的chirp屬性,所以才能夠?qū)崿F(xiàn)遞歸,這也就引出來(lái)一個(gè)問(wèn)題:引用丟失

引用丟失的問(wèn)題

上面的示例代碼,依賴于一個(gè)進(jìn)行遞歸調(diào)用的對(duì)象屬性引用。與函數(shù)的實(shí)際名稱不同,因?yàn)檫@種引用可能是暫時(shí)的。

var ninja = {
    chirp:function(n) {
      return n>1?ninja.chirp(n-1)+"-chirp":"chirp";
    }
}
var samurai = {chirp:ninja.chirp};
ninja = {};

try{
    console.log(samurai.chirp(3) === "chirp-chirp-chirp")
}catch (err){
    if(err) alert(false);
}

如上,我們把ninja屬性上的方法賦值給了samurai,然后置空ninja,然后你懂得~這就是引用丟失的問(wèn)題。


截圖自《JavaScript忍者秘籍》

通過(guò)完善之前對(duì)匿名函數(shù)的粗略定義,我們可以修復(fù)解決這個(gè)問(wèn)題。在匿名函數(shù)中,我們不在使用顯示的ninja引用。這里我們使用this(關(guān)于this的使用詳解,請(qǐng)關(guān)注我的個(gè)人微信公眾號(hào):前端的全棧之路)。

var ninja = {
    chirp:function(n) {
      return n>1?this.chirp(n-1)+"-chirp":"chirp";
    }
}

當(dāng)函數(shù)作為方法被調(diào)用的時(shí)候,函數(shù)的上下文指的是該方法的對(duì)象。

使用this調(diào)用,可以讓我們的匿名函數(shù)更加的強(qiáng)大且靈活。但是。。。

內(nèi)聯(lián)命名函數(shù)

上面我們解決了作為函數(shù)方法作為遞歸時(shí)候的一個(gè)完美操作。但實(shí)際上,不管是否進(jìn)行方法遞歸,巧妙使用this都是我們應(yīng)該所掌握的(關(guān)注微信公眾號(hào),早晚都給你說(shuō)到)。

話說(shuō)回來(lái),其實(shí)這樣寫(xiě)也還是有問(wèn)題的,問(wèn)題在于給對(duì)象定義方法的時(shí)候,方法名稱是寫(xiě)死的,如果屬性名稱不一樣,豈不是一樣會(huì)丟失引用?

所以,這里我們采用另一種解決方案,給匿名函數(shù)起個(gè)名字吧!對(duì)的,肯定又人會(huì)說(shuō),我擦!那還是匿名函數(shù)么?嗯。。。好吧,那就不叫匿名函數(shù)了吧,叫內(nèi)聯(lián)函數(shù)~

var ninja = {
    chirp:function signal(n) {
      return n>1?signal(n-1)+"-chirp":"chirp";
    }
}
var samurai = {chirps:ninja.chirp};
ninja = {};

try{
    console.log(samurai.chirps(3) === "chirp-chirp-chirp")
}catch (err){
    if(err) alert(false);
}

所以如上的解決辦法,就完美解決了我們之前說(shuō)到所有問(wèn)題。內(nèi)聯(lián)函數(shù)還有一個(gè)很重要的一點(diǎn),就是盡管可以給內(nèi)聯(lián)函數(shù)進(jìn)行命名,但是這些名稱只能在自身函數(shù)內(nèi)部才可見(jiàn)。

將函數(shù)視為對(duì)象

JavaScript中的函數(shù)和其他語(yǔ)言中的函數(shù)有所不同,JavaScript賦予了函數(shù)很多的特性,其中最重要的特性之一就是函數(shù)作為第一類(lèi)型對(duì)象。是的,對(duì)象!

所以,我們可以給函數(shù)添加屬性,甚至可以添加方法。

函數(shù)存儲(chǔ)

有時(shí)候,我們可能需要存儲(chǔ)一組相關(guān)但又獨(dú)立的函數(shù),事件回調(diào)管理是最為明顯的例子。向這個(gè)集合添加函數(shù)時(shí)候,我們得知道哪些函數(shù)在集合中存在,否則不添加。

var store = {
    nextId:1,
    cache:{},
    add:function(fn) {
      if(!fn.id){
          fn.id = store.nextId++;
          return !!(store.cache[fn.id] = fn);
      }
    }
}

function ninja() {}

console.log(store.add(ninja));
console.log(store.add(ninja));

上述代碼比較簡(jiǎn)單常規(guī),也就不做過(guò)多解釋。

自記憶函數(shù)

緩存記憶是構(gòu)造函數(shù)的過(guò)程,這種函數(shù)能夠記住先前計(jì)算的結(jié)果。通過(guò)避免重復(fù)的計(jì)算,極大地提高性能。

緩存記憶昂貴的計(jì)算結(jié)果

作為一個(gè)簡(jiǎn)單的例子,這里我來(lái)判斷一個(gè)數(shù)字是否為素?cái)?shù)。

function isPrime(value) {
  if(!isPrime.answers) isPrime.answers = {};
  if(isPrime.answers[value]!=null){
      return isPrime.answers[value]
  }
  var prime = value != 1;//1 不是素?cái)?shù)
  for(var i = 2;i

如上代碼也都是常規(guī)操作,不做過(guò)多解釋。我們可以通過(guò)下面的console.log判斷出緩存是否成功。

緩存記憶有兩個(gè)主要的優(yōu)點(diǎn):

在函數(shù)調(diào)用獲取之前計(jì)算結(jié)果的時(shí)候,最終用戶享有性能優(yōu)勢(shì)

發(fā)生在幕后,完全無(wú)縫,最終用戶和開(kāi)發(fā)者都無(wú)需任何特殊的操作或者為此做任何初始化工作。

當(dāng)然,總歸會(huì)有缺點(diǎn)的

為了提高性能,任何類(lèi)型的緩存肯定會(huì)犧牲內(nèi)存

純粹主義者可能認(rèn)為緩存這個(gè)問(wèn)題不應(yīng)該與業(yè)務(wù)邏輯放到一起。一個(gè)函數(shù)或者方法只應(yīng)該做一件事。

很難測(cè)試和測(cè)量一個(gè)算法的性能。(比如我們這個(gè)“簡(jiǎn)單”的例子)

緩存DOM記憶

通過(guò)元素標(biāo)簽名來(lái)獲取DOM元素是一個(gè)非常常見(jiàn)的操作。但是性能可能不是特別好。所以從上面的緩存記憶我們可以進(jìn)行如下的騷操作:

function getElements(name) {
  if(!getElements.cache) getElements.cache = {};
  return getElements.cache[name] = getElements.cache[name]||document.getElementsByTagName(name); 
}

上面的代碼很簡(jiǎn)單,但是有么有眼前一亮的感覺(jué)呢??我有!而且我們還發(fā)現(xiàn),這個(gè)簡(jiǎn)單的緩存的代碼產(chǎn)生了5倍以上的性能提升。

我們可以將狀態(tài)和緩存信息存儲(chǔ)在一個(gè)封裝的獨(dú)立位置上,不僅在代碼組織上有好處,而且外部存儲(chǔ)或緩存對(duì)象無(wú)需污染作用域,就可以獲取性能的提升。

別激動(dòng),下面還有更多的奇淫技巧~

偽造數(shù)組方法

有時(shí)候我們想創(chuàng)建一個(gè)包含一組數(shù)據(jù)的對(duì)象。如果只是集合,則只需要?jiǎng)?chuàng)建一個(gè)數(shù)組即可。但是在某些情況下,除了集合本身,可能會(huì)有更多的狀體需要保存。

一種選擇是,每次創(chuàng)建對(duì)象新版本的時(shí)候都創(chuàng)建一個(gè)新數(shù)組,然后將元數(shù)據(jù)作為屬性或者方法添加到這個(gè)新數(shù)組上。但是這個(gè)操作太常規(guī)了。

欣賞如下騷操作:








通常,Array.prototype.push()是通過(guò)其函數(shù)上下文操作其自身數(shù)組的。這里我們通過(guò)call方法來(lái)講我們自己的對(duì)象扮演了一次他的上下文。push的方法會(huì)增加length的值(會(huì)認(rèn)為他就是數(shù)組的length屬性),然后給對(duì)象添加一個(gè)數(shù)字屬性,并將其引用到傳入的元素上。

關(guān)于函數(shù)的執(zhí)行上下文,以及prototype的一些說(shuō)明,將在后續(xù)文章寫(xiě)到。

可變函數(shù)的參數(shù)列表

JavaScript靈活且強(qiáng)大的特性之一是函數(shù)可以接受任意數(shù)量的參數(shù)。雖然JavaScript沒(méi)有函數(shù)的重載,但是參數(shù)列表的靈活性是獲取其他語(yǔ)言類(lèi)似重載功能的關(guān)鍵所在

使用apply()支持可變參數(shù)

需求:查找數(shù)組中的最大值、最小值

一開(kāi)始,我認(rèn)為Math中提供的min(),max()可以滿足,但是貌似他并不能夠找到數(shù)組中的最大值最小值,難道要我這樣:Math.min(arr[0],arr[1],arr[3]...)??

來(lái)吧,我們繼續(xù)我們的奇淫技巧。

function smallest(arr) {
  return Math.min.apply(Math,arr);
}
function largest(arr) {
  return Math.max.apply(Math,arr);
}

console.log(smallest([0,1,2,3,4]));
console.log(largest([0,1,2,3,4]));

不做過(guò)多解釋,操作常規(guī),是不是又是一個(gè)眼前一亮呢?

函數(shù)重載

之前我們有介紹過(guò)函數(shù)的隱士傳遞,arguments,也正是因?yàn)檫@個(gè)arguments的存在,才讓函數(shù)有能力處理不同數(shù)量的參數(shù)。即使我們只定義固定數(shù)量的形參,通過(guò)arguments參數(shù)我們還是可以訪問(wèn)到實(shí)際傳給函數(shù)的所有的參數(shù)。

檢測(cè)并遍歷參數(shù)

方法的重載通常是通過(guò)在同名的方法里聲明不同的實(shí)例來(lái)達(dá)到目的。但是在javascript中并非如此,在javaScript中,我們重載函數(shù)的時(shí)候只有一個(gè)實(shí)現(xiàn)。只不過(guò)這個(gè)實(shí)現(xiàn)內(nèi)部是通過(guò)函數(shù)實(shí)際傳入的參數(shù)的特性和個(gè)數(shù)來(lái)達(dá)到相應(yīng)目的的。

function merge(root){
  for(var i = 1;i

通過(guò)如上代碼,我們將傳遞給函數(shù)的對(duì)象都合并到一個(gè)對(duì)象中。在javascript中,沒(méi)有強(qiáng)制函數(shù)聲明多少個(gè)參數(shù)就得穿入多少個(gè)參數(shù)。函數(shù)是否可以成功處理這些參數(shù),完全取決于函數(shù)本身的定義。

注意,我們要做的事情是想讓第二個(gè)或者第n個(gè)參數(shù)上的屬性合并到第一個(gè)對(duì)象中,所以這個(gè)遍歷是從1開(kāi)始的。

利用參數(shù)個(gè)數(shù)進(jìn)行函數(shù)的重載

基于函數(shù)的參數(shù),有很多種辦法進(jìn)行函數(shù)的重載。一種通用的方法是,根據(jù)傳入?yún)?shù)的類(lèi)型執(zhí)行不同的操作。另一種辦法是,可以通過(guò)某些特定參數(shù)是否存在來(lái)進(jìn)行判斷。還有一種是通過(guò)傳入?yún)?shù)個(gè)數(shù)來(lái)進(jìn)行判斷。

假如對(duì)象上有一個(gè)方法,根據(jù)傳入?yún)?shù)的個(gè)數(shù)來(lái)執(zhí)行不同的操作,冗長(zhǎng)且呆呆的函數(shù)應(yīng)該張這樣:

var ninja = {
  whatever:function(){
    switch(arguments.length){
      case:0:
       //do something
       break;
        case:1:
       //do something
       break;
        case:2:
       //do something
       break;
        case:3:
       //do something
       break;

    }
  }
}

這種方式,看起來(lái)非常的呆呆的。所以我們換一種方式來(lái)說(shuō)下。

如果按照如下思路,添加重載的方法會(huì)怎樣呢。

var ninja = {};
addMethod(ninja,"whatever",function(){/*do something*/});
addMethod(ninja,"whatever",function(a){/*do something*/});
addMethod(ninja,"whatever",function(a,b){/*do something*/});

這里我們使用同樣的名稱(whatever)將方法添加到該對(duì)象上,只不過(guò)每個(gè)重載的函數(shù)是多帶帶的。注意每一個(gè)重載的函數(shù)參數(shù)是不同的。通過(guò)這種方式,我們真正為每一個(gè)重載都創(chuàng)建了一個(gè)獨(dú)立的匿名函數(shù)。漂亮且簡(jiǎn)潔。

下面就讓我操刀來(lái)實(shí)現(xiàn)這個(gè)addMethod函數(shù)吧

function addMethod(object,name,fn){
  var old = object[name];
  object[name] = function(){
    if(fn.length === arguments.length){
      return fn.apply(this,arguments);
    }else if(typeof old == "function"){
      return old.apply(this,arguments);
    }
  }
}

這個(gè)操作我們這里解釋一下,第一步,我們保存原有的函數(shù),因?yàn)檎{(diào)用的時(shí)候可能不匹配傳入的參數(shù)個(gè)數(shù)。第二部創(chuàng)建一個(gè)新的匿名函數(shù),如果該匿名函數(shù)的形參個(gè)數(shù)和實(shí)際個(gè)數(shù)匹配,就調(diào)用這個(gè)函數(shù),否則調(diào)用原來(lái)的函數(shù)。

這里的fn.length是返回函數(shù)定義時(shí)候定義的形參個(gè)數(shù)。

下面解釋下這個(gè)函數(shù)的執(zhí)行吧。adMethod第一次調(diào)用將創(chuàng)建一個(gè)新的匿名函數(shù)傳入零個(gè)參數(shù)進(jìn)行調(diào)用的時(shí)候?qū)?huì)調(diào)用這個(gè)fn函數(shù)。由于此時(shí)這個(gè)ninja是一個(gè)新的對(duì)象,所以不必?fù)?dān)心之前創(chuàng)建過(guò)的方法。

第二次調(diào)用addMethod的時(shí)候,首先將之前的同名函數(shù)保存到一個(gè)變量old中,然后將新創(chuàng)建的匿名函數(shù)作為方法。新方法首先檢查傳入的個(gè)數(shù)是否為1,如果是則調(diào)用新傳入的fn,如果不是,則調(diào)用舊的。重新調(diào)用該函數(shù)的時(shí)候?qū)⒃诖藱z查參數(shù)個(gè)數(shù)是否為0

這種調(diào)用方式類(lèi)似于剝洋蔥,每一層都檢查參數(shù)個(gè)數(shù)是否匹配。這里的一個(gè)技巧是關(guān)于內(nèi)部匿名函數(shù)是否合訪問(wèn)到old和fn的。這個(gè)關(guān)于函數(shù)閉包的知識(shí)就在下一篇博客講解(關(guān)注微信公眾號(hào)吧)

function addMethod(object,name,fn){
  var old = object[name];
  object[name] = function(){
    if(fn.length === arguments.length){
      return fn.apply(this,arguments);
    }else if(typeof old == "function"){
      return old.apply(this,arguments);
    }
  }
}

var ninjas = {
  values:["Neal","yang","Nealyang","Neal yang"]
}

addMethod(ninjas,"find",function(){
  return this.values;
});

addMethod(ninjas,"find",function(name){
  var ret = [];
  for(var i = 0;i

關(guān)于上面使用的閉包想關(guān)注的知識(shí),將在下一篇博客中,為大家總結(jié)。

然后使用如上的技巧的時(shí)候需要注意下面幾點(diǎn):

重載是適用于不同數(shù)量的參數(shù),不區(qū)分類(lèi)型、參數(shù)名稱或者其他東西

這樣的重載方法會(huì)有一些函數(shù)調(diào)用的開(kāi)銷(xiāo)。我們要考慮在高性能時(shí)的情況。

交流

掃碼關(guān)注我的個(gè)人微信公眾號(hào),分享更多原創(chuàng)文章。點(diǎn)擊交流學(xué)習(xí)加我微信、qq群。一起學(xué)習(xí),一起進(jìn)步

歡迎兄弟們加入:

Node.js技術(shù)交流群:209530601

React技術(shù)棧:398240621

前端技術(shù)雜談:604953717 (新建)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://hztianpu.com/yun/92000.html

相關(guān)文章

  • 2017年 最好javascript 書(shū)籍

    摘要:請(qǐng)記住,這些書(shū)中的一些可能不是最新的,但概念和基礎(chǔ)仍應(yīng)適用。是最好的老師之一。的秘密由部分組成。在你完成這些書(shū)后,查看書(shū)籍和最好的本土?xí)? 我看過(guò)三本,第1本,第二本,第四本。第一本買(mǎi)的的實(shí)體書(shū),其他兩本看的是電子書(shū)。第一本是大名鼎鼎老道寫(xiě)的,書(shū)很薄,但是非常經(jīng)典。javascirpt忍者秘籍是jquery的作者寫(xiě)的,也是非常經(jīng)典。you dont kown js系列也是非常好??戳?..

    mingzhong 評(píng)論0 收藏0
  • JavaScript實(shí)現(xiàn)水果忍者游戲,支持鼠標(biāo)操作

    摘要:智能手機(jī)剛剛普及時(shí),水果忍者這款小游戲可謂風(fēng)靡一時(shí)。幾年過(guò)去了,現(xiàn)在,讓我們用純來(lái)實(shí)現(xiàn)這個(gè)水果忍者游戲,就算是為了錘煉我們的開(kāi)發(fā)技能吧。那么只需要修改函數(shù),如下圖的紅色分支就是切到水果的分支,執(zhí)行加分和顯示水果被切成兩半的效果。 智能手機(jī)剛剛普及時(shí),水果忍者這款小游戲可謂風(fēng)靡一時(shí)。幾年過(guò)去了,現(xiàn)在,讓我們用純JavaScript來(lái)實(shí)現(xiàn)這個(gè)水果忍者游戲,就算是為了錘煉我們的JavaScr...

    huhud 評(píng)論0 收藏0
  • 第一章無(wú)處不在JavaScriptJavascript忍者秘籍2閱讀筆記】

    摘要:無(wú)處不在的理解語(yǔ)言與其他主流語(yǔ)言相比,函數(shù)式語(yǔ)言的血統(tǒng)更多一些。函數(shù)式語(yǔ)言一類(lèi)程序設(shè)計(jì)語(yǔ)言,是一種非馮諾伊曼式的程序設(shè)計(jì)語(yǔ)言。函數(shù)式語(yǔ)言主要成分是原始函數(shù),定義函數(shù)和函數(shù)型。性能分析內(nèi)置對(duì)象上的和方法。 無(wú)處不在的JavaScript 理解JavaScript語(yǔ)言 與其他主流語(yǔ)言相比,JavaScript函數(shù)式語(yǔ)言的血統(tǒng)更多一些。 函數(shù)式語(yǔ)言一類(lèi)程序設(shè)計(jì)語(yǔ)言,是一種非馮.諾伊曼式的程序...

    yck 評(píng)論0 收藏0
  • 閉包:私有化變量 《JavaScript高程3》 《JavaScript忍者秘籍》

    摘要:閉包閉包的特點(diǎn)就是內(nèi)部匿名函數(shù)可以訪問(wèn)外部函數(shù)作用域的變量和方法變量對(duì)象。閉包的主要表現(xiàn)形式就是匿名函數(shù),但是兩者并不是等價(jià)的。中是沒(méi)有塊級(jí)作用域的,為了在中引入塊級(jí)作用域,可以使用匿名函數(shù)模擬塊級(jí)作用域。 在介紹閉包之前,首先解釋在隨后的測(cè)試實(shí)例中會(huì)使用的assert測(cè)試函數(shù),這個(gè)方法有別于alert()測(cè)試,有很大的改進(jìn)。 assert()測(cè)試方法 #...

    selfimpr 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<