本週咱們 55 人學了什麼

程序員這行若是想一直作下去,那麼持續學習是必不可少的。html

你們找工做一般會喜歡技術氛圍好點的團隊,由於這樣可以幫助本身更好的成長,可是並非每一個團隊都擁有這樣的氛圍。因而萌發一個念頭,想創建一個地方,讓一些人能在這塊地方記錄本身學習到的內容。這些內容一般會是一個小點,可能並不足以寫成一篇文章。可是這個知識點可能不少人也不知道,那麼經過這種記錄的方式讓別人一樣也學習到這個知識點就是一個很棒的事情了。node

若是你也想參與這個記錄的事情,歡迎貢獻你的一份力量,地址在這裏react

本週總共有 55 人貢獻了他們所學到的知識,如下是一些整合後的內容,更詳細的內容推薦前往倉庫閱讀。ios

JS

解決鍵盤彈出後擋表單的問題

window.addEventListener('resize', function () {
if (
  document.activeElement.tagName === 'INPUT' ||
  document.activeElement.tagName === 'TEXTAREA' ||
  document.activeElement.getAttribute('contenteditable') == 'true'
) {
  window.setTimeout(function () {
    if ('scrollIntoView' in document.activeElement) {
      document.activeElement.scrollIntoView();
    } else {
      // @ts-ignore
      document.activeElement.scrollIntoViewIfNeeded();
    }
  }, 0);
}
})
複製代碼

圖片加載相關

首先是實現圖片懶加載git

<ul>
	<li><img src="./img/default.png" data="./img/1.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/2.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/3.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/4.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/5.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/6.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/7.png" alt=""></li>
	<li><img src="./img/default.png" data="./img/8.png" alt=""></li>
</ul>
let imgs =  document.querySelectorAll('img')
// 窗口可視區高度
let clientHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
// img 距離窗口可視區頂部的距離 imgs[i].getBoundingClientRect().top
function lazyLoadImg () {
    for (let i = 0; i < imgs.length; i ++) { if((imgs[i].getBoundingClientRect().top + imgs[i].height)>=0&&imgs[i].getBoundingClientRect().top < clientHeight ){ imgs[i].src = imgs[i].getAttribute('data') } } } window.addEventListener('scroll', lazyLoadImg); 複製代碼

可是這種方式會引發圖片下載過程當中閃白一下,能夠經過 JS 預先加載圖片解決。程序員

同時上述的懶加載解決方案已經很老了,可使用最新的 API Intersection_Observer 來作這件事,會更簡單並且可控一些。github

無loop生成指定長度的數組

const List1 = len => ''.padEnd(len, ',').split('.')

const List2 = len => [...new Array(len).keys()]
複製代碼

異步的 Promise的 then 方法的回調是什麼時候被添加到microtasks queue中的?

今天刷博客的時候看到一個題:npm

const pro = new Promise((resolve, reject) => {
    const pro1 = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve(3);
        }, 0);
    });
    resolve(4);
    pro1.then((args) => {
        console.log(args);
    });
});
pro.then((args) => {
    console.log(args);
});
複製代碼

不少人都知道這道題的輸出結果是4,3;可是我對題主的這個問題產生了很大的疑問,由於我的並無着手實現過符合promise A/A+規劃的promise,因此每次作這種題都是憑着平時的使用經驗,實際上心裏虛得很,而後本身查閱了 spec:ECMAScript 2018 Language Specification 根據 spec,若是調用 then 時 promise 是 pending 狀態,回調會進入 promise 的 [[PromiseFulfill/RejectReactions]] 列表裏;不然會進入 PromiseJobs。windows

PromiseJob 以及 Job Queue 是 ES 中的說法,而 macroTask 和 microTask 是瀏覽器中的概念,包括 setTimeout 也是宿主環境提供的。所以輸出 4 3 是 ECMAScript 和 瀏覽器兩種規範共同約束的結果。數組

PromiseJob 對應瀏覽器中的一個 microTask。對於調用 then 時 promise 處於 pending 狀態,回調函數進入到對應的 reactions 隊列中。當該 promise 被 fulfill 或 reject 時,則 flush 對應的 reactions 隊列 ,其中的每一個 reaction 對應一個 PromiseJob 被按序 enqueue 到 Job Queue若是調用 then 時 promise 處於其餘兩個狀態,JS 引擎就直接 enqueue 一個對應的 PromiseJob 到 Job Queue示例中的代碼。

在瀏覽器中以下順序:

0. current cycle of evevt loop start
1. Install Timer,Timer get enqueued
2. Resovle pro, because there is no fulfillReaction binding to pro, do nothing
3. call then() at pro1, because pro1 is pending, add fulfillReaction to pro1
4. call then() at pro, because pro is reolved,immediately enqueue a PromiseJob
5. current macroTask is finished
6. run all PromiseJobs(microTasks) in order, 
7. console.log(4)
8. current cycle of event loop is finishedanother cycle starts
9. Timer Fires, and pro1 is resolved
10. at this time, pro1 hasfulfillReactions,enqueue every fulfillReaction as a PromiseJob in order
11. current macro Job is finished 
12. run all PromiseJobs in order
13. console.log(3)
14. current cycle of event loop is finished
複製代碼

移動端打開指定App或者下載App

navToDownApp() {
      let u = navigator.userAgent
      if (/MicroMessenger/gi.test(u)) {
        // 若是是微信客戶端打開,引導用戶在瀏覽器中打開
        alert('請在瀏覽器中打開')
      }
      if (u.indexOf('Android') > -1 || u.indexOf('Linux') > -1) {
        // Android
        if (this.openApp('en://startapp')) {
          this.openApp('en://startapp') // 經過Scheme協議打開指定APP
        } else {
          //跳轉Android下載地址
        }
      } else if (u.indexOf('iPhone') > -1) {
        if (this.openApp('ios--scheme')) {
          this.openApp('ios--scheme') // 經過Scheme協議打開指定APP
        } else {
          // 跳轉IOS下載地址
        }
      }
    },
    openApp(src) {
      // 經過iframe的方式試圖打開APP,若是能正常打開,會直接切換到APP,並自動阻止a標籤的默認行爲
      // 不然打開a標籤的href連接
      let ifr = document.createElement('iframe')
      ifr.src = src
      ifr.style.display = 'none'
      document.body.appendChild(ifr)
      window.setTimeout(function() {
        // 打開App後移出這個iframe
        document.body.removeChild(ifr)
      }, 2000)
    }
複製代碼

利用 a 標籤解析 URL

function parseURL(url) {
    var a =  document.createElement('a');
    a.href = url;
    return {
        host: a.hostname,
        port: a.port,
        query: a.search,
        params: (function(){
            var ret = {},
                seg = a.search.replace(/^\?/,'').split('&'),
                len = seg.length, i = 0, s;
            for (;i<len;i++) {
                if (!seg[i]) { continue; }
                s = seg[i].split('=');
                ret[s[0]] = s[1];
            }
            return ret;
        })(),
        hash: a.hash.replace('#','')
    };
}
複製代碼

數組去重

var array = [1, 2, 1, 1, '1'];
  function unique(array) {
    var obj = {};
    return array.filter(function(item, index, array){
      return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
    })
  }
複製代碼

利用一個空的 Object 對象,咱們把數組的值存成 Object 的 key 值,好比 Object[value1] = true,在判斷另外一個值的時候,若是 Object[value2]存在的話,就說明該值是重複的。

由於 1 和 '1' 是不一樣的,可是這種方法會判斷爲同一個值,這是由於對象的鍵值只能是字符串,因此咱們可使用 typeof item + item 拼成字符串做爲 key 值來避免這個問題

JS 函數對象參數的陷阱

上週在實現某個彈層功能的時候,用到了rc-util裏的 contains 方法函數, 結果 code-review 的時候同事對該代碼提出了疑問:

rc-util 源碼倉庫

export default function contains(root, n) {
  let node = n;
  while (node) {
    if (node === root) {
      return true;
    }
    node = node.parentNode;
  }
  return false;
}
複製代碼

上述代碼是 antd 內部抽象的一個工具方法,用來判斷某個dom是否爲另外一個dom的祖先節點。

同事疑問的是 let node = n; 這段代碼是否是多餘的?

首先一開始的理解是 函數參數 n 是一個對象,一個dom節點對象。
若是用 node 保存 n 的值,防止 node = node.parentNode 這段代碼執行的時候,會改變傳入的實參 n 對應的值。

畢竟如下的代碼咱們都很熟悉:

function contains(root, n) {
  if(n) {
    n.a = 3
  }
}

const A = {a:1};
const B = {a:2};
contains(A,B)
console.log(B)    // {a:3}
複製代碼

即當實參爲對象時,函數內部是能夠改變該對象的值從而影響函數以外的實參。

可是測試另一段代碼,發現和理解的不同:

function contains(root, n) {
  if(n) {
    n = {a:3}
  }
}

const A = {a:1};
const B = {a:2}
contains(A,B)
console.log(B) // {a:2}
複製代碼

n.a = 3n = {a:3} 這兩段代碼是不同的。

網上也有相關資料,其實能夠簡單的理解爲: 當函數一開始執行時,n 是指向實參 B 的一個引用.

n.a = 3 是在引用上關聯了一個屬性,此時和 B 仍是同一個引用,所以會改變實參B的值。

n = {a:3} 則使得 n 再也不指向實參 B, 而是指向一個新對象{a:3},也就是 nB 完全斷絕了關係,所以不會改變實參 B 的值。

是否是能夠給螞蟻的團隊提個issue建議刪除該代碼,不過有這句代碼也不會有什麼bug~

相關資料:JavaScript深刻之參數按值傳遞

其餘

kill 指定端口

如下命令能夠 kill 掉 8080 端口,固然你也能夠選擇經過 npm 命令的方式指定須要 kill 的端口。

lsof -i tcp:8080 | grep LISTEN | awk '{print $2}'| awk -F"/" '{ print $1 }' | xargs kill -9
複製代碼

另外以上命令在 windows 上是不可用的。若是有多平臺的需求的話,能夠直接使用 Kill-port-process

Linux下經過命令行替換文本

# 將wxml文件的i標籤替換爲text
grep '<i ' -rl . --include='*.wxml' --exclude-dir=node_module --exclude-dir=dist | xargs sed -i -e 's/<i /<text /g'
grep '</i>' -rl . --include='*.wxml' --exclude-dir=node_module --exclude-dir=dist | xargs sed -i -e 's/<\/i>/<\/text>/g'
複製代碼

如何判斷文件中的換行符是 LF(\n) 仍是 CRLF(\r\n)

文章連接,經過這篇文章能夠了解到換行符究竟是什麼。

另外這位大佬天天都將學習到的知識記錄了下來,感興趣的能夠 閱讀一下

畢業半年感悟

  • 自身的實力最重要,要有同樣核心技能,其餘方面也要有所涉獵。
  • 公司帶給我的的影響是很大的,若是一個公司不肯意培養你,真的不值得去付出。
  • 溝通確實很重要,溝通不明確會致使接下來一系列的問題。
  • 說話是後天鍛煉出來的,多和人交流,話到嘴邊留三分。
  • 不用討厭加班,人與人拉開差距就在下班後的幾個小時,加班能夠學習啊。雷軍還說過你拿3000塊錢換我一個月的青春,多不划算。

最後

這周的分享內容質量很高,我也從中汲取到了一些知識。

這是一個須要你們一塊兒分享才能持續下去的事情,光靠我一人分享是作不下去的。歡迎你們參與到這件事情中來,地址在這裏

相關文章
相關標籤/搜索