国产精品天干天干,亚洲毛片在线,日韩gay小鲜肉啪啪18禁,女同Gay自慰喷水

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

來(lái)寫(xiě)一個(gè)簡(jiǎn)單的計(jì)算器吧!(JS)

2018-01-25 20:28 作者:MXXXXXS  | 我要投稿

每個(gè)簡(jiǎn)單易用的設(shè)計(jì)背后,必定有縝密細(xì)心的邏輯。

這是我在試著寫(xiě)完這個(gè)自認(rèn)為大概應(yīng)該再?zèng)]有什么bug的計(jì)算器后最大的感嘆。從未想過(guò)只有加減乘除,還不帶括號(hào)的簡(jiǎn)單計(jì)算器,具體寫(xiě)起來(lái)還真不簡(jiǎn)單。

一開(kāi)始思路就沒(méi)對(duì),只是想到哪寫(xiě)哪,然而越寫(xiě)就邏輯越復(fù)雜就越亂,最后決定重新思考整個(gè)構(gòu)建模式,以下是個(gè)人覺(jué)得應(yīng)該對(duì)的思路。

從需求出發(fā)

應(yīng)該能保留輸入歷史,一行一行顯示
按等號(hào)就換行,計(jì)算輸出
輸錯(cuò)能退格,能全部清除
結(jié)果能作為輸入繼續(xù)運(yùn)算

具體計(jì)算有兩種思路:

1.用eval函數(shù)直接傳入表達(dá)式計(jì)算

2.用逆波蘭表達(dá)式和棧,分析出輸入的值來(lái)計(jì)算

從偷懶的角度考慮,還是果斷選前者了!


開(kāi)始


關(guān)鍵思維是這樣的:

從整體上先對(duì)計(jì)算器的狀態(tài)進(jìn)行劃分:初始輸入狀態(tài),正常輸入狀態(tài),結(jié)果狀態(tài)

分別記作0,1,2,通過(guò)狀態(tài)來(lái)控制輸入

0狀態(tài):準(zhǔn)備首次輸入,或是全部清零后準(zhǔn)備輸入

1狀態(tài):在首次輸入之后準(zhǔn)備繼續(xù)輸入(還沒(méi)按等號(hào)),或是按等號(hào)以后,使用結(jié)果繼續(xù)準(zhǔn)備計(jì)算

2狀態(tài):按下等號(hào)以后


為什么要?jiǎng)澐譅顟B(tài)?

換行的需求導(dǎo)致。0狀態(tài),需要新建一行來(lái)準(zhǔn)備輸入用,2狀態(tài),在不需要接著結(jié)果算的時(shí)候也要新建一行。

一行使用一個(gè)<p>元素,用id區(qū)分,id每行加一,從0開(kāi)始。新建一行這個(gè)操作就可以寫(xiě)成一個(gè)函數(shù)以備后用

let newLine = function() {

    count++;

    let newLine = document.createElement("p");

    newLine.setAttribute("id", count);

    results.appendChild(newLine);

  }

其中count記錄了當(dāng)前行,count即是id,初始化count = -1

狀態(tài)使用flag記錄,初始化flag = 0


對(duì)于輸入類(lèi)型,也進(jìn)行了以下劃分,共七種

等號(hào)輸入

點(diǎn)號(hào)輸入

非零數(shù)字輸入

零輸入

運(yùn)算符輸入

回退輸入

清零輸入

其中對(duì)于數(shù)字,為什么要?jiǎng)澐殖?,還是因?yàn)槠涮厥庑?/p>


零會(huì)對(duì)后續(xù)輸入產(chǎn)生影響,而其余的輸入只是依據(jù)先前狀態(tài)決定自身行為

舉例:

首次輸入時(shí),按下0,顯然其后不應(yīng)跟數(shù)字,應(yīng)該是點(diǎn)號(hào),意指輸入一個(gè)小數(shù)

這樣,零其實(shí)和狀態(tài)flag相似,因此在狀態(tài)控制上再加一維,初始化zeroSwitch = 0

接著例子,輸入零后,使zeroSwitch = 1,zeroSwitch用0和1來(lái)控制,相當(dāng)于是一個(gè)篩子,之后只能輸點(diǎn)號(hào),或清除


所以全部的狀態(tài)有三種:count,flag,zeroSwitch


接著來(lái)看輸入

輸入一共有七種類(lèi)型,分別對(duì)應(yīng)一個(gè)函數(shù)

對(duì)于零的輸入,zero函數(shù):

let zero = function() {

    if (zeroSwitch != 1) {  //強(qiáng)制在zeroSwitch=1時(shí),其后只能輸入點(diǎn)號(hào)

      if (flag != 1) {  //0,2狀態(tài),新建一行

        newLine();

        flag = 1;  //變成正常行

        zeroSwitch = 1;    //新建一行后輸入零,zeroSwitch需要置1,因?yàn)樵摿闶且粋€(gè)數(shù)字之始

        document.getElementById(count).innerHTML += event.target.value; //插入輸入的值

      } else {

        let theString = document.getElementById(count).innerHTML,

          lastWord = theString[theString.length - 1],

          Ope = RegExp(/[-x÷\+]/);

        if (Ope.test(lastWord)) {  //匹配已經(jīng)輸入的最后一個(gè)字符,如果是運(yùn)算符,則這個(gè)零是一個(gè)數(shù)字之始,后也只跟點(diǎn)號(hào)

          zeroSwitch = 1;

          document.getElementById(count).innerHTML += event.target.value;

        } else {   //非數(shù)字之始,沒(méi)限制

          document.getElementById(count).innerHTML += event.target.value;

        }

      }

    }

  }


對(duì)于點(diǎn)號(hào)輸入,dot函數(shù):

dot = function() {

    if (flag != 1) {

      newLine();

      flag = 1;

      zeroSwitch = 0;  //零輸入后,只能跟點(diǎn)號(hào)的狀態(tài)關(guān)閉

      document.getElementById(count).innerHTML += event.target.value;

    } else {

      let theString = document.getElementById(count).innerHTML,

        i = theString.length - 1;

      Ope = RegExp(/[-x÷\+]/);

      dots = RegExp(/\./);

      for (i; i >= 0; i--) {     //從后往前檢查已輸入值,一個(gè)數(shù)字內(nèi)是不會(huì)有兩個(gè)點(diǎn)號(hào)的

        if (dots.test(theString[i])) { //遇到一個(gè)數(shù)字內(nèi)已有點(diǎn)號(hào),就不輸入了  

          break;

        } else if (Ope.test(theString[i])) {  //沒(méi)有點(diǎn)號(hào),先找到了一個(gè)運(yùn)算符,就可以輸入

          zeroSwitch = 0;

          document.getElementById(count).innerHTML += event.target.value;

          break;

        }

      }

      if (i < 0) {  //全部檢查完了,既沒(méi)點(diǎn)號(hào)又沒(méi)運(yùn)算符,那就輸入唄

        zeroSwitch = 0;

        document.getElementById(count).innerHTML += event.target.value;

      }

    }

  }


對(duì)于等號(hào)輸入,equal函數(shù):

equal = function() {

    if (flag != 0) {

      let buffer;  //因?yàn)橛?jì)劃的輸入是數(shù)學(xué)符號(hào),乘和除,運(yùn)算時(shí)要轉(zhuǎn)換

      buffer = document.getElementById(count).innerHTML.replace(/x/g, "*");

      buffer = buffer.replace(/÷/g, "/");

      try { //萬(wàn)一式子不對(duì)呢

        if (new Function("return " + buffer)()) {  //構(gòu)造函數(shù)算值,實(shí)際就是eval函數(shù)

          newLine();

          flag = 2; //轉(zhuǎn)為結(jié)果行狀態(tài)

          document.getElementById(count).innerHTML = new Function("return " + buffer)();

        }

      } catch (e) {}

    }

  }


對(duì)于數(shù)字輸入,num函數(shù):

num = function() {

    if (zeroSwitch != 1) {  //就是零輸入的大篩子

      if (flag != 1) {

        newLine();

        flag = 1;

        document.getElementById(count).innerHTML += event.target.value;

      } else {

        document.getElementById(count).innerHTML += event.target.value;

      }

    }

  }

對(duì)于運(yùn)算符輸入,ope函數(shù):

ope = function() {

    if (zeroSwitch != 1) {

      let validOpe = RegExp(/[-\+]/),

        reValidOpe = RegExp(/[x÷]/),

        Ope = RegExp(/[-x÷\+]/);

      if (flag == 0) {

        if (validOpe.test(event.target.value)) { //允許正負(fù)號(hào)開(kāi)頭

          newLine();

          flag = 1;

          document.getElementById(count).innerHTML += event.target.value;

        }

      } else if (flag == 1) {

        let theString = document.getElementById(count).innerHTML,

          lastWord = theString[theString.length - 1];

        if (reValidOpe.test(lastWord) && event.target.value == "-") {//禁止符號(hào)重復(fù)輸入,但可以輸入負(fù)號(hào),表示負(fù)數(shù)

          document.getElementById(count).innerHTML += event.target.value;

        } else if (!Ope.test(lastWord)) { //前面沒(méi)符號(hào)就接著輸入唄

          document.getElementById(count).innerHTML += event.target.value;

        }

      } else { //結(jié)果行,連算

        flag = 1;

        document.getElementById(count).innerHTML += event.target.value;

      }

    }

  }

對(duì)于回退,back函數(shù):

back = function() {

    let theString = document.getElementById(count).innerHTML;

    if (flag == 2) {  //結(jié)果行回退,自然轉(zhuǎn)換為正常輸入了

      document.getElementById(count).innerHTML = theString.slice(0, theString.length - 1);

      flag = 1;

      zeroSwitch = 0;

    } else if (flag == 1) {

      document.getElementById(count).innerHTML = theString.slice(0, theString.length - 1);

      zeroSwitch = 0;

    }

  }

對(duì)于清零,allClear函數(shù):

allClear = function() {

    if (flag != 0) {

      let allNodes = results.childNodes;

      for (let i = allNodes.length - 1; i >= 0; i--) {//從后往前刪,方便

        results.removeChild(allNodes.item(i));

      }

      flag = 0;

      count = -1;

      zeroSwitch = 0;

    }

  }

最后的完工

operator.addEventListener("click", //操作面板,一整塊區(qū)域

  function functionName(event) {//事件委托一下

    if (event.target && event.target.nodeName.toLowerCase() == "button") {

      clicked = event.target.className;

      eval(clicked + "()");//拼湊出調(diào)用的函數(shù)

      results.scrollTo(0, results.offsetHeight);//這個(gè)么,在你輸入過(guò)多東西的時(shí)候,滾動(dòng)條置底

    }

  });

這里是鏈接

https://codepen.io/mxxxxxs/full/vpQjJQ/

這是總的思路圖,當(dāng)時(shí)碼字的藍(lán)圖


這就是全部了,分享一下以供參考!(?ˉ?ˉ?)

來(lái)寫(xiě)一個(gè)簡(jiǎn)單的計(jì)算器吧!(JS)的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
喜德县| 博爱县| 昌邑市| 凌云县| 容城县| 诏安县| 绥德县| 建昌县| 苍梧县| 大兴区| 睢宁县| 綦江县| 九龙城区| 寿光市| 门头沟区| 蒙自县| 卓尼县| 太湖县| 宝丰县| 揭阳市| 丹寨县| 嘉峪关市| 涿鹿县| 珲春市| 邹平县| 崇阳县| 巴中市| 得荣县| 仁怀市| 理塘县| 贵阳市| 澄迈县| 宜宾县| 邹平县| 鹤峰县| 滕州市| 彭山县| 鹰潭市| 翁牛特旗| 同仁县| 海门市|