<address id="ttjl9"></address>

      <noframes id="ttjl9"><address id="ttjl9"><nobr id="ttjl9"></nobr></address>
      <form id="ttjl9"></form>
        <em id="ttjl9"><span id="ttjl9"></span></em>
        <address id="ttjl9"></address>

          <noframes id="ttjl9"><form id="ttjl9"></form>

          首頁

          一個 npm 包的坎坷“續命”之生

          seo達人

          如果說 npm 的大新聞,莫過于之前的 left-pad 撤包事件,event-stream 投毒事件,Ant Design 彩蛋事件。使得很多前端開發者又開始重新思考 npm 生態時候真的存在問題?



          今天我們文章的主角是 memwatch,一個用來幫助我們檢查 Node.js 是否存在內存泄漏的庫,和這個庫傳奇的一生。



          2012 年 02 月 06 日,一位 Mozilla 的工程師 lloyd 創建了這個庫,并寫了一篇博文“Is My NodeJS Program Leaking?”(我的 Node.js 程序是否存在內存泄漏?)。這個包最初被命名為 gcstats,代碼上傳到了 github。



          6 月 27 日,npm 包改名為 memwatch,發布 0.1.1 版。



          7 月 4 日,lloyd 為這個庫添加了開源許可協議:WTFPL,發布 0.1.2 版。很多人對這個開源許可協議可能比較陌生,WTFPL 的全稱是 Do What The Fuck You Want To Public License,中文譯名:你他媽的想干嘛就干嘛公共許可證。也許就是這份協議開啟了 memwatch 庫不尋常的一生。



          2013 年 3 月 14 日,作者 lloyd 提交了最后一次代碼,發布了 0.2.2 版本。支持的 Node.js 版本為 0.6.0。隨后這個庫再也沒有更新過。



          從作者的博文和推文可以看到,作者在 2014 年離開了 Mozilla。而從作者的 github 動態更可以看出,作者應該是轉入了 golang 陣營。



          2014 年 6 月 28 日,作者的一位前同事 deepak1556 fork 了這個庫,增加了對 Node.js 0.11 的支持,并發起了合并請求。但是作者并沒有回復,也沒有合并此次請求。此時距離原作者放棄這個庫也已經過去一年多了。



          2015 年 2 月 7 日,marcominetti 又 fork 了 deepak1556 的庫,增加了對 Node.js 0.12 的支持,并向原庫發起了合并請求,同樣沒有得到作者的任何回復。于是 marcominetti 決定自立門戶,于是將 memwatch 改名為 memwatch-next 發布到了 npm。



          2017 年 1 月 27 日,如同前兩位維護者一樣,marcominetti 也最終放棄了繼續更新這個庫。到此時,此庫支持的 Node.js 版本為 4、5、6。



          2018 年 5 月 6 日,eduardbcom 又 fork 了 marcominetti 的庫,增加了 Node.js 9 的支持,并且放棄了對 Node.js 9 以下所有版本的支持。改名為 node-memwatch 并發布到了 npm。隨后再也沒有更新過代碼。



          2018 年 7 月 17 日,一位開發者 dyatko 又 fork 了 eduardbcom 的庫,增加了對 Node.js 8 的支持,并向原庫發起了合并請求,同樣沒有得到作者的任何回復。



          但在此次 pr 的評論中,另一位開發者說,airbnb 也 fork 了 marcominetti 的庫,并改名為 @airbnb/node-memwatch 發布到了 npm。



          有了大廠接手,也算是這個庫最終的歸宿吧。







          相關閱讀



          開發者對 npm 公司不滿,unpublish 了自己的所有模塊



          月下載量千萬的 npm 包被黑客篡改,Vue 開發者可能正在遭受攻擊



          駁《我不是很懂 Node.js 社區的 DRY 文化》



          機器人偽裝成人類在 GitHub 上為開源項目修復 bug




          兩欄布局

          seo達人

          兩列布局的幾種方法

          html結構

           <div class="content">

                <div class="content-left">

                  左側固定200px

                </div>

                <div class="content-right">

                  右側自適應

                </div>

           </div>



          1.通過float和margin-left

           / 清除瀏覽器默認邊距 /

                {

                  margin: 0;

                  padding: 0;

                }



                .content{

                  overflow: hidden;

                }

                /
          脫離文檔流 /

                .content-left {

                  float: left;

                  width: 200px;

                  height: 200px;

                  background: red;

                }



                .content-right {

                  /
          通過margin-left將左邊位置空出 /

                  margin-left: 200px;

                  background: blue;

                  height: 200px;

                }



          2.通過 position: absolute;絕對定位

           /
          清除瀏覽器默認邊距 /

               
          {

                  margin: 0;

                  padding: 0;

                }



                .content {

                  overflow: hidden;

                  position: relative;

                }

                / 脫離文檔流 /

                .content-left {

                  position: absolute;

                  top: 0;

                  left: 0;

                  width: 200px;

                  height: 200px;

                  background: red;

                }



                .content-right {

                  / 通過margin-left將左邊位置空出 /

                  margin-left: 200px;

                  background: blue;

                  height: 200px;

                }



          3.通過flex彈性布局

          / 清除瀏覽器默認邊距 /

                {

                  margin: 0;

                  padding: 0;

                }



                .content {

                  overflow: hidden;

                  display: flex;

                }

                .content-left {

                    /
          除了width: 200px;還可以flex-basis: 200px; /

                  width: 200px;

                  height: 200px;

                  background: red;

                }



                .content-right {

                    /
          flex:1;將剩余空間分給它 /

                  flex: 1;

                  background: blue;

                  height: 200px;

                }



          4.通過 display: table;表格布局

           /
          清除瀏覽器默認邊距 /

               
          {

                  margin: 0;

                  padding: 0;

                }



                .content {

                  overflow: hidden;

                  display: table;

                  / 必須給父級定寬不然自適應盒子沒定寬只會由內容撐開 /

                  width: 100%;

                }

                .content-left {

                  display: table-cell;

                  width: 200px;

                  height: 200px;

                  background: red;

                }



                .content-right {

                  display: table-cell;

                  background: blue;

                  height: 200px;

                }



          5.通過inline-block和calc()函數

           / 清除瀏覽器默認邊距 /

                {

                  margin: 0;

                  padding: 0;

                }



                .content {

                  /
          必須加font-size=0;把inline-block默認間距去掉,

                  不過設置后里面文字不顯示了可以給里面塊設置font-size:20px;

                  或者把兩個塊之間的換行刪掉也能去掉間距/

                  font-size: 0;

                  overflow: hidden;

                }

                .content-left {

                  font-size: 20px;

                  display: inline-block;

                  width: 200px;

                  height: 200px;

                  background: red;

                }



                .content-right {

                  font-size: 20px;

                  display: inline-block;

                  background: blue;

                  height: 200px;

                  /
          注意calc里的運算符兩邊要有空格 /

                  width: calc(100% - 200px);

                }



          6.通過float和calc()函數,左右兩塊都要浮動

           /
          清除瀏覽器默認邊距 /

               
          {

                  margin: 0;

                  padding: 0;

                }



                .content {

                  overflow: hidden;

                }

                .content-left {

                  float: left;

                  width: 200px;

                  height: 200px;

                  background: red;

                }

                .content-right {

                  float: left;

                  background: blue;

                  height: 200px;

                  / 注意calc里的運算符兩邊要有空格 /

                  width: calc(100% - 200px);

                }



          7.使用grid布局

           / 清除瀏覽器默認邊距 /

                {

                  margin: 0;

                  padding: 0;

                }



                .content {

                  overflow: hidden;

                  display: grid;

                  grid-template-columns: 200px 1fr;

                  /
          grid布局也有列等高的默認效果。需要設置: align-items: start;。 /

                  align-items: start;

                }

                .content-left {

                  height: 200px;

                  background: red;

                  /
          grid布局還有一個值得注意的小地方和flex不同:在使用margin-left的時候,

                  grid布局默認是box-sizing設置的盒寬度之間的位置。

                  而flex則是使用兩個div的border或者padding外側之間的距離。 */

                  box-sizing: border-box;

                  grid-column: 1;

                }

                .content-right {

                  background: blue;

                  height: 200px;

                  box-sizing: border-box;

                  grid-column: 2;

                }



          如何復制網頁上不能復制的文本!!!

          seo達人

             我們經常需要引用(白嫖)一些網頁上的文字,但是豆丁網,百度文庫等等設置的有復制權限,我們無法直接復制,或者復制文字有上限,提示付費。

              這里介紹幾種,都是些花里胡哨的白嫖方案:

          1.手機掃描:

              拿著手機,用手機QQ的文字掃描直接去識別問題,遇上好識別的文章短的直接就識別,但是這種方法遇到文章比較長的就十分麻煩。可以針對那些選中



          2.魔鬼牽引:

              原來在計蒜客就這樣搞,選中網站上的文字,然后用鼠標一直拖到別的頁面,或者一個記事本什么的,屢試不爽。



          3.側邊翻譯:

              側邊翻譯,火狐或者谷歌下載一些插件,比如說側邊翻譯,這個東西小巧玲瓏,選中文字側邊翻譯之后你就可以對文本進行復制了。



          4.原始查看法:

              在瀏覽器中直接F12,打開瀏覽器查看,就下面這個東西,瀏覽器你要復制的文本就在這里面,里面封裝的html語言,你可以搜索你需要找的文字,然后可以直接復制,如果想要復制多一點你也可以直接把里面的html語言拿出來解析到自己的網頁里面,然后再進行復制。





          5.氪金法:

              沒別的,充錢就完事了。



          6.某巨巨提供:

              下載一個ocr工具,類似qq掃描的功能。






          詳解函數和變量的聲明提升

          seo達人

          詳細解讀—函數和變量的聲明提升

          一 - 聲明提升常見面試題

          ?我們先以幾道面試題開頭來引入,

          ?大家可以先給自己做出一個答案,然后再看文章的思路捋一捋喲。



          來一道基礎的吧~



          var a="Hello";  

          function test(){  

            alert(a); 

            var a="World";

            alert(a);

          }

          test();



          難度+1



          var a = 1;

          function outer(){ 

            a = 2; 

            function inner(){       

                alert(a); 

                a = 4; 

            } 

            inner();



          outer(); 

          alert(a);



          繼續加油



          (function(){

            f1(); 

            f2();

            var f1 = function(){};

            function f2(){

                alert(1);

            }

          })();



          最后一道



          (function () {

             console.log(a);

             var a=1;

             function a() {

                 console.log("biu~");

             }

          })()



          二 - 究竟什么是聲明提升?

          引擎在解釋JS代碼之前,首先要對JS代碼進行編譯,其中編譯的一部分工作就是找到所有的聲明,包括變量和函數的所有聲明都會在任何代碼被執行前首先被處理。

          var a = 1這句話會被瀏覽器讀成 var a和a = 1兩句話執行,其中var a會在編譯階段就先執行了,而a = 1這段賦值代碼會在原地等待執行階段。

          console.log(a); 

          var a = 2;



          上邊這段代碼,如果代碼按照順序由上自下執行,那么執行到console.log(a);時,a還沒有聲明,所以會包一個找不到變量a的錯,但是事實上,這句話打印了一個undefined,說明a被聲明了,但是沒有被賦值,那么結合上一段的文字,我們可以得出代碼實際運行的是這樣的:



          var a;

          console.log(a);

          a = 2;



          三 - 函數的提升

          大家可能在書寫代碼的時候發現,無論函數封裝寫在前或者后,我們的函數調用都可以順利執行。



          fn1();//可以執行

          function fn1() {

              console.log("hello");

          }



          為什么呢?其實函數聲明,包括函數的代碼塊都i會被提升,所以調用函數的時候,函數聲明已經被執行過了。



          但是有個案例大家了解一下:



          fn2();//報錯,fn2不是一個函數

          var fn2 = function () {

             console.log("world");

          }



          我們可以看到 以給匿名函數賦值的形式定義函數,只會提升函數聲明,但是函數表達式卻不會被提升。因為變量fn2被提升,但是并沒有賦值,我們書寫的fn2()無法運行,而拋出了異常。

          以下就是實際執行的順序:



          var fn2;

          fn2();

          fn2 = function () {

             console.log("world")

          }



          函數優先提升

          我們都知道了,函數聲明和變量聲明都會被提升,那么遇到這樣的情況會怎么辦?



          fn3();

          var fn3=function () {

              console.log("fn3-1");

          }

          fn3();

          function fn3() {

              console.log("fn3-2");

          }



          哎呦,嘛情況,突然迷了?。?!

          ? 這個時候你就要考慮,同樣的一個變量名稱,到底是把var fn3給先提聲上去,再提升 fn3函數體?還是先提升 fn3函數體,再提升var fn3???其實都不對?。?!



          ? 答案是:函數會被優先提升,但后才是變量提升,但是當函數提升后,然后發現還有一個變量聲明和函數聲明一樣的名稱,這個就是重復聲明,那么這個var fn3 是不生效直接忽略的。



          所以實際代碼運行順序是:



          function fn3() {

             console.log("fn3-2");

          }

          fn3();//fn3-2

          fn3=function () {//var fn3因為重復聲明被忽略

             console.log("fn3-1");

          }

          fn3();//fn3-1



          當然,我們還是建議再同一個作用域重復聲明是很爛的選擇



          說在最后

          再代碼作用域中的聲明,都會在代碼執行前被首先處理,所有的聲明都會被移動到各自作用域的最頂端,這個過程就叫做聲明提升。



          四 - 答案:

          問題1:



          var a="Hello";  

          function test(){  

            alert(a); 

            var a="World";

            alert(a);

          }

          test();



          實際執行:

          var a="Hello";

          function test(){

             //作用域有聲明a,聲明提升到這里

             var a;

             alert(a);//本作用域聲明a,所以不去使用父作用域的a,但是本作用域的a沒有賦值,所以彈出undefined

             a="World";

             alert(a);//賦值后 ,彈出world

          }

          test();



          問題2:



          var a = 1;

          function outer(){ 

            a = 2; 

            function inner(){       

                alert(a); 

                a = 4; 

            } 

            inner();



          outer(); 

          alert(a);



          執行結果:



          var a = 1;

          function outer(){

             a = 2;

             function inner(){

                 //本作用域沒有聲明a,所以沒有任何提升,直接執行

                 alert(a); // 所以彈出 a為 2

                 a = 4;

             }

             inner();

          }

          outer();

          alert(a);//只有全局聲明了a,所以所有作用域使用的都是全局的a,所以a最后被賦值為4 彈出4



          問題3



          (function(){

            f1(); 

            f2();

            var f1 = function(){};

            function f2(){

                alert(1);

            }

          })();

          實際執行結果:



          (function(){

             function f2(){

                 alert(1);

             }

             var fn1;

             f1();//提升后先執行fn1(),但是fn1被提升的是變量不是函數,所以這里報錯,不是一個函數

             f2();//上一句話報錯,這句話不再運行

             f1 = function(){};

          })();



          問題4:



          (function () {

             console.log(a);

             var a=1;

             function a() {

                 console.log("biu~");

             }

          })()

          實際執行結果:



          (function () {

             function a() {

                 console.log("biu~");

             }

             console.log(a);//打印了a這個函數的函數體

             a=1;//因為函數有限聲明提升,所以這里的var a被提升時,發現重復聲明,故被忽略了var a;    

          })()


          我的 Input框 不可能這么可愛

          seo達人

          作者:陳大魚頭

          github: KRISACHAN

          <input /> 標簽是我們日常開發中非常常見的替換元素了,但是最近在刷 whattwg 跟 MDN 的時候發現 跟 <input /> 有很多相關的屬性,選擇器都沒怎么用過,所以就開篇文章來整理一下一些比較有趣或者實用的知識點。



          本篇文章默認大家已經知道 <input /> 標簽的基本用法,不會做過多的基礎說明~







          沒想到,這些選擇器居然跟 input …

          到寫文章為止,根據的 drafts 指出,一共有3大類,16種跟 input 相關的選擇。其實都挺有用的,善用它們,會讓我們的用戶體驗更加美好。



          下面我們來分享一下這3大類選擇器的作用:







          第一類:控制系(Input Control States)

          選擇器 作用

          :enabled 選擇可使用狀態的 <input /> 元素

          :disabled 選擇不可使用狀態的 <input /> 元素

          :read-only 選擇不可編輯狀態的元素(不僅僅是 <input /> )

          :read-write 選擇可編輯狀態的元素(不僅僅是 <input /> )

          :placeholder-shown 選擇 placeholder text 顯示時的元素

          :default 選擇在 <button>,<input type="checkbox" />, <input type="radio" />, 以及 <option> 上的默認狀態

          第二類:輸出系(Input Value States)

          選擇器 作用

          :checked 選擇處于選中狀態的 <input type="radio" />

          :indeterminate 選擇狀態不確定的表單元素與 <progress>

          第三類:偵查系(Input Value-checking)

          選擇器 作用

          :blank 選擇處于空值時的 <input>,暫未被瀏覽器支持

          :valid 選擇驗證通過的表單元素

          :invalid 選擇驗證不通過的表單元素

          :in-range 選擇處于指定范圍內的 <input />

          :out-of-range 選擇不處于指定范圍內的 <input />

          :required 選擇必填的表單元素

          :optional 選擇選填的表單元素

          :user-invalid 選擇用戶輸入但值非法時的 <input />,暫未被瀏覽器支持

          可怕,除了選擇器,居然還跟這些屬性有關系

          <input> 除了有很多相關的選擇器,結合不同的type還有不同的屬性可以供使用。他們的作用如下:



          屬性 作用

          maxlength 可輸入的最大長度

          minlength 可輸入的最小長度

          size 輸入框的長度

          readonly 輸入框是否只讀

          required 輸入框是否必填

          multiple 輸入框是否可以多選

          pattern 輸入框驗證規則

          min 可輸入的最小值

          max 可輸入的最大值

          step 輸入框每次的增量

          list 輸入框綁定的可選值數據

          placeholder 輸入框預選文字

          實戰

          通過上面的三類說明,我們大致了解了 <input /> 標簽的相關信息,但是你們以為我是來列list的嗎?



          當然不是,還有實操啊~







          純CSS實現表單提交功能

          首先我們來看個效果圖







          上面的效果就是一個純CSS實現的表單提交功能,這是怎么實現的呢?下面我們直接看源碼,然后一步一步地來分拆(不想看的可以直接CV下面的源碼自己做測試~)



          <style>

              :root {

                --error-color: red;

              }

              .form > input {

                margin-bottom: 10px;

              }

              .form > .f-tips {

                color: var(--error-color);

                display: none;

              }

              input[type="text"]:invalid ~ input[type="submit"],

              input[type="password"]:invalid ~ input[type="submit"] {

                display: none;

              }

              input[required]:focus:invalid + span {

                display: inline;

              }

              input[required]:empty + span {

                display: none;

              }

              input[required]:invalid:not(:placeholder-shown) + span {

                display: inline;

              }

          </style>

          <form class="form" id="form" method="get" action="/api/form">

              賬號:

              <input data-title="賬號" placeholder="請輸入正確的賬號" pattern="\w{6,10}" name="account" type="text" required />

              <span class="f-tips">請輸入正確的賬號</span>

              <br />

              密碼:

              <input data-title="密碼" placeholder="請輸入正確的密碼" pattern="\w{6,10}" name="password" type="password" required />

              <span class="f-tips">請輸入正確的密碼</span>

              <br />

              <input name="button" type="submit" value="提交" />

          </form>



          第一步:寫好基礎結構

          首先我們來把基礎結構給寫好,代碼如下:



          <style>

              :root {

                --error-color: red;

              }

              .form > input {

                margin-bottom: 10px;

              }

              .form > .f-tips {

                color: var(--error-color);

                display: none;

              }

          </style>

          <form class="form" id="form" method="get" action="/api/form">

              賬號:

              <input data-title="賬號" placeholder="請輸入正確的賬號" pattern="\w{6,10}" name="account" type="text" required />

              <span class="f-tips">請輸入正確的賬號</span>

              <br />

              密碼:

              <input data-title="密碼" placeholder="請輸入正確的密碼" pattern="\w{6,10}" name="password" type="password" required />

              <span class="f-tips">請輸入正確的密碼</span>

              <br />

              <input name="button" type="submit" value="提交" />

          </form>



          掃一眼,嗯,挺簡單的,都是常用的東西。咦,不對,這個 pattern 是什么東西?



          在這里我們重點分享下 pattern 這個屬性,這是一個用來驗證 input[value] 是否合法的屬性,里面的內容就是匹配value的,語法便是正則的語法,例子如下:



          <label>

              <!--

          當前pattern的內容就是驗證input[name="part"]的value的,其規則如同里面的正則一樣,匹配input[name="part"]的value是否是一個數字+3個大寫字母

          -->

              <input pattern="[0-9][A-Z]{3}" name="part" />

          </label>



          當然,不同的 input[type] 也會默認帶有相應的 pattern ,例如 input[type="email"] 就是默認匹配了以下規則:



          /^[a-zA-Z0-9.!#$%&'+\/=?^_`{|}~-]+@a-zA-Z0-9?(?:.a-zA-Z0-9?)$/

          1

          第二步:重點功能

          input[type="text"]:invalid ~ input[type="submit"],

          input[type="password"]:invalid ~ input[type="submit"] {

              display: none;

          }

          input[required]:focus:invalid + span {

              display: inline;

          }

          input[required]:empty + span {

              display: none;

          }

          input[required]:invalid:not(:placeholder-shown) + span {

              display: inline;

          }



          上面便是核心交互的實現。



          首先第一個class就是保證了在兩個輸入框不通過的時候隱藏,就是當輸入框值為空或者不符合驗證規則,則隱藏提交按鈕。



          第二個,第三個class則是控制當用戶在輸入框輸入內容時,如果不符合驗證規則,則顯示錯誤信息,否則則隱藏。



          第四個class則是用過 placeholder 是否存在來控制錯誤信息的顯隱,如果 placeholder 不顯示,則證明用戶正在輸入,錯誤信息則根據用戶輸入的值來判斷是否顯隱,否則則隱藏。



          狀態切換

          上面我們有提到一個選擇器 :indeterminate ,這個是用于選擇狀態不確定的表單元素與 <progress> ,玩過掃雷的人都知道,右擊除了可以選擇紅旗,還可以選擇問號,就是選中,但不確定;又跟 promise 的 pending 狀態類型,介于 resolve 與 reject 之間。



          多了 :indeterminate 會給我們帶來很多很有趣的體驗。



          首先我們來看看它的使用案例。



          基礎使用法

          先看效果







          代碼如下:



          <style>

              body {

                  background: #333;

                  color: #fff;

                  padding: 20px;

                  text-align: center;

              }

              input {

                  margin-right: .25em;

                  width: 30px;

                  height: 30px;

              }

              label {

                  position: relative;

                  top: 1px;

                  font-size: 30px;

              }

          </style>

          <form>

              <input type="checkbox" id="checkbox">

              <label for="option">點擊左邊</label>

          </form>

          <script>

                'use strict';

                checkbox.addEventListener('click', ev => {

                  if (ev.target.readOnly) {

                    ev.target.checked = ev.target.readOnly = false;

                  } else if (!ev.target.checked) {

                    ev.target.readOnly = ev.target.indeterminate = true;

                  };

                });

          </script>



          這里面其實沒有什么復雜的實現,只是做了個中間態的判斷,就非常輕松的實現了radio的三種狀態切換。



          秀到頭皮發麻法

          先看效果







          (此天秀效果來自于 Ben Szabo 的 codepen,有興趣的可以仔細研究下,我何時才能有大佬這么優秀,嚶嚶嚶~)



          輸入框綁定的可選值

          先看效果







          其實代碼很簡單:



          <input type="text" list="names" multiple />

          <datalist id="names">

              <option value="kris">

              <option value="陳大魚頭">

              <option value="深圳金城武">

          </datalist>



          <input type="email" list="emails" multiple />

          <datalist id="emails">

              <option value="chenjinwen77@foxmail.com" label="kris">

              <option value="chenjinwen77@gmail.com" label="kris">

          </datalist>



          <input type="date" list="dates" />

          <datalist id="dates">

              <option value="2019-09-03">

          </datalist>



          這里原理就是通過 <input list="dates" /> 來綁定需要下拉顯示的數據列表 <datalist id="dates"> 。



          那么當我們要實現輸入聯想的時候,也可以通過修改 <datalist id="dates"> 的子元素來實現,而不是再寫一大堆的操作函數來實現。



          總結


          JS----預編譯及變量提升詳解

          seo達人

          JS----預編譯及變量提升詳解

          JS屬于解釋型語言,在執行過程中順序執行,但是會分塊先預編譯然后才執行。因此在JS中存在一種變量提升的現象。搞懂預編譯環節,變量提升自然而然也就懂了。本文講圍繞以下幾點進行介紹(變量提升會穿插在其中講解):



          預編譯執行步驟

          示例演示



          預編譯執行步驟

          預編譯發生在函數執行的前一刻,過程如下:



          創建AO對象,執行期上下文(后面更新關于執行期上下文詳解)。

          尋找函數的形參和變量聲明,將變量和形參名作為AO對象的屬性名,值設定為undefined.

          將形參和實參相統一,即更改形參后的undefined為具體的形參值。

          尋找函數中的函數聲明,將函數名作為AO屬性名,值為函數體。



          至此,預編譯環節結束,函數中咯變量按照最終AO對象中的值開始執行。接下來,結合示例演示就會更加清晰。



          作者:北海北方

          鏈接:https://juejin.im/post/5aa6693df265da23884cb571

          來源:掘金

          著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。



          示例演示

          我們先來看下面這段代碼:

          function fn(a){

          console.log(a);

          var a = 123;

          console.log(a);



              function a(){};

              console.log(a);

              

              var b = function(){};

              console.log(b);

              

              function d(){};

           }

           

           //調用函數

           fn(1);



          作者:北海北方

          鏈接:https://juejin.im/post/5aa6693df265da23884cb571

          來源:掘金

          著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

          接下來我們來按照前面的步驟詳細分析它的預編譯執行過程:



          創建AO對象



          AO{

              //空對象    

          }

          復制代碼

          找形參和變量聲明



          AO{

              a : undefined,

              b : undefined

          }

          復制代碼

          形參和實參相統一



          AO{

              a : 1,

              b : undefined

          }

          復制代碼

          找函數聲明



          AO{

              a : function a(){},

              b : undefined,

              d : function d(){}

          }

          復制代碼預編譯環節就此結束,此時的AO對象已經更新為:

          AO{

              a : function a(){},

              b : undefined,

              d : function d(){}

          }

          復制代碼函數開始逐行順序執行:

           function fn(a){

              console.log(a);// 輸出functiona(){}

              var a = 123;//執行到這里重新對a賦,AO對象再一次更新

              console.log(a);// 輸出123

              

              function a(){};//預編譯環節已經進行了變量提升,故執行時不在看這行代碼

              console.log(a);// 輸出123

              

              var b = function(){};//這個是函數表達式不是函數聲明,故不能提升,會對AO中的b重新賦值

              console.log(b);//輸出function(){}

              

              function d(){};

           }

          復制代碼至此,函數執行完畢,銷毀AO對象。

          我們再來看幾個例子,熟悉函數的預編譯過程。

          示例一:

          function test (a,b){

              console.log(a);

              c = 0;

              var c;

              a = 3;

              b = 2;

              console.log(b);

              function b(){};

              function d(){};

              console.log(b);



          //調用函數

          test(1);

          復制代碼它的AO創建過程如下(此處省略創建空AO對象的部分,下文同):

          AO1{

              a : undefined,

              b : undefined,

              c : undefined

          }



          AO2{

              a : 1,

              b : undefined,

              c : undefined

          }



          AO3{

              a : 1,

              b : function b(){},

              c : undefined,

              d : function d(){}

          }

          復制代碼至此預編譯環節完成,開始執行:

          function test (a,b){

              console.log(a); //輸出1

              c = 0; //給AO對象中的c重新賦值0

              var c;//預編譯環節變量提升,不再讀此行代碼

              a = 3;//給AO對象中的a重新賦值3

              b = 2;//給AO對象中的b重新賦值2

              console.log(b);//輸出2

              function b(){};//預編譯環節變量提升,執行時不再讀這行代碼

              function d(){};//預編譯環節變量提升,執行時不再讀這行代碼

              console.log(b);//輸出2



          //調用函數

          test(1);



          復制代碼示例二:

          這個例子中我們引入全局對象GO。GO與AO的過程類似

          function test(){

          var a = b = 123;

          }

          test();

          復制代碼此函數的執行過程:先把123賦給b,再聲明a,再把b賦給a。此時變量b未經聲明就賦值,為全局變量。預編譯環節如下:

          GO1{

          b : undefined

          }

          AO1{

          a : undefined

          }



          GO2{

              b : 123;

          }

          AO2{

              a : 123;

          }

          復制代碼示例三 :

          console.log(test);

          function test(test){

             console.log(test);

             var test = 234;

             console.log(test);

             function test(){};

          }

          test(1);

          var test = 123;

          復制代碼我們來看它的預編譯過程:

          //執行前(頁面加載完成時)生成GO對象

          GO1{

              test : undefined

          }

          GO2{

              test : function(){}

          }



          //輸出 function test(){...}



          //執行test()前生成它的AO對象

          AO1{

              test : undefined

          }

          AO2{

              test : 1

          }

          AO3{

              test : function test(){}

          }



          //預編譯結束開始執行test(1);

          AO4{

              test : 234

          }

          //輸出234

          復制代碼示例四:

          function demo(){

              console.log(b);

              if(a){

                  var b = 100;

              }

              console.log(b);

              c = 234;

              console.log(c);

          }

          var a;

          demo();

          a = 10;

          console.log(c);

          復制代碼我們來看它的預編譯過程:

          //首先是全局對象GO 

          GO1{

              a : undefined

          }

          G02{

              a : undefined,

              demo : function demo(){}

          }

          //執行demo()前預編譯,由于demo中的c未聲明就使用故為全局對象



          //輸出undefined

          GO3{

              a : undefined,

              demo : function demo(){}

              c : undefined

          }

          //此時a還是undefined,故不執行if()代碼塊

          //輸出還是undefined

          GO4{

              a : undefined,

              demo : function demo(){}

              c : 234;

          }

          //輸出234

          GO5{

              a : 10,

              demo : function demo(){}

              c : 234;

          }

          //輸出234


          解決nodejs koa express以及vue,nuxt項目中使用別名映射vscode不提示的問題,兼容webpack的@和best-require 的:xxx 別名映射

          seo達人

          nodejs中使用別名映射,兼容webpack的@和best-require 的:xxx 別名映射

          項目地址: https://github.com/langyuxiansheng/biu-server-admin



          寫在前面

          研究了很久,找了很多資料發現都沒有,只好自己去想辦法,查資料.才弄好的,凌晨發布的,轉載請注明出處.

          在做nodejs項目開發的時候,你是不是也在為

          require('./posts');

          require('./controllers/posts');

          require('../controllers/posts');

          require('../../controllers/posts');

          require('../../../apis/controllers/posts');



          或者



          require(ROOT_PATH + '/application/apis/controllers/posts');

          // other require()...

          require(ROOT_PATH + '/application/apis/controllers/users');

          require(ROOT_PATH + '/application/apis/controllers/products');

          require(ROOT_PATH + '/application/apis/services/rest');

          require(ROOT_PATH + '/application/apis/config');



          這樣的寫法而困擾;



          那看完這篇文章,從此之后就可以告別這個煩惱了;



          感謝一下 best-require 這個模塊包的作者,不然還需要自己去寫這個

          npmjs 鏈接 https://www.npmjs.com/package/best-require

          github 鏈接 https://github.com/yuezhihan/best-require



          不廢話了,進入正題 往下看:

          1. 安裝庫 best-require 進行別名映射





            npm i best-require --save


          2. 映射別名. 實例在本項目中 server/index.js 中





            const path = require('path');

            const ROOT_PATH = process.cwd();

            const SRC_PATH = path.join(ROOT_PATH, /server/src);

            console.log(ROOT_PATH, SRC_PATH);

            //映射目錄別名

            require('best-require')(ROOT_PATH, {

                root: ROOT_PATH,

                src: SRC_PATH,

                controllers: path.join(SRC_PATH, '/controllers'),

                models: path.join(SRC_PATH, '/models'),

                routes: path.join(SRC_PATH, '/routes'),

                crawlers: path.join(SRC_PATH, '/crawlers'),

                services: path.join(SRC_PATH, '/services'),

                middleware: path.join(SRC_PATH, '/middleware'),

                lib: path.join(SRC_PATH, '/lib'),

                config: path.join(SRC_PATH, '/config'),

                logs: path.join(SRC_PATH, '/logs')

            });



            //運行服務

            require('./src/bin/Server').run();


          3. 設置 jsconfig.json





            {

                "compilerOptions": {

                    "allowSyntheticDefaultImports": true,

                    "baseUrl": "./",

                    "paths": {

                        "@/": ["client/"],

                        ":root/": [""],

                        ":config/": ["server/src/config/"],

                        ":lib/": ["server/src/lib/"],

                        ":services/": ["server/src/services/"],

                        ":controllers/":["server/src/controllers/"],

                        ":models/": ["server/src/models/"],

                        ":routes/": ["server/src/routes/"],

                        ":crawlers/": ["server/src/crawlers/"],

                        ":middleware/": ["server/src/middleware/"],

                        ":logs/": ["server/src/logs/"]

                    }

                },

                "include": ["server/*/","client/*/"],

                "exclude": [

                    "node_modules",

                    "nuxt-dist",

                    "server-dist"

                ]

            }


          4. vscode要安裝 path-intellisense 插件 并在設置中配置setting.json



            vscode 中的設置,setting.json



            workspaceRoot 是當前的工作空間,就是當前編輯器打開的目錄.



            配置如下





            {

                "path-intellisense.mappings": {

                    "@": "${workspaceRoot}/client",

                    ":root": "${workspaceRoot}",

                    ":lib": "${workspaceRoot}/server/src/lib",

                    ":controllers": "${workspaceRoot}/server/src/controllers",

                    ":models": "${workspaceRoot}/server/src/models",

                    ":routes": "${workspaceRoot}/server/src/routes",

                    ":crawlers": "${workspaceRoot}/server/src/crawlers",

                    ":services": "${workspaceRoot}/server/src/services",

                    ":middleware": "${workspaceRoot}/server/src/middleware",

                    ":config": "${workspaceRoot}/server/src/config",

                    ":logs": "${workspaceRoot}/server/src/logs",

                }

            }


          5. 重啟vscode,試試看吧!

            作者的目錄結構









            vue中使用







            后續更新

            nodejs中使用sequelize的model映射,這樣就解決了沒得提示的煩惱了,讓你的效率提升2個檔次

            寫在后面

            如果你遇到難題或者有疑問,有好的建議請留言反饋.

            這種提示以及Ctrl + 鼠標左鍵的跳轉,只針對 .js 的文件, .vue的沒試過.這個也只是為了解決 js方法映射后沒提示的問題.


          vue生命周期過程簡單敘述

          seo達人

          vue 生命周期

          每個 Vue 實例在被創建時都要經過一系列的初始化過程。設置數據監聽、編譯模板、掛載等等。vue生命周期還是不太容易理解,這里就簡單地說一下它的整個過程。

          1創建一個vue實例



          new vue({

          data () {

          return {

          }

              }

          })



          2 初始化事件和生命周期 beforeCreate 創建實例之前執行的鉤子函數

          3 初始化·注入和校驗 created 實例創建完成后執行的鉤子



          new vue ({

          data () {

          return {

          a: 1

          }

          },

          created: function () {

          console.log('created')

          }

          })



          4 渲染頁面 編譯 beforeMount 將編譯完成的html掛載在虛擬dom時執行的鉤子

          5 mouted鉤子 掛載完畢對數據進行渲染 會做一些ajax情求初始化數據 mounted整個實例過程中只執行一次



          new vue ({

          data () {

          return {

          a: 1

          }

          },

          created: function () {

          console.log('created')

          },

          // 一些鉤子函數

          mouted: function () {

          console.log('mounted')

          }

          })



          6 修改數據 beforeUpdate 更新之前的鉤子

          7 updated 修改完成重新渲染

          8 準備解除綁定子組件以及事件監聽器 beforeDestroy

          9 銷毀完成 destroyed


          圖片切換簡易版

          seo達人

          css:

          *{margin:0;padding:0;}

          tu{margin: 50px auto;padding: 10px;width: 500px;

          background: rgb(201, 230, 128);text-align: center;}



          html:



          <body>

              <div id="tu">

                  <P id="info"></P>

                  <img src="jiao.jpg" alt="冰棒">

                  <input type="button" id="yi" value="第一張">

                  <input type="button" id="er" value="第二張">

              </div>

          </body>



          javascript:

          window.onload = function(){

          var yi = document.getElementById(“yi”);

          var er = document.getElementById(“er”);

          var img = document.getElementsByTagName(“img”)[0];

          var imgArr = [ “jiao.jpg”,“san.jpg”,“bao.jpg”,“hua.jpg”,“pei.jpg”,“tu.jpg”,“xin.jpg”,“niu.jpg”]

          var index = 0 ;

          var info = document.getElementById(“info”);



              info.innerHTML = "一共" + imgArr.length + "張圖片,當前第"+(index+1)+"張";

              yi.onclick = function(){

                  index--;

                  if(index < 0){

                      index = imgArr.length - 1; 

                  }

                  img.src = imgArr[index];

                  info.innerHTML = "一共" + imgArr.length + "張圖片,當前第"+(index+1)+"張";

              }



              er.onclick = function(){

                  index++;

                   if(index > imgArr.length - 1){               

                      index = 0; 

                  }

                  img.src = imgArr[index];

                  info.innerHTML = "一共" + imgArr.length + "張圖片,當前第"+(index+1)+"張";

              }

          }


          遞推和遞歸的區別

          seo達人

          1,從程序上看,遞歸表現為自己調用自己,遞推則沒有這樣的形式。



          2,遞歸是從問題的最終目標出發,逐漸將復雜問題化為簡單問題,最終求得問題



          是逆向的。遞推是從簡單問題出發,一步步的向前發展,最終求得問題。是正向的。



          3,遞歸中,問題的n要求是計算之前就知道的,而遞推可以在計算中確定,不要求計算前就知道n。



          4,一般來說,遞推的效率高于遞歸(當然是遞推可以計算的情況下)



          最容易理解就是結合一個經典的例子:斐波那契數列



          遞歸求解





          int fib(n){

              return n < 2 ? 1 : fib(n-1)+f(n-2);

          }



          遞推求解



          int fib(int n){

              int fn   = 1;

              int fn_1 = 0;

              for(int i=0; i<n; i++) {

                 int t = fn

                 fn    = fn + fn_1;

                 fn_1  = t;

              }

              return fn;

          }



          遞推 Inductive 是從1 往 n推(未知)



          遞歸Recursive是從n(未知)往1推, 再層層返回


          日歷

          鏈接

          個人資料

          藍藍設計的小編 http://www.syprn.cn

          存檔

          亚洲va欧美va天堂v国产综合