hr小姐姐說一共有1輪筆試 + 3輪技術面 + 1輪hr面,面試地點在中關村天使大廈,崗位是1-3年前端
筆試分爲多選 簡答 判斷 手寫代碼四部分,下面只寫了印象比較深的幾道。css
一、position爲relative的元素可使用top和left進行定位嗎
答:能夠。
我本身沒見過這種寫法,就沒敢選,而後錯。前端
二、如下哪一個是加密算法
答:RES、DES。
md5不算加密算法。vue
這部分題目是給出代碼,讓你寫輸出
一、nginx
setTimeout(() => {console.log(1)}) const promise = new Promise(resolve => { setTimeout(() => {console.log(2)}) resolve() }) promise.then(() => {console.log(3)})
答:312。
考察macro/micro task面試
二、算法
for(var i = 1; i < 3; i++) { setTimeout(() => {console.log(i)}) }
答:3 3
考察異步,這個題簡直是必考題
變種:json
for(let i = 1; i< 3; i++) { setTimeout(() => {console.log(i)}) }
答:1 2
用let的話就會每輪循環都是一個嶄新的isegmentfault
三、api
function A() { this.a = 'hi' console.log(this.a) } A.prototype.a = 'hello' const a = new A() console.log(a.a)
答:hi hi
考察原型鏈,A.prototype.a = 'hello'
,修改的是a原型上的a屬性,與a自己的a屬性無瓜。
瀏覽器運行截圖跨域
四、
[] == false
答:true
考察類型轉換,雙等運算兩邊先轉換爲Number
五、
[1,2,3].push(4)
答:4
考察經常使用函數返回值, 數組的push和unshift都返回最新數組的長度
判斷就5道題,挺簡單的,沒啥印象
手寫一個節流函數,這個網上一搜一大把就不說了
筆試寫了大概30-40分鐘,一面的面試官就來了,看答題狀況的時候順便要求介紹一下本身,而後針對題目作了一些講解,而後開始問問題。
一、再手寫一個防抖,我寫了一個第一次觸發事件不會調用回調的,面試官又問若是但願首次也會調用怎麼寫,代碼以下
var debounce = function(fn, delayTime, immediate) { var timeId; return function() { var context = this, args = arguments; if(immediate) { var callNow = !timeId; if(callNow) { fn.apply(context, args); } } timeId && clearTimeout(timeId); timeId = setTimeout(function() { fn.apply(context, args); }, delayTime) } }
而後還聊了一下時間戳和定時器的方式實現節流的不一樣,須要注意箭頭函數是不可使用arguments對象的,因此返回的函數必需要寫成return function() {}
二、有什麼實現深拷貝的方法嗎
我一開始覺得他說api,就回答JSON.parse(JSON.stringfy())和MessageChannel,他問有什麼問題嗎。我說不能解決複製函數和環的問題。他又問那你能本身實現一個嗎,繼續手寫代碼
function isObject(obj) { return obj !== null && typeof obj === 'object' } function cloneDeep(obj) { let result = {} const keys = Object.keys(obj); for(let i = 0, len = keys.length; i < len; i++) { if(isObject(obj[keys[i]])){ result[keys[i]] = cloneDeep(obj[keys[i]]) } else { result[keys[i]] = obj[keys[i]] } } return resultset }
寫完以後他又問我應該如何判斷一個變量是數組,答Array.isArray()和Object.prototype.toString.call(arr) === '[object Array]',回來反思發現多是寫深拷貝的時候忘記了數組的狀況,而後他才問的判斷數組。
三、如何用css畫一個三角形
答:heigh: 0; width: 0; border: 100px, solid, transparent; border-bottom: 100px, solid, yellow;
四、怎麼實現垂直居中
答:position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); 還有flex;
五、簡單說一下前端優化策略
答:減小請求,他:具體應該怎麼減小,我:好比圖片懶加載,配置svg-sprite-loader打包一張svg圖面,而後就是減小dom操做,減小瀏覽器迴流重繪次數,減小做用域鏈的查找,減小對象的深度查找。他:還有嗎。我:暫時想不起其它了
優化涉及的東西太多了,之後再單獨總結吧。
六、new一個對象的時候發生了什麼
這個問題是講解筆試簡答第三題時候問的
正確答案:1.建立一個空對象; 2.設置建立對象的__proto__屬性的值爲構造函數的prototype屬性的值; 3.將第一步建立的空對象做爲this的上下文,執行構造函數代碼; 若是構造函數沒有返回對象,那麼返回this
七、看你簡歷上寫最近在看vue源碼,那你知道nextTick咋實現的嗎
答:2.6的版本是promise,mutationObserver,setTimeout,setImmediate
至此面試官說一面差很少就到這裏,算法啥的留給二面吧,他給個人一面評價是知識廣度不夠(由於筆試錯了比較多),可是感受人比較有靈性,能夠進入二面,而後就去叫下一個boss了。
二面面試官看起來比前一個要嚴厲好多,覺得要問一些算法題,結果"一面反饋基礎不夠紮實,那我就再問一點" "GG"
一、import和require的區別
答:import輸出引用,require輸出拷貝。他:還有嗎。 我:不知道了。他:還有require是運行時加載,import是編譯時輸出接口。
二、說一下瀏覽器的事件傳播機制
答:不知道
正確答案: 事件傳播分爲三個階段:捕獲,目標對象,冒泡。其中捕獲是事件對象從window派發到目標對象父級的過程;目標階段是事件對象派發到目標元素時的階段,若是事件類型指示不冒泡,那事件傳播在此階段終止;冒泡和捕獲相反,是以目標對象父級到window的過程。
三、手寫一個bind
答:不知道。
平時用的都是call和apply來改this,bind只用過一兩次,手寫call也看過,可是我連bind的參數是啥都沒印象,寫個錘子。
正確答案:
///使用call Function.prototype.cvBind = function() { var self = this var context = [].shift.call(arguments) var args = Array.from(arguments) return function() { return self.call(context, ...args) } } // 不用call Function.prototype.cvBind = function() { var context = [].shift.call(arguments) context.fn = this var args = [] var argument = [].slice.call(arguments, 0) for(var i = 0, len = argument.length; i < len; i++) { args.push('argument[' + i + ']') } return function() { var result = eval('context.fn(' + args + ')') delete context.fn return result } } // 測試 var obj = { a: 'local', log: function(x, y) { console.log(this.a, x, y) } } var a = 'window' obj.log('arg1', 'arg2') var func = obj.log.cvBind(window, 'arg1', 'arg2') func()
須要注意不用call的版本須要拷貝一次arguments,否則return的函數中args數組裏都是undefined,上面的代碼不考慮參數是引用類型變量。
2019.10.29更新
由於return的是一個function(){}
而不是箭頭函數,因此存在本身的arguments而不能使用閉包中的arguments,這裏拷貝一遍是能夠的能夠,可是也能夠返回一個箭頭函數來直接使用父做用域中的arguments
四、寫一個繼承
答:不知道
正確答案:
4.1類式繼承,經過構造函數實現繼承
//父類 function Parent(name) { this.name = name || 'parent' } Parent.prototype.say = function() { return this.name } //子類 function Child() {}
4.1.1 父類對象繼承
Child.prototype = new Parent('child') var child = new Child() child.say()
這種繼承方式,子類繼承父類自身屬性和父類原型上的屬性,可是缺點在於初始化父類對象指給子類原型時,並不能肯定父類構造函數的初始化參數。
4.1.2 改造子類構造函數
function Child() { Parent.apply(this, arguments) }
弟中弟方法,只能繼承父類自身方法
4.1.3 共享原型
Child.prototype = Parent.prototype
弟中弟中弟,共享一個原型,子類修改會影響父類(然而面試的時候腦子裏浮現的就是這種)
4.1.4 臨時構造函數
function inherit(Child, Parent) { var F = function() {} F.prototype = Parent.protoType Child.protoype = new F() }
利用一個空函數F()充當子類父類之間的代理,既能夠實現父類原型屬性的繼承,也能夠在子類原型上隨意拓展
使用Object.create()
能夠達到相同效果
Child.prototype = Object.create(Parent.prototype)
4.1.5 關於protptype.constructor
整理資料的時候,發現有些在繼承後又寫了一句Child.prototype.constructor = Child
,有些就沒有。首先這個constructor時建立實例對象的構造函數的引用,而後就是這句話到底有用沒用,下面是ctrl cv自MDN的兩個例子以及結論
示例1:
function Parent() {}; function CreatedConstructor() {} CreatedConstructor.prototype = Object.create(Parent.prototype); CreatedConstructor.prototype.create = function create() { return new this.constructor(); } new CreatedConstructor().create().create(); // error undefined is not a function since constructor === Parent
在上面的示例中,將顯示異常,由於構造函數連接到Parent。爲了不它,只需分配將要使用的必要構造函數。
function Parent() {}; function CreatedConstructor() {} CreatedConstructor.prototype = Object.create(Parent.prototype); CreatedConstructor.prototype.constructor = CreatedConstructor; // set right constructor for further using CreatedConstructor.prototype.create = function create() { return new this.constructor(); } new CreatedConstructor().create().create(); // it's pretty fine
示例2:
function ParentWithStatic() {} ParentWithStatic.startPosition = { x: 0, y:0 }; ParentWithStatic.getStartPosition = function getStartPosition() { return this.startPosition; } function Child(x, y) { this.position = { x: x, y: y }; } Child.prototype = Object.create(ParentWithStatic.prototype); Child.prototype.constructor = Child; Child.prototype.getOffsetByInitialPosition = function getOffsetByInitialPosition() { var position = this.position; var startPosition = this.constructor.getStartPosition(); // error undefined is not a function, since the constructor is Child return { offsetX: startPosition.x - position.x, offsetY: startPosition.y - position.y } };
對於此示例,就須要保持父構造函數繼續正常工做。
結論:手動設置或更新構造函數可能會致使不一樣且有時使人困惑的後果。爲了防止它,只需在每一個特定狀況下定義構造函數的角色。在大多數狀況下,不使用構造函數,而且不須要從新分配構造函數。
4.2 經過複製屬性實現繼承
淺拷貝和4.1.3的共享原型沒區別,深拷貝繼承以後修改父類,子類不會改變。都有問題不過也是一種思路,順帶一提。
五、跨域有哪些解決方案
答:iframe, jsonp, cors。他:用過jsonp嗎。答:沒有,用的都是cors。他:那說一下cors是怎麼解決跨域問題的。我:不知道。他:那請求頭裏有哪些相關的字段。我:(我知道你真的很給機會了可是對不起我是個菜雞我真的)不知道。他:用過nginx嗎。我:沒有。
正確答案:點這裏
balabala一些客套話,問我有什麼問題,我說沒有,而後結束。
認識到差距也更有前進的動力,繼續加油