你盼世界,我盼望你無bug
。Hello 你們好!我是霖呆呆!css
呆呆每週都會分享七道前端題給你們,系列名稱就是「DD每週七題」。html
系列的形式主要是:3道JavaScript
+ 2道HTML
+ 2道CSS
,幫助咱們你們一塊兒鞏固前端基礎。前端
全部題目也都會整合至 LinDaiDai/niubility-coding-js 的issues
中,歡迎你們提供更好的解題思路,謝謝你們😁。webpack
一塊兒來看看本週的七道題吧。git
如下代碼輸出什麼?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
。瀏覽器
(題目來源: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))) 複製代碼
(參考來源:相學長-你的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
當即執行函數
name
和
getSex()
)
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
來定義原型方法。
可是能夠經過設置babel
的loose
模式(寬鬆模式)爲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
編譯時默認的loose
爲false
,即非寬鬆模式
不管哪一種模式,轉換後的定義在類內部的屬性方法是被定義在構造函數的原型對象上的;靜態屬性被定義到構造函數上
只不過非寬鬆模式時,這些屬性方法會被_createClass
函數處理,函數內經過Object.defineProperty()
設置屬性的可枚舉值enumerable
爲false
因爲在_createClass
函數內使用了Object
,因此非寬鬆模式下是會產生反作用的,而寬鬆模式下不會。
webpack
中的UglifyJS
依舊仍是會將寬鬆模式認爲是有反作用的,而rollup
有「程序流程分析」的功能,能夠更好的判斷代碼是否真正產生反作用,因此它會認爲寬鬆模式沒有反作用。
(反作用大體理解爲:一個函數會、或者可能會對函數外部變量產生影響的行爲。)
(答案參考來源:前端性能優化-頁面加載渲染優化)
「正常模式」
這種狀況下 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。
<p>測試 空格</p>
這兩個詞之間的空格變大?(題目來源:https://github.com/haizlin/fe-interview/issues/2440)
這道題的意思是說,本來有一段HTML
代碼以下:
<p>測試 空格</p>
複製代碼
在"測試"
和"空格"
兩個詞之間有一個空格,而後如何將這個空格變大。
這邊有這麼兩種方法:
p
標籤設置
word-spacing
,將這個屬性設置成本身想要的值。
span
標籤包裹起來,而後設置
span
標籤的
letter-spacing
或者
word-spacing
。
我分別用letter-spacing
和word-spacing
來處理了p
和span
標籤:
<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-spacing
和word-spacing
處理p
標籤,是會呈現不一樣的效果的,letter-spacing
把中文之間的間隙也放大了,而word-spacing
則不放大中文之間的間隙。
而span
標籤中只有一個空格,因此letter-spacing
和word-spacing
效果同樣。
所以咱們能夠得出letter-spacing
和word-spacing
的結論:
letter-spacing
和
word-spacing
這兩個屬性都用來添加他們對應的元素中的空白。
letter-spacing
添加字母之間的空白,而
word-spacing
添加每一個單詞之間的空白。
word-spacing
對中文無效。
本來的代碼爲:
<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> 複製代碼
並不會,DOM樹是HTML頁面的層級結構,指的是元素與元素之間的關係,例如包裹個人是個人父級,與我並列的是個人兄弟級,相似這樣的關係稱之爲層級結構。
而文檔流則相似於排隊,我本應該在隊伍中的,然而我脫離了隊伍,可是我與個人父親,兄弟,兒子的關係還在。
知識無價,支持原創。
參考文章:
你盼世界,我盼望你無bug
。這篇文章就介紹到這裏。
您每週也許會花48
小時的時間在工做💻上,會花49
小時的時間在睡覺😴上,也許還能夠再花20
分鐘的時間在呆呆的7道題上,日積月累,我相信咱們都能見證彼此的成長😊。
什麼?你問我爲何系列的名字叫DD
?由於呆呆
呀,哈哈😄。
喜歡「霖呆呆」的小夥還但願能夠關注霖呆呆的公衆號 LinDaiDai
或者掃一掃下面的二維碼👇👇👇。
我會不定時的更新一些前端方面的知識內容以及本身的原創文章🎉
你的鼓勵就是我持續創做的主要動力 😊。
本文使用 mdnice 排版