92国产精品视频_亚洲a级在线观看_国产精品电影观看_国产精品免费观看在线_精品伊人久久97_亚洲人成在线观_尤物九九久久国产精品的特点_成人激情在线播放_成人黄色大片在线免费观看_亚洲成人精品久久久_久久免费视频在线观看_久久精品国产一区_国产一区二区三区18_亚洲欧美中文字幕在线一区_日韩美女中文字幕_日韩视频免费在线

首頁

一個 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://m.skdbbs.com

存檔

92国产精品视频_亚洲a级在线观看_国产精品电影观看_国产精品免费观看在线_精品伊人久久97_亚洲人成在线观_尤物九九久久国产精品的特点_成人激情在线播放_成人黄色大片在线免费观看_亚洲成人精品久久久_久久免费视频在线观看_久久精品国产一区_国产一区二区三区18_亚洲欧美中文字幕在线一区_日韩美女中文字幕_日韩视频免费在线
欧美日本精品一区二区三区| a美女胸又www黄视频久久| 国产亚洲欧洲高清| 蜜乳av另类精品一区二区| 国产美女在线精品免费观看| 日韩欧美综合在线| 九色精品免费永久在线| 国内在线观看一区二区三区| 成人精品久久| 国产精品久久久久久久天堂| 亚洲视频小说图片| 5566中文字幕一区二区| 亚洲精品久久久| 亚洲美女激情视频| 欧美日韩成人在线| 国产精品视频精品| 亚洲6080在线| 亚洲欧洲成视频免费观看| 欧美日韩午夜在线| 午夜日韩福利| 在线电影欧美日韩一区二区私密| 欧美性色aⅴ视频一区日韩精品| 激情久久久久| 成人免费va视频| 91国语精品自产拍在线观看性色| 日日骚一区二区网站| 日本 国产 欧美色综合| 欧美激情乱人伦一区| 久久久久久成人| 91免费精品国自产拍在线不卡| 久久久久北条麻妃免费看| 久久99国产综合精品女同| 欧美日韩在线观看一区二区三区| jizz日韩| 亚洲国产精品人人爽夜夜爽| 亚洲片国产一区一级在线观看| 欧美一级黄色片| 国产免费一区二区三区在线能观看| 中文字幕av亚洲精品一部二部| 国产亚洲视频在线| 久久久久久电影| 精品视频在线观看免费观看| 国产精品免费视频xxxx| 天堂在线亚洲视频| 欧美午夜精品理论片a级按摩| 五月天国产在线| 欧洲永久精品大片ww免费漫画| 欧美成人全部免费| 午夜视频一区二区三区| 亚洲国产一区二区三区高清| 97天天综合网| 欧美有码在线观看视频| 精品久久久91| 欧美日韩亚洲一区二区三区在线观看| 日本a级在线| 日韩一区在线视频| 亚洲国产精品成人综合色在线婷婷| 国产一区二区三区在线观看视频| 久久这里都是精品| 日韩中文字幕网站| yw视频在线观看| 一区二区三区四区视频| 国产精品久久久久久久小唯西川| 成人午夜激情片| 亚洲+小说+欧美+激情+另类| 欧美日韩一级视频| 欧美日韩一区二区在线观看视频| 精品国产一区二区三区麻豆免费观看完整版| 欧美精品一区二区三区久久| 全球中文成人在线| 中文字幕亚洲天堂| 五月天综合网| 69精品小视频| 免费成人av在线| 亚洲成人激情社区| 欧美性猛交xxxx免费看| 国产美女精品视频免费观看| 国产精品成人国产乱一区| 久久精品123| 国产成人在线免费| 欧美xxxxhdvideosex| 97视频在线观看亚洲| 国内精品久久久久影院一蜜桃| 亚洲情综合五月天| 国产欧美久久一区二区三区| 亚洲第一成年网| 国产一区私人高清影院| 日韩午夜在线影院| av在线精品| 久久尤物电影视频在线观看| 中文字幕欧美视频在线| 国产精品乱码一区二区三区软件| 亚洲欧美制服中文字幕| 一区二区三区蜜桃| 国产精品欧美在线| 亚洲国产成人精品女人久久久| 国产69精品久久99不卡| 懂色中文一区二区在线播放| 亚洲国产高清在线观看| 成人午夜伦理影院| 欧美/亚洲一区| 久久久久久久高潮| 国产精品二区三区四区| 国产精品视频一二三区| 欧美午夜女人视频在线| 日本女人一区二区三区| 91精品综合久久久久久| 国产视频一区不卡| 美女av在线播放| 国产精品都在这里| 国产丝袜一区二区| 91精品91久久久中77777| 国产福利精品导航| 日韩一区二区三区国产| 成人精品国产| 99久久精品一区二区| 欧美freesex交免费视频| 色综合久久88色综合天天免费| 国产一区二区免费看| 成人在线观看黄色| 亚洲国产精品小视频| 91亚洲精品久久久久久久久久久久| 欧美三级网页| 日韩欧美国产成人一区二区| 亚洲一区二区三区视频在线播放| 国产农村妇女精品| 亚洲午夜极品| 日韩精品一区二区三区| 欧亚精品中文字幕| 神马影院我不卡午夜| 69影院欧美专区视频| 亚洲精品中文字幕乱码三区不卡| 久久一区91| 亚洲另类视频| 久久久神马电影| 亚洲狠狠爱一区二区三区| 久久精品亚洲乱码伦伦中文| 亚洲男人影院| 99热99热| 欧美肉体xxxx裸体137大胆| 日本在线观看不卡视频| 成人a在线视频免费观看| 96精品久久久久中文字幕| 国产不卡在线观看| 国产亚洲精品美女久久久久久久久久| av软件在线观看| 自拍偷拍亚洲图片| 欧美黑人疯狂性受xxxxx野外| 国产精品久久久久一区二区三区共| 在线精品亚洲| 国产美女精品一区二区三区| 在线成人av影院| 国产精品丝袜黑色高跟| heyzo中文字幕在线| 国产一区二区三区三区在线观看| 精品久久国产字幕高潮| 国产精品另类一区| 天堂影院一区二区| 亚洲国产黄色片| 色老汉av一区二区三区| 91精品国产麻豆国产在线观看| 国产精品刘玥久久一区| 8x福利精品第一导航| 欧美亚洲综合一区|