DD每週前端七題詳解-第四期

DD每週前端七題詳解-第四期

系列介紹

你盼世界,我盼望你無bug。Hello 你們好!我是霖呆呆!css

呆呆每週都會分享七道前端題給你們,系列名稱就是「DD每週七題」。html

系列的形式主要是:3道JavaScript + 2道HTML + 2道CSS,幫助咱們你們一塊兒鞏固前端基礎。前端

全部題目也都會整合至 LinDaiDai/niubility-coding-jsissues中,歡迎你們提供更好的解題思路,謝謝你們😁。webpack

一塊兒來看看本週的七道題吧。git

正題

1、following function return?

如下代碼輸出什麼?github

function getName () {
 return  {  name: 'LinDaiDai'  } } console.log(getName()) 複製代碼

這道題其實涉及到了JavaScript中的一個名爲ASI的機制,全名Automatic Semicolon Insertion,好吧,不要整的那麼高大上了,其實就是自動插入分號的機制。web

按照ECMAScript標準,一些 特定語句(statement) 必須以分號結尾。分號表明這段語句的終止。可是有時候爲了方便,這些分號是有能夠省略的。這種狀況下解釋器會本身判斷語句該在哪裏終止。這種行爲被叫作「自動插入分號」,簡稱ASI (Automatic Semicolon Insertion) 。實際上分號並無真的被插入,這只是個便於解釋的形象說法。segmentfault

也就是說這道題在執行的時候,會在return關鍵字後面自動插入一個分號,因此這道題就至關因而這樣:數組

function getName () {
 return;  {  name: 'LinDaiDai'  } } console.log(getName()) 複製代碼

所以最終的結果也就是undefined瀏覽器

github.com/LinDaiDai/n…

2、實現一個pipe函數

(題目來源:30-seconds-of-interviews)

以下所示,實現一個pipe函數:

const square = v => v * v
const double = v => v * 2 const addOne = v => v + 1 const res = pipe(square, double, addOne) console.log(res(3)) // 19; addOne(double(square(3))) 複製代碼

首先看到這道題,pipe是能夠接收任意個數的函數,而且返回的是一個新的函數res

(1) pipe基本結構

那麼咱們能夠得出pipe的基本結構是這樣的:

const pipe = function (...fns) {
 return function (param) {} } 複製代碼

它自己是一個函數,而後咱們能夠利用...fns獲取到全部傳入的函數參數square、double這些。

以後它會返回一個函數,且這個函數中是能夠接收參數param的。

(2) 返回的函數

接下來的邏輯主要就是在於返回的函數上了,在這個返回的函數中,咱們須要對param進行層層處理。

OK👌,這很容易就讓人想到了...reduce...

咱們能夠對fns函數數組使用reduce,以後reduce的初始值爲傳入的參數param

讓咱們一塊兒來看看最終的代碼:

const pipe = function (...fns) {
 return function (param) {  return fns.reduce((pre, fn) => {  return fn(pre)  }, param)  } } 複製代碼

最終返回的是通過fns數組中全部函數處理過的值。

固然,咱們也能夠用簡潔點的寫法:

const pipe = (...fns) => param => fns.reduce((pre, fn) => fn(pre), param)
複製代碼

這樣就獲得了咱們想要的pipe函數了:

const square = v => v * v
const double = v => v * 2 const addOne = v => v + 1 const pipe = (...fns) => param => fns.reduce((pre, fn) => fn(pre), param) const res = pipe(square, double, addOne) console.log(res(3)) // 19; addOne(double(square(3))) 複製代碼

github.com/LinDaiDai/n…

3、Babel是如何編譯Class的?

(參考來源:相學長-你的Tree-Shaking並沒什麼卵用)

就拿下面的類來講:

class Person {
 constructor ({ name }) {  this.name = name  this.getSex = function () {  return 'boy'  }  }  getName () {  return this.name  }  static getLook () {  return 'sunshine'  } } 複製代碼

若是你對Class或者裏面的static還不熟悉的話可得先看看呆呆的這篇文章了:《【何不三連】比繼承家業還要簡單的JS繼承題-封裝篇(牛刀小試)》

當咱們在使用babel的這些plugin或者使用preset的時候,有一個配置屬性loose它默認是爲false,在這樣的條件下:

Class編譯後:

  • 整體來講 Class會被封裝成一個 IIFE當即執行函數
  • 當即執行函數返回的是一個與類同名的構造函數
  • 實例屬性和方法定義在構造函數內(如 namegetSex())
  • 類內部聲明的屬性方法( getName)和靜態屬性方法( getLook)是會被 Object.defineProperty所處理,將其可枚舉屬性設置爲 false

(下面的代碼看着好像很長,其實劃分一下並無什麼東西的)

編譯後的代碼:

"use strict";
 function _classCallCheck(instance, Constructor) {  if (!(instance instanceof Constructor)) {  throw new TypeError("Cannot call a class as a function");  } }  function _defineProperties(target, props) {  for (var i = 0; i < props.length; i++) {  var descriptor = props[i];  descriptor.enumerable = descriptor.enumerable || false;  descriptor.configurable = true;  if ("value" in descriptor) descriptor.writable = true;  Object.defineProperty(target, descriptor.key, descriptor);  } }  function _createClass(Constructor, protoProps, staticProps) {  if (protoProps) _defineProperties(Constructor.prototype, protoProps);  if (staticProps) _defineProperties(Constructor, staticProps);  return Constructor; }  var Person = /*#__PURE__*/ (function () {  function Person(_ref) {  var name = _ref.name;   _classCallCheck(this, Person);   this.name = name;   this.getSex = function () {  return "boy";  };  }   _createClass(  Person,  [  {  key: "getName",  value: function getName() {  return this.name;  },  },  ],  [  {  key: "getLook",  value: function getLook() {  return "sunshine";  },  },  ]  );   return Person; })(); 複製代碼

爲何Babel對於類的處理會使用Object.defineProperty這種形式呢?它和直接使用原型鏈有什麼不一樣嗎?

  • 經過原型鏈聲明的屬性和方法是可枚舉的,也就是能夠被 for...of...搜尋到
  • 而類內部聲明的方法是不可枚舉的

因此,babel爲了符合ES6真正的語義,編譯類時採起了Object.defineProperty來定義原型方法。

可是能夠經過設置babelloose模式(寬鬆模式)爲true,它會不嚴格遵循ES6的語義,而採起更符合咱們日常編寫代碼時的習慣去編譯代碼,在.babelrc中能夠以下設置:

{
 "presets": [["env", { "loose": true }]] } 複製代碼

好比上述的Person類的屬性方法將會編譯成直接在原型鏈上聲明方法:

"use strict";
 var Person = /*#__PURE__*/function () {  function Person(_ref) {  var name = _ref.name;  this.name = name;   this.getSex = function () {  return 'boy';  };  }   var _proto = Person.prototype;   _proto.getName = function getName() {  return this.name;  };   Person.getLook = function getLook() {  return 'sunshine';  };   return Person; }(); 複製代碼

總結

  • 當使用Babel編譯時默認的loosefalse,即非寬鬆模式

  • 不管哪一種模式,轉換後的定義在類內部的屬性方法是被定義在構造函數的原型對象上的;靜態屬性被定義到構造函數上

  • 只不過非寬鬆模式時,這些屬性方法會被_createClass函數處理,函數內經過Object.defineProperty()設置屬性的可枚舉值enumerablefalse

  • 因爲在_createClass函數內使用了Object,因此非寬鬆模式下是會產生反作用的,而寬鬆模式下不會。

  • webpack中的UglifyJS依舊仍是會將寬鬆模式認爲是有反作用的,而rollup程序流程分析的功能,能夠更好的判斷代碼是否真正產生反作用,因此它會認爲寬鬆模式沒有反作用。

    (反作用大體理解爲:一個函數會、或者可能會對函數外部變量產生影響的行爲。)

github.com/LinDaiDai/n…

4、JS三種加載方式的區別

(答案參考來源:前端性能優化-頁面加載渲染優化)

正常模式

這種狀況下 JS 會阻塞瀏覽器,瀏覽器必須等待 index.js 加載和執行完畢才能去作其它事情。

<script src="index.js"></script>
複製代碼

async(異步) 模式

async 模式下,JS 不會阻塞瀏覽器作任何其它的事情。它的加載是異步的,當它加載結束,JS 腳本會當即執行。

<script async src="index.js"></script>
複製代碼

defer(延緩) 模式

defer 模式下,JS 的加載是異步的,執行是被推遲的。等整個文檔解析完成、DOMContentLoaded 事件即將被觸發時,被標記了 defer 的 JS 文件纔會開始依次執行。

<script defer src="index.js"></script>
複製代碼

從應用的角度來講,通常當咱們的腳本與 DOM 元素和其它腳本之間的依賴關係不強時,咱們會選用 async;當腳本依賴於 DOM 元素和其它腳本的執行結果時,咱們會選用 defer。

github.com/LinDaiDai/n…

5、如何讓<p>測試 空格</p>這兩個詞之間的空格變大?

(題目來源:https://github.com/haizlin/fe-interview/issues/2440)

這道題的意思是說,本來有一段HTML代碼以下:

<p>測試 空格</p>
複製代碼

"測試""空格"兩個詞之間有一個空格,而後如何將這個空格變大。

這邊有這麼兩種方法:

  • 經過給 p標籤設置 word-spacing,將這個屬性設置成本身想要的值。
  • 將這個空格用一個 span標籤包裹起來,而後設置 span標籤的 letter-spacing或者 word-spacing

我分別用letter-spacingword-spacing來處理了pspan標籤:

<style>  .p-letter-spacing {  letter-spacing: 10px;  }  .p-word-spacing {  word-spacing: 10px;  }  .span-letter-spacing {  letter-spacing: 10px;  }  .span-word-spacing {  word-spacing: 10px;  } </style> <body>  <p>測試 空格</p>  <p class="p-letter-spacing">測試 空格</p>  <p class="p-word-spacing">測試 空格</p>  <p>測試<span class="span-letter-spacing"> </span>空格</p>  <p>測試<span class="span-word-spacing"> </span>空格</p> </body> 複製代碼

讓咱們一塊兒來看看效果:

你們能夠看到效果,我用letter-spacingword-spacing處理p標籤,是會呈現不一樣的效果的,letter-spacing把中文之間的間隙也放大了,而word-spacing則不放大中文之間的間隙。

span標籤中只有一個空格,因此letter-spacingword-spacing效果同樣。

所以咱們能夠得出letter-spacingword-spacing的結論:

  • letter-spacingword-spacing這兩個屬性都用來添加他們對應的元素中的空白。
  • letter-spacing添加字母之間的空白,而 word-spacing添加每一個單詞之間的空白。
  • word-spacing對中文無效。

github.com/LinDaiDai/n…

6、如何解決inline-block空白問題?

本來的代碼爲:

<style> .sub {  background: hotpink;  display: inline-block; } </style> <body>  <div class="super">  <div class="sub">  孩子  </div>  <div class="sub">  孩子  </div>  <div class="sub">  孩子  </div>  </div> </body> 複製代碼

效果爲:

能夠看到每一個孩子之間都會有一個空白。inline-block元素間有空格或是換行,所以產生了間隙。

解決辦法:

  • (1) 刪除html中的空白:不要讓元素之間換行:

    <div class="super">
     <div class="sub">  孩子  </div><div class="sub">  孩子  </div><div class="sub">  孩子  </div> </div> 複製代碼
  • (2) 設置負的邊距:你能夠用負邊距來補齊空白。但你須要調整font-size,由於空白的寬度與這個屬性有關係。例以下面這個例子:

    .sub {
     background: hotpink;  display: inline-block;  font-size:16px;  margin-left: -0.4em; } 複製代碼
  • (3) 給父級設置font-size: 0:無論空白多大,因爲空白跟font-size的關係,設置這個屬性便可把空白的寬度設置爲0。可是若是你的子級有字的話,也得單獨給子級設置字體大小。

  • (4) 註釋

    <div class="super">
     <div class="sub">  孩子  </div><!--  --><div class="sub sub2">  孩子  </div><!--  --><div class="sub">  孩子  </div> </div> 複製代碼

github.com/LinDaiDai/n…

7、脫離文檔流是否是指該元素從DOM樹中脫離?

並不會,DOM樹是HTML頁面的層級結構,指的是元素與元素之間的關係,例如包裹個人是個人父級,與我並列的是個人兄弟級,相似這樣的關係稱之爲層級結構。

而文檔流則相似於排隊,我本應該在隊伍中的,然而我脫離了隊伍,可是我與個人父親,兄弟,兒子的關係還在。

github.com/LinDaiDai/n…

參考文章

知識無價,支持原創。

參考文章:

後語

你盼世界,我盼望你無bug。這篇文章就介紹到這裏。

您每週也許會花48小時的時間在工做💻上,會花49小時的時間在睡覺😴上,也許還能夠再花20分鐘的時間在呆呆的7道題上,日積月累,我相信咱們都能見證彼此的成長😊。

什麼?你問我爲何系列的名字叫DD?由於呆呆呀,哈哈😄。

喜歡霖呆呆的小夥還但願能夠關注霖呆呆的公衆號 LinDaiDai 或者掃一掃下面的二維碼👇👇👇。

我會不定時的更新一些前端方面的知識內容以及本身的原創文章🎉

你的鼓勵就是我持續創做的主要動力 😊。

本文使用 mdnice 排版

相關文章
相關標籤/搜索