源:魚頭的Web海洋
之前刷某乎的時候,看到這么一個問題:“如何衡量一個人的 JavaScript 水平?[2]”然后自己也不要臉地回答了一下這個問題。以下是我的答案:
原文如下:
A:看一個人寫代碼是否有規范,代碼是否壯健,是否可拓展,可讀性高不高,API設計是否合理。
這些都是長年累月積累下來的且獨立于編程語言以外的。
遠比把什么手寫bind,原型鏈,閉包給背下來更有價值。
這才是證明你代碼水平的關鍵點。
Q:在面試的時候如何快速判斷出呢?
A:讓面試者設計個組件,不用寫,回答就行。從API設計,文檔編寫,項目結構,單元測試,編寫模式,性能優化等方面來回答。
有工作經驗的人,基本業務邏輯都能寫,但是寫的好不好,就是經驗跟能力以及學習力的體現 。
首先來個免責聲明,以上的回答都是個人的經驗與見解,答案肯定不唯一,甚至不一定全對,所以求輕噴。
上面問如何在面試的時候快速判斷對方是否是高級前端的時候,我為什么說是“設計組件”呢?
因為我覺得有一定實力的前端來說,“組件”這個概念是繞不過的,或者看過開源組件的源碼,或者自己寫過組件。
對于一般的業務問題,我相信作為一個從業了一定時間的開發者,無論水平如何,這都不是問題,但是如何區分這個開發者的水平,可以通過他寫的代碼來判斷,當然也不完全是,畢竟在996或者趕進度的時候,很容易就會為了完成快速出產品而寫,這種情況下代碼質量跟個人水平不一定能體現。
下面,我們以設計一個“按鈕(<Button>)組件”為例,來探索這個問題。
首先“按鈕(<Button>)”的作用這個我們是否明確?它是裝飾性的組件還是功能性的組件?
這個問題很簡單,“按鈕(<Button>)”是一個功能性的組件,是讓用戶通過點擊或觸碰來采取行動并做出選擇的一個組件。
那么“按鈕(<Button>)”通常放在什么地方?有經驗的開發可能會想到以下場景:
?對話框?模態窗口?表單?卡片?工具欄
代表狀態可能會有以下幾種:
?默認狀態?初始狀態?信息狀態?警告狀態?危險狀態
形態可能會有以下幾種:
?實心按鈕?文本按鈕?描邊按鈕?圖標按鈕?圓角按鈕?直角按鈕
尺寸可能會有以下幾種:
?small?medium?large
操作性可能會有以下幾種:
?回車鍵點擊?鼠標點擊?觸摸點擊?禁止點擊
攜帶的事件可能有以下兩種:
?click事件?回車鍵keydown事件?tap事件
以上雖然是偏樣式,但是作為一個組件開發者,這都是我們日常所需要考慮的。
在API的設計環節,我們通過上述的場景,我們可能會暴露出以下的API
?type:按鈕狀態?size:按鈕尺寸?color:按鈕顏色?text:按鈕內的文本?icon:按鈕內的圖標?htmlType:原生按鈕支持的type屬性?attrs:其他的原生屬性?variant:按鈕形態?click:鼠標點擊事件?tap:觸摸屏點擊事件?keydown:回車鍵按下事件
在我們API設計好之后,我們就可以開始開發了,這時候根據我們項目的類型,選擇的開發工具以及模式,可能會有所不同。
我們是獨立編寫還是直接在項目里面去編寫,如果是獨立編寫,選擇哪個打包工具,是gulp還是webpack還是其它,為什么這么選?
例如如果我們是用TS寫,我們可能需要編寫Button.d.ts,如果是vue的組件,我們還得考慮Vue.use注入到Vue中,也就是Button.install(vue),如果是react,我們還得考慮是否使用React.forwardRef來進行ref轉發。
然后就是我們的代碼規范,是用Function還是Class,共同的代碼塊如何抽象,如何,還有命名規范是什么,哪些屬性必選,哪些屬性可選,默認值是什么?我們是怎么考慮的?
所以最終的組件使用可能會是這種形式:
import Button from './componenet/Button'<Button htmlType="submit" aria-label="add" variant="contained" color="rgba(17, 82, 147, 1)" click="clickHandler" />添加</Button>
在我們開發的過程中,有一道麻煩但又必不可少的工序就是單元測試,這時候單元測試的庫我們是怎么選?用Jest還是Mocha?測試用例怎么寫?如何模擬點擊或者異步響應?是否需要快照(snapshots)?這也是在我們的考慮范圍內。
所以我們的測試腳本可能長這樣:
import Button from './componenet/Button'import { shallow } from 'enzyme'describe('<Button />', ()=> { it('render success', ()=> { const wrapper=shallow(( <Button htmlType="submit" aria-label="add" variant="contained" color="rgba(17, 82, 147, 1)" click="clickHandler" />添加</Button> )) expect(wrapper.text('添加')).to.equal(true) })})
其它的諸如開發文檔,使用文檔,版本迭代,項目配置,打包開發優化,以及其他自動化的功能,也是我們所需要考慮。
以上便是我們在開發一個“按鈕(<Button>)組件”時可能會考慮到的點,可能有不夠完善的地方,但是我想說的意思是,這其實可以很好的衡量一個人的JavaScript水平。比如你再會手寫原型鏈關系圖,閉包,防抖,節流等基礎概念,但是如果不在項目中運用起來,終究是紙上談兵,對技術水平沒有太多實質的幫助,當然不是說精通這些內容不好,但是比起實戰,還是差強人意。
能手寫代碼的不一定是高級,但是如果能寫好一個組件,水平再差也不會差到哪里去。
本文似乎有點文不對題了,本來談的是“如何衡量一個人的JavaScript水平”,結果卻超綱了許多。但是通過這種方式,確實能夠判斷出一個人代碼水平,當然也并不只是JS,換成安卓,IOS也同樣適用。
不知道你是通過什么方式來衡量一個的JavaScript水平的呢?歡迎留言區域回復互動。
者|顏海鏡
編輯|覃云
出處丨前端之巔
本文已獲作者授權,轉載來源:
https://segmentfault.com/a/1190000016389031
劃重點,這是一道面試必考題,很多面試官都喜歡問這個問題,我就被問過好幾次了。
要實現上圖的效果看似很簡單,實則暗藏玄機,本文總結了一下 CSS 實現水平垂直居中的方式大概有下面這些,本文將逐一介紹一下,我將本文整理成了一個 github 倉庫在:https://github.com/yanhaijing/vertical-center
歡迎大家 star。
僅居中元素定寬高適用:
居中元素不定寬高:
為了實現上面的效果先來做些準備工作,假設 HTML 代碼如下,總共兩個元素,父元素和子元素:
<div class="wp"> <div class="box size">123123</div> </div>
wp 是父元素的類名,box 是子元素的類名,因為有定寬和不定寬的區別,size 用來表示指定寬度,下面是所有效果都要用到的公共代碼,主要是設置顏色和寬高。
注意:后面不在重復這段公共代碼,只會給出相應提示。
/* 公共代碼 */ .wp { border: 1px solid red; width: 300px; height: 300px; } .box { background: green; } .box.size{ width: 100px; height: 100px; } /* 公共代碼 */
絕對定位的百分比是相對于父元素的寬高,通過這個特性可以讓子元素的居中顯示,但絕對定位是基于子元素的左上角,期望的效果是子元素的中心居中顯示。
為了修正這個問題,可以借助外邊距的負值,負的外邊距可以讓元素向相反方向定位,通過指定子元素的外邊距為子元素寬度一半的負值,就可以讓子元素居中了,css 代碼如下。
/* 此處引用上面的公共代碼 */ /* 此處引用上面的公共代碼 */ /* 定位代碼 */ .wp { position: relative; } .box { position: absolute;; top: 50%; left: 50%; margin-left: -50px; margin-top: -50px; }
這是我比較常用的方式,這種方式比較好理解,兼容性也很好,缺點是需要知道子元素的寬高。
點擊查看完整 DEMO:
http://yanhaijing.com/vertical-center/absolute1.html
這種方式也要求居中元素的寬高必須固定,HTML 代碼如下:
<div class="wp"> <div class="box size">123123</div> </div>
這種方式通過設置各個方向的距離都是 0,此時再講 margin 設為 auto,就可以在各個方向上居中了。
/* 此處引用上面的公共代碼 */ /* 此處引用上面的公共代碼 */ /* 定位代碼 */ .wp { position: relative; } .box { position: absolute;; top: 0; left: 0; right: 0; bottom: 0; margin: auto; }
這種方法兼容性也很好,缺點是需要知道子元素的寬高。
點擊查看完整 DEMO:
http://yanhaijing.com/vertical-center/absolute2.html
這種方式也要求居中元素的寬高必須固定,所以我們為 box 增加 size 類,HTML 代碼如下:
<div class="wp"> <div class="box size">123123</div> </div>
感謝 css3 帶來了計算屬性,既然 top 的百分比是基于元素的左上角,那么在減去寬度的一半就好了,代碼如下
/* 此處引用上面的公共代碼 */ /* 此處引用上面的公共代碼 */ /* 定位代碼 */ .wp { position: relative; } .box { position: absolute;; top: calc(50% - 50px); left: calc(50% - 50px); }
這種方法兼容性依賴 calc 的兼容性,缺點是需要知道子元素的寬高。
點擊查看完整 DEMO:
http://yanhaijing.com/vertical-center/absolute3.html
還是絕對定位,但這個方法不需要子元素固定寬高,所以不再需要 size 類了,HTML 代碼如下:
<div class="wp"> <div class="box">123123</div> </div>
修復絕對定位的問題,還可以使用 css3 新增的 transform,transform 的 translate 屬性也可以設置百分比,其是相對于自身的寬和高,所以可以講 translate 設置為 -50%,就可以做到居中了,代碼如下:
/* 此處引用上面的公共代碼 */ /* 此處引用上面的公共代碼 */ /* 定位代碼 */ .wp { position: relative; } .box { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }
這種方法兼容性依賴 translate2d 的兼容性。
點擊查看完整 DEMO:
http://yanhaijing.com/vertical-center/absolute4.html
利用行內元素居中屬性也可以做到水平垂直居中,HTML 代碼如下:
<div class="wp"> <div class="box">123123</div> </div>
把 box 設置為行內元素,通過 text-align 就可以做到水平居中,但很多同學可能不知道通過通過 vertical-align 也可以在垂直方向做到居中,代碼如下:
/* 此處引用上面的公共代碼 */ /* 此處引用上面的公共代碼 */ /* 定位代碼 */ .wp { line-height: 300px; text-align: center; font-size: 0px; } .box { font-size: 16px; display: inline-block; vertical-align: middle; line-height: initial; text-align: left; /* 修正文字 */ }
這種方法需要在子元素中將文字顯示重置為想要的效果。
點擊查看完整 DEMO:
http://yanhaijing.com/vertical-center/lineheight.html
很多同學一定和我一樣不知道 writing-mode 屬性,感謝 @張鑫旭老師的反饋,簡單來說 writing-mode 可以改變文字的顯示方向,比如可以通過 writing-mode 讓文字的顯示變為垂直方向。
<div class="div1">水平方向</div> <div class="div2">垂直方向</div> .div2 { writing-mode: vertical-lr; }
顯示效果如下:
水平方向 垂 直 方 向
更神奇的是所有水平方向上的 css 屬性,都會變為垂直方向上的屬性,比如 text-align,通過 writing-mode 和 text-align 就可以做到水平和垂直方向的居中了,只不過要稍微麻煩一點:
<div class="wp"> <div class="wp-inner"> <div class="box">123123</div> </div> </div> /* 此處引用上面的公共代碼 */ /* 此處引用上面的公共代碼 */ /* 定位代碼 */ .wp { writing-mode: vertical-lr; text-align: center; } .wp-inner { writing-mode: horizontal-tb; display: inline-block; text-align: center; width: 100%; } .box { display: inline-block; margin: auto; text-align: left; }
這種方法實現起來和理解起來都稍微有些復雜。
點擊查看完整 DEMO:
http://yanhaijing.com/vertical-center/writing-mode.html
曾經 table 被用來做頁面布局,現在沒人這么做了,但 table 也能夠實現水平垂直居中,但是會增加很多冗余代碼:
<table> <tbody> <tr> <td class="wp"> <div class="box">123123</div> </td> </tr> </tbody> </table>
tabel 單元格中的內容天然就是垂直居中的,只要添加一個水平居中屬性就好了。
.wp { text-align: center; } .box { display: inline-block; }
這種方法就是代碼太冗余,而且也不是 table 的正確用法。
點擊查看完整 DEMO:
http://yanhaijing.com/vertical-center/table.html
css 新增的 table 屬性,可以讓我們把普通元素,變為 table 元素的現實效果,通過這個特性也可以實現水平垂直居中。
<div class="wp"> <div class="box">123123</div> </div>
下面通過 css 屬性,可以讓 div 顯示的和 table 一樣:
.wp { display: table-cell; text-align: center; vertical-align: middle; } .box { display: inline-block; }
這種方法和 table 一樣的原理,但卻沒有那么多冗余代碼,兼容性也還不錯。
點擊查看完整 DEMO:
http://yanhaijing.com/vertical-center/css-table.html
flex 作為現代的布局方案,顛覆了過去的經驗,只需幾行代碼就可以優雅的做到水平垂直居中。
<div class="wp"> <div class="box">123123</div> </div> .wp { display: flex; justify-content: center; align-items: center; }
目前在移動端已經完全可以使用 flex 了,PC 端需要看自己業務的兼容性情況。
點擊查看完整 DEMO:
http://yanhaijing.com/vertical-center/flex.html
感謝 @一絲姐 反饋的這個方案,css 新出的網格布局,由于兼容性不太好,一直沒太關注,通過 grid 也可以實現水平垂直居中。
<div class="wp"> <div class="box">123123</div> </div> .wp { display: grid; } .box { align-self: center; justify-self: center; }
代碼量也很少,但兼容性不如 flex,不推薦使用。
點擊查看完整 DEMO:
http://yanhaijing.com/vertical-center/grid.html
下面對比下各個方式的優缺點,肯定又雙叒叕該有同學說回字的寫法了,簡單總結下:
小貼士:關于 flex 的兼容性決方案,請看這里:
https://yanhaijing.com/css/2016/08/21/flex-practice-on-mobile/
最近發現很多同學都對 css 不夠重視,這其實是不正確的,比如下面的這么簡單的問題都有那么多同學不會,我也是很無語:
<div class="red blue">123</div> <div class="blue red">123</div> .red { color: red } .blue { color: blue }
問兩個 div 的顏色分別是什么,竟然只有 40% 的同學能夠答對,這 40% 中還有很多同學不知道為什么,希望這些同學好好補習下 CSS 基礎。
備JavaScript面試時應了解的事項。
JavaScript現在是一種非常流行的編程語言,基于該語言,派生了大量庫和框架。 但是,無論高層生態系統如何發展,離不開原始的JavaScript。 在這里,我選擇了4個JavaScript面試問題來測試程序員使用普通JavaScript的技能。
如何手動實現Array.prototype.map方法?
熟練使用數組的內置方法并不難。但是,如果您只是熟悉語法而又不了解原理,那么很難真正理解JavaScript。
對于Array.prototype.map,它將創建一個新數組,其中將填充在調用數組中每個元素上調用提供的函數的結果。
如果引用lodash,我們可以編寫一個map函數,如下所示:
function map(array, iteratee) {
let index=-1
const length=array==null ? 0 : array.length
const result=new Array(length)
while (++index < length) {
result[index]=iteratee(array[index], index, array)
}
return result
}
使用示例:
如何實現這種編碼效果?
我們可以看到,當我們嘗試連續打印obj.a三次時,會得到三種不同的結果。看起來多么不可思議!
您可以創建一個神秘的對象obj來實現此效果嗎?
實際上,此問題有三種解決方案:
· 訪問者屬性
· Object.defineProperty
· 代理
根據ECMAScript,對象的屬性可以采用兩種形式:
從邏輯上講,對象是屬性的集合。每個屬性都是數據屬性或訪問器屬性:
· 數據屬性將鍵值與ECMAScript語言值和一組布爾屬性相關聯。
· 訪問器屬性將鍵值與一個或兩個訪問器函數以及一組布爾屬性相關聯。訪問器函數用于存儲或檢索與屬性關聯的ECMAScript語言值。
所謂的數據屬性通常是我們寫的:
let obj={ a: 1, b: 2}
我們對一個對象的屬性只有兩個操作:讀取屬性和設置屬性。對于訪問器屬性,我們使用get和set方法定義屬性,其編寫方式如下:
let obj={
get a(){
console.log('triggle get a() method')
console.log('you can do anything as you want')
return 1
},
set a(value){
console.log('triggle set a() method')
console.log('you can do anything as you want')
console.log(`you are trying to assign ${value} to obj.a`)
}
}
訪問屬性為我們提供了強大的元編程能力,因此我們可以通過以下方式滿足我們的要求:
let obj={
_initValue: 0,
get a() {
this._initValue++;
return this._initValue
}
}
console.log(obj.a, obj.a, obj.a)
第二種方法是使用Object.defineProperty,該方法的工作方式與我們用來訪問屬性的方法相同,除了不是直接聲明訪問屬性,而是通過Object.defineProperty配置訪問屬性。
這使用起來更加靈活,因此我們可以這樣編寫:
let obj={}Object.defineProperty(obj, 'a', { get: (function(){ let initValue=0; return function(){ initValue++; return initValue } })()})console.log(obj.a, obj.a, obj.a)
在這里的get方法中,我們使用了一個閉包,以便我們需要使用的變量initValue隱藏在閉包中,并且不會污染其他范圍。
第三種方法是使用代理。
使用代理,我們可以攔截對對象屬性的訪問。 只要我們使用代理來攔截對obj.a的訪問,然后依次返回1、2和3,我們就可以在以下條件之前完成要求:
let initValue=0;
let obj=new Proxy({}, {
get: function(item, property, itemProxy){
if(property==='a'){
initValue++;
return initValue
}
return item[property]
}
})
console.log(obj.a, obj.a, obj.a)
為什么理解這個問題很重要?因為Object.defineProperty和Proxy給了我們強大的元編程能力,所以我們可以適當地修改對象以做一些特殊的事情。
在著名的前端框架Vue中,其核心機制之一是數據的雙向綁定。在Vue2.0中,Vue通過使用Object.defineProperty實現了該機制。在Vue3.0中,使用Proxy完成此機制。
如果不掌握Vue之類的框架,您將無法真正理解。如果您掌握了這些原則,則只需學習Vue的一半,就可以獲得兩倍的結果。
運行此代碼的結果是什么?
function foo(a,b) {
console.log(b)
return {
foo:function(c){
return foo(c,a);
}
};
}
let res=foo(0);
res.foo(1);
res.foo(2);
res.foo(3);
上面的代碼同時具有多個嵌套函數和三個foo嵌套函數,乍一看看起來非常繁瑣。那么,我們如何理解這一點呢?
首先,請確保上面的代碼中有多少個功能?我們可以看到在上面的代碼中的兩個地方都使用了關鍵字函數,因此上面的代碼中有兩個函數,即第一行函數foo(a,b) 和第四行 foo:function(c)。并且這兩個函數具有相同的名稱。
第二個問題:第5行的foo(c,a)調用哪個函數?如果不確定,讓我們來看一個簡單的示例:
var obj={
fn:function (){
console.log(fn);
}
};
obj.fn()
如果我們運行該代碼,是否會引發異常? 答案是肯定的。
這是因為obj.fn()方法的上限是全局的,并且無法訪問obj內部的fn方法。
回到前面的示例,以同樣的邏輯,當我們調用foo(c,a)時,實際上是在第一行上調用foo函數。
當我們調用res.foo(1)時,將調用哪個foo? 顯然,第4行的foo函數被調用。
因為這兩個foo函數的工作方式不同,所以我們可以將其中一個的名稱更改為bar,以使我們更容易理解代碼。
function foo(a,b) {
console.log(b)
return {
bar:function(c){
return foo(c,a);
}
};
}
let res=foo(0);
res.bar(1);
res.bar(2);
res.bar(3);
此更改不會影響最終結果,但會使我們更容易理解代碼。如果將來遇到類似的問題,請嘗試此技巧。
每次調用一個函數時,都會創建一個新的作用域,因此我們可以繪制圖表以幫助我們理解代碼工作原理的邏輯。
當我們執行let res=foo(0);時,實際上是在執行foo(0,undefiend)。此時,將在程序中創建一個新的作用域,在當前作用域中a=0,b=undefined。因此,我繪制的圖看起來像這樣。
然后將執行console.log(b),因此它第一次在控制臺中打印出" undefined"。
然后執行res.bar(1),創建一個新范圍,其中c=1:
然后從上面的函數中再次調用foo(c,a),它實際上是foo(1,0),作用域如下所示:
在新作用域中,a的值為1,b的值為0,因此控制臺將打印出0。
再次執行res.bar(2)。注意,res.bar(2)和res.bar(1)是并行關系,因此我們應該像這樣繪制范圍圖:
因此,在此代碼中,控制臺也會打印出值0。
執行res.bar(3)的過程也是如此,控制臺仍顯示0。
因此,以上代碼的最終結果是:
實際上,上述問題可以用其他方式改變。例如,可以將其更改為以下內容:
function foo(a,b) {
console.log(b)
return {
foo:function(c){
return foo(c,a);
}
};
}
foo(0).foo(1).foo(2).foo(3);
在解決這個問題之前,我們要做的第一件事是區分兩個不同的foo函數,因此可以將上面的代碼更改為如下所示:
function foo(a,b) {
console.log(b)
return {
bar:function(c){
return foo(c,a);
}
};
}
foo(0).bar(1).bar(2).bar(3);
執行foo(0)時,作用域與以前相同,然后控制臺將打印出" undefined"。
然后執行.bar(1)創建一個新的作用域。此參數1實際上是c的值。
然后.bar(1)方法再次調用foo(c,a),它實際上是foo(1,0)。這里的參數1實際上將是新作用域中a的值,而0將是新作用域中b的值。
因此,控制臺隨后輸出了b的值,即0。
再次調用.bar(2),在新作用域中c的值為2:
然后.bar(2)調用foo(c,a),它實際上是foo(2,1),其中2是新作用域中a的值,而1是新作用域中b的值。
因此,控制臺隨后輸出了b的值,即0。
然后它將執行.bar(3),該過程與之前相同,因此我將不擴展其描述,此步驟控制臺將打印出2。
如上所述,代碼運行的最終結果是:
好了,經過漫長的旅程,我們終于得到了答案。 這個問題很好地檢驗了受訪者對封閉和范圍的理解。
假設我們有一個看起來像這樣的函數:
function compose (middleware) { // some code}
compose函數接受函數數組中間件:
let middleware=[]
middleware.push((next)=> {
console.log(1)
next()
console.log(1.1)
})
middleware.push((next)=> {
console.log(2)
next()
console.log(2.1)
})
middleware.push(()=> {
console.log(3)
})
let fn=compose(middleware)
fn()
當我們嘗試執行fn時,它將調用中間件中的函數,并將下一個函數作為參數傳遞給每個小函數。
如果我們在一個小函數中執行next,則將調用中間件中該函數的next函數。而且,如果您接下來不執行,程序也不會崩潰。
執行完上面的代碼后,我們得到以下結果:
1232.11.1
那么,我們如何編寫一個compose函數來做到這一點呢?
首先,compose函數必須返回一個composed函數,因此我們可以編寫如下代碼:
function compose (middleware) {
return function () { }
}
然后,在返回的函數中,中間件的第一個函數開始執行。我們還將傳遞下一個函數作為其參數。所以讓我們這樣寫:
function compose (middleware) {
return function () {
let f1=middleware[0]
f1(function next(){ })
}
}
下一個功能充當繼續在中間件中運行的開關,如下所示:
function compose (middleware) {
return function () {
let f1=middleware[0]
f1(function next(){
let f2=middleware[1]
f2(function next(){ ... })
})
}
}
然后繼續在下一個函數中調用第三個函數…等待,這看起來像遞歸! 因此,我們可以編寫一個遞歸函數來完成此嵌套調用:
function compose (middleware) {
return function () {
dispatch(0)
function dispatch (i) {
const fn=middleware[i]
if (!fn) return null
fn(function next () {
dispatch(i + 1)
})
}
}
}
好的,這就是我們的撰寫功能,所以讓我們對其進行測試:
好吧,此功能完全可以完成其所需的工作。 但是我們也可以優化我們的compose函數可以支持異步函數。 我們可以改進以下代碼:
function compose (middleware) {
return async function () {
await dispatch(0)
function async dispatch (i) {
const fn=middleware[i]
if (!fn)
return null
await fn(function next () {
dispatch(i + 1)
})
}
}
}
實際上,以上的撰寫功能是眾所周知的節點框架koa的核心機制。
當我選擇候選人時,我接受他/她對某些框架不熟悉。畢竟,JavaScript生態系統中有太多的庫和框架,沒有人能完全掌握它們。但是我確實希望候選人知道這些重要的原始JavaScript技巧,因為它們是所有庫和框架的基礎。
實際上,我的草稿中還有其他一些面試問題,但由于本文篇幅有限,因此在此不再繼續解釋。稍后再與您分享。
本文主要涉及普通JavaScript,而不涉及瀏覽器,節點,框架,算法,設計模式等。如果您對這些主題也感興趣,請隨時發表評論。
感謝您的閱讀!
(本文由聞數起舞翻譯自bitfish的文章《Improve Your JavaScript Level With These 4 Questions》,轉載請注明出處,原文鏈接:https://medium.com/javascript-in-plain-english/i-use-these-4-questions-to-find-outstanding-javascript-developers-4a468ea17155)
*請認真填寫需求信息,我們會在24小時內與您取得聯系。