年底研發組解散失業, 選擇回去學車了,也順利拿到了駕照,最近迴歸大深圳,開始踏上漫漫的找工做之路。javascript
拉勾上吊一百年不匹配, BOSS直聘日夜沒反應。css
題目範圍涵蓋我最近遇到的筆試題和麪談的(CSS/JS/HTTP/Node/Hybrid/Vue/NG/React)html
emm,這裏不列舉哪些公司了, 如果你完整的閱讀一遍,相信你有很多的收穫,謝謝閱讀前端
offer
,還有一些後續不清楚的font-size
,font-weight
,line-height
,color
,cursor
等display
,margin
、border
、padding
、height
等更加全面的能夠到引擎找vue
input
,span
,a
,img
以及display:inline
的元素p
,div
,header
,footer
,aside
,article
,ul
以及display:block
這些br
,hr
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>扇形</title>
<style> .sector { width: 0; height: 0; border-width: 50px; border-style: solid; border-color: #f00 transparent transparent; border-radius: 50px; } </style>
</head>
<body>
<div class="sector"></div>
</body>
</html>
複製代碼
box-sizing
經常使用的屬性有哪些? 分別有啥做用?box-sizing
有兩個值:content-box(W3C標準盒模型)
,border-box(怪異模型)
,html5
這個css 主要是改變盒子模型大小的計算形式java
可能有人會問padding-box
,這個以前只有 Firefox 標準實現了,目前50+的版本已經廢除;node
用一個栗子來距離,一個div
的寬高分別100px
,border
爲5px
,padding
爲5px
webpack
<style> .test { box-sizing: content-box; border: 5px solid #f00; padding:5px; width: 100px; height: 100px; } </style>
<div class="test"></div>
<!-- content-box的計算公式會把寬高的定義指向 content,border和 padding 另外計算, 也就是說 content + padding + border = 120px(盒子實際大小) 而border-box的計算公式是總的大小涵蓋這三者, content 會縮小,來讓給另外二者 content(80px) + padding(5*2px) + border(5*2px) = 100px -->
複製代碼
經常使用的通常爲三種.clearfix
, clear:both
,overflow:hidden
;nginx
比較好是 .clearfix
,僞元素萬金油版本,後二者有侷限性..等會再扯
.clearfix:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
<!--
爲毛沒有 zoom ,_height 這些,IE6,7這類須要 csshack 再也不咱們考慮以內了
.clearfix 還有另一種寫法,
-->
.clearfix:before, .clearfix:after {
content:"";
display:table;
}
.clearfix:after{
clear:both;
overflow:hidden;
}
.clearfix{
zoom:1;
}
<!--
用display:table 是爲了不外邊距margin重疊致使的margin塌陷,
內部元素默認會成爲 table-cell 單元格的形式
-->
複製代碼
clear:both
:如果用在同一個容器內相鄰元素上,那是賊好的,有時候在容器外就有些問題了, 好比相鄰容器的包裹層元素塌陷
overflow:hidden
:這種如果用在同個容器內,能夠造成 BFC
避免浮動形成的元素塌陷
transition
和animate
有何區別? animate
如何停留在最後一幀!這種問題見仁見智,個人回答大致是這樣的..待我捋捋.
transition
通常用來作過渡的, 沒時間軸的概念, 經過事件觸發(一次),沒中間狀態(只有開始和結束)
而animate
則是作動效,有時間軸的概念(幀可控),能夠重複觸發和有中間狀態;
過渡的開銷比動效小,前者通常用於交互居多,後者用於活動頁居多;
至於如何讓animate
停留在最後一幀也好辦,就它自身參數的一個值就能夠了
animation-fill-mode: forwards;
<!--backwards則停留在首幀,both是輪流-->
複製代碼
讓咱們來舉個栗子,.本身新建一個 html 跑一下,.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Box-sizing</title>
<style> .test { box-sizing: border-box; border: 5px solid #f00; padding: 5px; width: 100px; height: 100px; position:absolute; /* 簡寫的姿式排序 @keyframes name : 動畫名 duration 持續時間 timing-function 動畫頻率 delay 延遲多久開始 iteration-count 循環次數 direction 動畫方式,往返仍是正向 fill-mode 通常用來處理停留在某一幀 play-state running 開始,paused 暫停 ,. 更多的參數去查文檔吧..我就不一一列舉了 */ animation: moveChangeColor ease-in 2.5s 1 forwards running; } @keyframes moveChangeColor { from { top:0%; left:5%; background-color:#f00 } to{ top:0%; left:50%; background-color:#ced; } } </style>
</head>
<body>
<div class="test"></div>
</body>
</html>
複製代碼
咱們要考慮兩種狀況,定寬高和不定寬高的;
方案 N 多種,我記得我很早寫過這類的筆記
傳送門:網頁元素居中攻略記
!important
> 行內樣式 > id
> class
> tag
樣式權重能夠疊加, 好比 id>class
簡言之:就是不濫用標籤(好比 DIV)/隨意嵌套(好比 span>div) ,
類的命名要合理, 利於瀏覽器解析乃至引擎收錄,也利於團隊協做和維護
七種數據類型
(ES6以前)其中5種爲基本類型:string
,number
,boolean
,null
,undefined
,
ES6出來的Symbol
也是原始數據類型 ,表示獨一無二的值
Object
爲引用類型(範圍挺大),也包括數組、函數,
null
和undefined
的差別大致說一下,想要知其因此然請引擎搜索
相同點:
if
判斷語句中,值都默認爲 false
差別:
null
轉爲數字類型值爲0,而undefined
轉爲數字類型爲 NaN(Not a Number)
undefined
是表明調用一個值而該值卻沒有賦值,這時候默認則爲undefined
null
是一個很特殊的對象,最爲常見的一個用法就是做爲參數傳入(說明該參數不是對象)null
的變量或者對象會被內存收集器回收document.getElementById/ClassName/Name/TagName 等,或者 querySelector
)// example
// get Node
var element = document.querySelector('#test');
// 追加
element.appendChild(Node);
// 刪除
element.removeChild(Node);
// 查找
element.nextSibling // 獲取元素以後的兄弟節點 , 會拿到註釋文本,空白符這些
element.nextElementSibling // 等同, 獲取標籤(不會拿到註釋文本這些)
element.previousSibling // 和上面同理,往前找兄弟節點
element.previousElementSibling
// 改動,好比 屬性這些
element.setAttribute(name, value); // 增長屬性
element.removeAttribute(attrName); //刪除屬性
// 來一個簡易的練習題,隨便一個網頁追加插入一塊DOM(非覆蓋:不能 innerHTML);
/* <div id="test"> <span>Hello, World</span> </div> */
// 以上面的例子爲例
var test = document.createElement('div'); // 建立一個塊級元素
test.setAttribute("id","test"); // 設置其id 屬性
var span = document.createElement('span'); // 建立一個 span
span.innerText = "Hello,world"; // 插入 span 的文本內容
test.appendChild(span); // 組合節點
element.appendChild(test); //追加到某個節點區域
複製代碼
hasOwnProperty
,這個更多的是用來區分自身屬性和原型鏈上的屬性。
DOM
添加捕獲和冒泡的兩種寫法的事件點擊,誰先執行?分狀況分析:
node.addEventListener('event',callback,bubble or capture)
; 誰先調用誰先執行stackoverflow 有相關的探討:
ajax
全稱是異步 javascript 和 XML
,用來和服務端進行數據交互的,讓無刷新替換頁面數據成了可能;
至於有哪些要要點,來一個簡短的ajax
請求
var xhr = new XMLHttpRequest(); // 聲明一個請求對象
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){ // readyState 4 表明已向服務器發送請求
if(xhr.status === OK){ // // status 200 表明服務器返回成功
console.log(xhr.responseText); // 這是返回的文本
} else{
console.log("Error: "+ xhr.status); // 鏈接失敗的時候拋出錯誤
}
}
}
xhr.open('GET', 'xxxx');
// 如何設置請求頭? xhr.setRequestHeader(header, value);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(null); // get方法 send null(亦或者不傳,則直接是傳遞 header) ,post 的 send 則是傳遞值
複製代碼
更爲詳細的能夠閱讀此處;
這裏主要考察了閉包,函數表達式以及 IIFE(當即執行表達式)
var add = (function() {
// 聲明一變量,因爲下面 return因此變量只會聲明一次
var count = 0;
return function() {
return console.log(count++);
};
})();
add(); // 0
add(); // 1
add(); // 2
複製代碼
['1','2','3'].map(parseInt); // [1,NaN,NaN]
// 刨析
// map有三個參數:數組元素,元素索引,原數組自己
// parseInt有兩個參數,元素自己以及進制
// 理清了這兩個就好辦了,
// ['1','2','3'].map(parseInt); 等於以下
['1','2','3'].map(function(item,index,array){
return parseInt(item,index); // 是否是一目瞭然
});
// parseInt("1",0); => 1
// parseInt("2",1); => NaN
// parseInt("3",2); => NaN
複製代碼
WebSocket、localstorge、cookies
均可以。
要考慮瀏覽器無痕模式的話用WebSocket
會更好,否則功能基本失效或者報錯。
最多見的就是輪詢XHR
window
對象是指瀏覽器打開的窗口。
document
對象是HTML 文檔對象的一個只讀引用,window
對象的一個屬性。
我這裏用的是結合 ES6
的,代碼量很短
//很好理解, Set 具備值惟一性(但不是全部值,等會我拋出個人另一篇文章)
// 結合,解構,能夠把可迭代(好比 arguments/nodelist 等)的轉爲數組
// sort 裏面傳入 兩個值比較,返回-1和1是由於1表明這個數大排後(相對),-1表明小(相對),0爲相等
let arr = [,new Set(['2018-03-05', '2013-06-12','2019-03-12','2018-03-05','2014-02-22'])].sort(function(a,b){
return a<b ? -1:1; // 這裏返回的是升序的,降序改下返回值就行了.因此是相對
})
// ["2013-06-12", "2014-02-22", "2018-03-05", "2019-03-12"]
複製代碼
對於數組去重的,有興趣的能夠看下我這篇水文:
[1,2,3,4,5,'6',7,'8','a','b','z']
進行亂序// 咱們依舊能夠用上面的 sort 的原理實現亂序
let tempArr = [1,2,3,4,5,'6',7,'8','a','b','z'].sort(function(){
return Math.random() > 0.5 ? -1 : 1;
})
// 由於裏面有隨機數,因此答案沒有標準答案,我這邊跑了一次是輸出這個
//["6", "z", 3, "b", 5, 2, 7, "8", "a", 1, 4]
複製代碼
上面和這道題逗涉及到數組順序的問題,想了解下爲何 a-b
,a>b
這類能夠更改排序
能夠看看知乎對於這塊的探討: 傳送門:javascript排序return a-b?
[1, 10, 11, -1,'-5',12, 13, 14, 15, 2, 3, 4, 7, 8, 9]
內最大值與最小值之差// 來一個很粗糙的版本,只當傳入是數組且能夠隱性轉爲數字的
function MaxMinPlus(arr) {
// 返回最大值與最小值之差
return Array.isArray(arr) ? Math.max.apply(Math, arr) - Math.min.apply(Math, arr) : console.log('傳入的不是數組亦或者未能解決的錯誤')
}
// 結果是 20
// 如果要完善的話,要考慮傳入的是非數組,
//傳入字符串的時候要判斷,而後切割爲數組..
// 都要考慮進去代碼量不短
複製代碼
Array
實現一個方法,去重後返回重複的字符(新數組)var testArr = [1,6,8,3,7,9,2,7,2,4,4,3,3,1,5,3];
Array.prototype.extraChar = function(){
var cacheExtraChar = []; // 緩存重複出現的字符
var that = this; // 緩存 this;
this.map(function(item,index){
// 怎麼理解這段代碼呢?
// 就是向前日後查找一遍和從後往前查找一遍,不等就是沒有重複
// 爲何還要判斷一遍緩存,是過濾緩存數組內屢次寫入
(that.indexOf(item) !== that.lastIndexOf(item)) && cacheExtraChar.indexOf(item) === -1 ? cacheExtraChar.push(item) : -1;
});
return cacheExtraChar;
}
testArr.extraChar(); // [1, 3, 7, 2, 4]
// 如果還須要排序就再排序下
[1,6,8,3,7,9,2,7,2,4,4,3,3,1,5,3]
.extraChar()
.sort(function(a,b){return a-b}) // [1, 2, 3, 4, 7]
複製代碼
name
和 age
構成({name:'張三',age:15}
).請用 JS 實現年齡從小到大的排序;var par = [{age:5,name:'張三'},{age:3,name:'李四'},{age:15,name:'王五'},{age:1,name:'隨便'}]
var parSort = par.sort(function(a,b){
return a.age - b.age;
})
複製代碼
迴文字符串
就是正序倒序都是同樣的;
同字母異序字符串
字符串都同樣,可是位置可能不必定同樣,好比abcefd
和dceabf
=>return true
後者的思路就是用排序把異序扭正
普通版
// 迴文判斷 , 好比用 abcba
var isPalindromes = function(params){
params = params.toString().toLowerCase()
return params === params.split('').reverse().join('');
}
// 同字母異序斷定,好比`abcefd`和`dceabf`
var isAnagram = function(str1, str2) {
str1 = str1.toString().toLowerCase();
str2 = str2.toString().toLowerCase();
return str1.split('').sort().join('') === str2.split('').sort().join('')
}
複製代碼
進階版:多一些特殊字符
如果咱們要去除全部非字母數字的字符,則須要用到正則
// 進階版: isPalindromes('abc_ &b #@a')
var isPalindromes = function(params){
// 傳入參數先轉爲字符串且所有轉爲小寫,最後去除多餘字符比較
params = params.toString().toLowerCase().replace(/[\W_\s]/g,'');
console.log(params)
return params === params.split('').reverse().join('');
}
// 進階版同字母異序: isAnagram('ab *&cef#d','!d@ce^abf')
var isAnagram = function(str1, str2) {
str1 = str1.toString().toLowerCase().replace(/[\W_\s]/g,'');
str2 = str2.toString().toLowerCase().replace(/[\W_\s]/g,'');
return str1.split('').sort().join('') === str2.split('').sort().join('')
}
複製代碼
String.trim()
方法;// 原生是有 trim()方法的.咱們要模擬一個;
String.prototype.emuTrim = function(){
// 這條正則很好理解,就是把頭部尾部多餘的空格字符去除
return this.replace(/(^\s*)|(\s*$)/g,'');
}
' fsaf fsdaf f safl lllll '.emuTrim(); //"fsaf fsdaf f safl lllll"
複製代碼
for(var i=0;i<10;i++){
// TODO
}
複製代碼
// 這道題涉及到做用域
for(var i=0;i<10;i++){
setTimeout((function(i){
return function(){
console.log(i);
}
})(i),1000);
}
複製代碼
如果用到 ES6,那簡直不能再簡便了
for(let i=0;i<10;i++){
setTimeout(function(){
console.log(i);
},1000);
}
複製代碼
淺拷貝就是把屬於源對象的值都複製一遍到新的對象,不會開闢二者獨立的內存區域;
深度拷貝則是完徹底全兩個獨立的內存區域,互不干擾
// 這個 ES5的
function shallowClone(sourceObj) {
// 先判斷傳入的是否爲對象類型
if (!sourceObj || typeof sourceObj !== 'object') {
console.log('您傳入的不是對象!!')
}
// 判斷傳入的 Obj是類型,而後給予對應的賦值
var targetObj = sourceObj.constructor === Array ? [] : {};
// 遍歷全部 key
for (var keys in sourceObj) {
// 判斷全部屬於自身原型鏈上的 key,而非繼承(上游 )那些
if (sourceObj.hasOwnProperty(keys)) {
// 一一複製過來
targetObj[keys] = sourceObj[keys];
}
}
return targetObj;
}
// ES6 能夠用 Object.assign(targeObj, source1,source2,source3) 來實現對象淺拷貝
複製代碼
// 就是把須要賦值的類型轉爲基本類型(字符串這些)而非引用類型來實現
// JOSN對象中的stringify能夠把一個js對象序列化爲一個JSON字符串,parse能夠把JSON字符串反序列化爲一個js對象
var deepClone = function(sourceObj) {
if (!sourceObj || typeof sourceObj !== 'object') {
console.log('您傳入的不是對象!!');
return;
}
// 轉->解析->返回一步到位
return window.JSON
? JSON.parse(JSON.stringify(sourceObj))
: console.log('您的瀏覽器不支持 JSON API');
};
複製代碼
簡言之:誰調用指向誰,運行時的上下文肯定,而非定義的時候就肯定;
強行綁定 this
的話,能夠用 call
,apply
,bind
,箭頭函數來來改變this
的指向
這類的文章太多,自行搜索吧。
Q: 看到你說到 bind
,能用 JS簡單的模擬個麼?
Function.prototype.emulateBind = function (context) {
var self = this;
return function () {
return self.apply(context);
}
}
複製代碼
這個實現很粗糙,更爲詳細全面,考慮周全的(好比參數的處理什麼的),自行谷歌.
做用域就是有它自身的上下文區域(好比函數內),內部會有變量聲明提高,函數聲明提高這些;
函數聲明提高優於變量聲明提高..
做用域有全局做用域和塊級做用域(局部,好比用 let 或者單純花括號的);
做用域會影響this
的指向
坐等補充,我回答的時候,面試大佬只是 嗯..恩,恩,也不知道具體如何
我通常用這三種,cors
,nginx反向代理
,jsonp
jsonp
: 單純的 get 一些數據,侷限性很大,就是利用script標籤的src屬性來實現跨域。nginx 反向代理
: 主要就是用了nginx.conf
內的proxy_pass http://xxx.xxx.xxx
,會把全部請求代理到那個域名,有利也有弊吧..cors
的話,可控性較強,須要先後端都設置,兼容性 IE10+ ,好比
Q: 對於想攜帶一些鑑權信息跨域如何走起?好比cookie
!
須要配置下 header Access-Control-Allow-Credentials:true
,具體用法看下面的nginx
demo
固然cros
的配置不只僅這些,還有其餘一些,具體引擎吧,.
如果咱們要用 nginx
或者 express
配置cors
應該怎麼搞起? 來個簡易版本的
location / {
# 檢查域名後綴
add_header Access-Control-Allow-Origin xx.xx.com;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Headers DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type;
add_header Access-Control-Max-Age 86400;
}
複製代碼
cors
中間件,操做性更強,let express = require('express');
let app = express();
//設置全部請求的頭部
app.all('*', (req, res, next) => {
res.header("Access-Control-Allow-Origin", "xx.xx.com");
res.header("Access-Control-Allow-Headers", "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type");
res.header("Access-Control-Allow-Credentials","true")
res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
next();
});
複製代碼
有些還會跟你死磕,除了這些還有其餘姿式麼,我說了一個HTML5的postMessage
,
由於真心沒用過,只是之前查閱的時候瞭解了下,只能大致點下
這貨用於iframe
傳遞消息居多, 大致有這麼兩步步
window
打開一個實例,傳遞一個消息到一個x域名message
事件,獲取傳遞的消息這貨的兼容性沒那麼好,並且沒考慮周全下容易遭受 CSRF
攻擊
XSS
和 CSRF
如何防範這裏就不說概念性的東西了
XSS的防範
<>
這些形成代碼直接運行的的標籤..輪詢或者正則替換
cookie
,設置爲http-only
,避免客戶端的篡改CSRF的防範通常這幾種
HTTP Referer
字段,判斷請求來源token
加密解密,這種是目前很經常使用的手段了,任何防範都有代價的,好比驗證碼形成的體驗很差,token
濫用形成的性能問題,輪詢替換形成的響應時間等
cookie
,sessionStorage
,localStorage
的差別..cookie
: 大小4KB 左右,跟隨請求(請求頭),會佔用帶寬資源,可是如果用來判斷用戶是否在線這些挺方便sessionStorage
和localStorage
大同小異,大小看瀏覽器支持,通常爲5MB,數據只保留在本地,不參與服務端交互.
sessionStorage
的生存週期只限於會話中,關閉了儲存的數據就沒了.localStorage
則保留在本地,沒有人爲清除會一直保留javascript
的原型鏈你怎麼理解?原型鏈算是 JS 內一種獨有的機制,
全部對象都有一個內置[[proto]]
指向建立它的原型對象(prototype
)
原型鏈的基本用來實現繼承用的
javascript
裏面的繼承怎麼實現,如何避免原型鏈上面的對象共享我在寫的時候,用了兩種,一個是 ES5和 ES6的方案
function ParentClass(name) {
this.name = name;
}
ParentClass.prototype.sayHello = function () {
console.log("I'm parent!" + this.name);
}
function SubClass(name, age) {
//如果要多個參數能夠用apply 結合 ,解構
ParentClass.call(this, name);
this.age = age;
}
SubClass.prototype = Object.create(ParentClass.prototype);
SubClass.prototype.constructor = SubClass;
SubClass.prototype.sayChildHello = function (name) {
console.log("I'm child " + this.name)
}
let testA = new SubClass('CRPER')
// Object.create()的polyfill
/* function pureObject(o){ //定義了一個臨時構造函數 function F() {} //將這個臨時構造函數的原型指向了傳入進來的對象。 F.prototype = obj; //返回這個構造函數的一個實例。該實例擁有obj的全部屬性和方法。 //由於該實例的原型是obj對象。 return new F(); } */
複製代碼
class ParentClass {
constructor(name) {
this.name = name;
}
sayHello() {
console.log("I'm parent!" + this.name);
}
}
class SubClass extends ParentClass {
constructor(name) {
super(name);
}
sayChildHello() {
console.log("I'm child " + this.name)
}
// 從新聲明父類同名方法會覆寫,ES5的話就是直接操做本身的原型鏈上
sayHello(){
console.log("override parent method !,I'm sayHello Method")
}
}
let testA = new SubClass('CRPER')
複製代碼
class
/import
/export
/extends
)let
,const
async
/await
Array.inclueds
/String.padStart|String.padEnd
/Object.assign
let
會產生塊級做用域,不會形成變量提高,沒法從新聲明(但能夠從新賦值);const
async
和await
的用途?promise
的異步變成同步運行成了可能,await
能夠等到 promise
執行完畢this
指向誰?確定不少小夥伴會說指向局部方法內!!答案是錯誤的,
箭頭函數所改變的並不是把 this 局部化,而是徹底不把 this 綁定到裏面去;
就是 this 是取自外部的上下級做用域(可是又不是常規 function
的語法糖)..
由於箭頭函數裏並不支持 var self = this
或者 .bind(this)
這樣的寫法。
靜態方法是ES6以後纔有這麼個玩意,有這麼些特色
let a = new ParentClass => a.sayHello() 會拋出異常
static
方法無法覆蓋父類看下面的代碼..
class ParentClass {
constructor(name) {
this.name = name;
}
static sayHello() {
console.log("I'm parent!" + this.name);
}
static testFunc(){
console.log('emm,Parent test static Func')
}
}
class SubClass extends ParentClass {
constructor(name) {
super(name);
}
sayChildHello() {
console.log("I'm child " + this.name)
}
static sayHello() {
console.log("override parent method !,I'm sayHello Method")
}
static testFunc2() {
console.log(super.testFunc() + 'fsdafasdf');
}
}
ParentClass.sayHello(); // success print
let a = new ParentClass('test');
a.sayHello() // throw error
SubClass.sayHello(); // 同名 static 能夠繼承且覆蓋
SubClass.testFunc2(); // 能夠繼承
let testA = new SubClass('CRPER');
複製代碼
私有變量能夠用WeakMap
模擬,也能用語義化的下劃線,亦或者symbol
,
因此回來只是找了下相關的資料,發現有一個比較好的模擬方案,就是WeakMap
;
WeakMap
能夠避免內存泄露,當沒有被值引用的時候會自動給內存寄存器回收了.
const _ = new WeakMap(); // 實例化,value 必須爲對象,有 delete,get,has,set四個方法,看名字都知道了
class TestWeakMap {
constructor(id, barcode) {
_.set(this, { id,barcode });
}
testFunc() {
let { id,barcode } = _.get(this); // 獲取對應的值
return { id,barcode };
}
}
複製代碼
固然你也能夠用Symbol
來實現一個私有變量,這也是一個好法子
Promise
和ajax
沒有半毛錢直接關係.promise
只是爲了解決"回調地獄"而誕生的;
平時結合 ajax
是爲了更好的梳理和控制流程,這裏咱們簡單梳理下..
Promise
有三種狀態,Pending/resolve()/reject();
一些須要注意的小點,以下
Pending
轉爲另外兩種之一的狀態時候,狀態不可在改變..Promise
的 then
爲異步.而(new Promise()
)構造函數內爲同步Promise
的catch
不能捕獲任意狀況的錯誤(好比 then
裏面的setTimout
內手動拋出一個Error
)Promise
的then
返回Promise.reject()
會中斷鏈式調用Promise
的 resolve
如果傳入值而非函數,會發生值穿透的現象Promise
的catch
仍是then
,return
的都是一個新的 Promise
(在 Promise 沒有被中斷的狀況下)Promise 還有一些自帶的方法,好比race
,all
,前者有任一一個解析完畢就返回,後者全部解析完畢返回,
實現一個延時的 promise 函數, 能夠用
async
和await
const delay = (time)=> new Promise((resolve,reject)=>{
setTimeout(resolve,time)
})
// test
let testRun = async function(){
console.log(1);
await delay(2000);
console.log('我兩秒後才觸發',3)
}
// 1 => Promise = > 3
複製代碼
如下這段代碼的運行結果是什麼?
var test = new Promise((resolve,reject)=>{
resolve();
});
test
.then(data => {
// promise start
console.log('promise first then : ', data);
return Promise.resolve(1); // p1
})
.then(data => {
// promise p1
console.log('get parent(p1) resolve data : ', data);
return Promise.reject(new Error('哎呀,中斷了,你能奈我何!')); // p2
})
.then(data => {
// promise p2
console.log('result of p2: ', data);
return Promise.resolve(3); // p3
})
.catch(err => {
console.log('err: ', err);
return false;
});
// promise first then : undefined
// get parent(p1) resolve data : 1
// err: Error: 哎呀,中斷了,你能奈我何!
// 這裏在 then 返回 Promise.reject()的時候已經中斷了鏈式調用.直接給 catch捕獲到
複製代碼
別急,假如你無論有沒有捕獲到錯誤,最後再執行一個回調函數如何實現?
這裏說的就是相似try..catch..finally
,給Promise
實現一個 finally;
// finally比較好加,按照如今社區的討論,finally的特色以下:
// url : https://www.v2ex.com/t/205715
//1. 不接收任何參數,原來的value或者Error在finally裏是收不到的
//2. 處理後不影響原Promise的狀態,該reject仍是reject,該resolve仍是resolve
//3. 不影響Promise向後傳遞的傳,resolve狀態仍是傳遞原來的value,reject狀態仍是傳遞原來的Error
Promise.prototype.finally = function (callback) {
let P = this.constructor; // 這裏拿到的是 Promise 的構造函數
//無論前面的 Promise 是fulfilled仍是rejected,都會執行回調函數callback。
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
// 用法很簡單,就是能夠傳入一個回調函數..
// https://developers.google.com/web/updates/2017/10/promise-finally
// 這個 url 中說了 node 及 chrome 的哪些版本已經實現了 finally 及用法
// ES 2018已經把 finally 追加到 promise 的原型鏈中..
複製代碼
Q: TCP 是在哪一個OSI 的哪一個層!通信過程是全雙工仍是半雙工(單工)?
A: 傳輸層,全雙工
Q: TCP的通信的過程是怎麼樣的!
A: 整個過程是三次握手,四次揮手..
Q: 你說的沒錯,說說整個過程如何?
A: 舉個栗子,我把 TCP 比作兩我的用對講機溝通(大白話)..三次握手就是.A1(吼叫方,客戶端)想要呼叫 A2(控制室的某某,服務端)..
A1對着對講機說"over over ,聽到請回答"(第一次,請求應答) ,
A2收到迴應"收到收到,你說"(第二次,確認應答)
A1開始巴拉巴拉個不停而 A2沒拒絕(第三次,通信創建)
而四次揮手則是二者確認互相傾述完畢的過程..
A1說:"控制室,報告完畢了"(第一次揮手)
A2說:"知道了,那麼你廢話說完就好好聽我指揮,.巴拉巴拉.."(第二次揮手)
A1此時等待控制室說完畢,而控制室等迴應(第三次揮手)
等到 A1回饋控制室確認都知道完畢了..(第四次揮手),
以上都是瞎掰,可能有些地方描述不當,笑笑就行了
TCP
沒有百分百創建成功的,會形成連接失敗的狀況有不少..
好比長時間沒應答(A1吼了半天沒有反應或者 A2應答了而 A1再也不鳥它)..亦或者丟包(對講機也沒了);
TCP
協議相關的文章網上不少,如果要更加全面的瞭解該協議請自行引擎..
我建議閱讀<<TCP-IP詳解卷1~卷3>>,這個是網絡聖經,很厚,我只看了一丟丟..
對於這類的問題我也只能大致點了下,畢竟不是專攻網絡這塊的,
OSI
七層涵蓋:物理層,數據鏈路層,網絡層,傳輸層,會話層,表示層,應用層;
五層模型就是"會話,表示,應用層"同爲一層;
Q: DNS
的大致的執行流程瞭解麼,屬於哪一個層級?工做在哪一個層級?
DNS
屬於應用層協議, 至於TCP/UDP
哪一層上面跑,看狀況 , 大致的執行流程是這樣的;
DNS 默認端口是53,走 UDP
hosts
文件(好比你寫了映射關係優先尋找)DNS 的解析的幾個記錄類型須要瞭解:
A
: 域名直接到 IPCNAME
: 能夠多個域名映射到一個主機,相似在 Github Page
就用 CNAME
指向MX
: 郵件交換記錄,用的很少,通常搭建郵件服務器纔會用到NS
: 解析服務記錄,能夠設置權重,指定誰解析TTL
: 就是生存時間(也叫緩存時間),通常的域名解析商都有默認值,也能夠人爲設置TXT
: 通常指某個主機名或域名的說明回來我找下相關的資料,有興趣的能夠深刻了解下,傳送門以下:
我只是粗淺的回答了下,
HTTP
相對於 HTTPS
來講,速度較快且開銷較小(沒有 SSL/TSL) 對接,默認是80端口;
HTTP
容易遭受域名劫持,而HTTPS
相對來講就較爲安全(加密),默認端口爲443。
HTTP
是明文跑在 TCP
上.而HTTPS
跑在SSL/TLS
應用層之下,TCP
上的
Q: 那麼 HTTPS
中的TLS/SSL
是如何保護數據的,
通常有兩種形式,非對稱加密,生成公鑰和私鑰,私鑰丟服務器,公鑰每次請求去比對驗證;
更嚴謹的採用 CA(Certificate Authority),給密鑰簽名,.
Q: 你說到對稱加密和非對稱加密,能說說整個流程如何運轉的麼(HTTPS)
懂得真心很少,回來找了下相關資料,有興趣能夠點擊看看;
Q: SPDY
據說過麼.什麼來的?
谷歌推行一種協議(HTTP
之下SSL之上[TCP]),能夠算是HTTP2的前身,有這麼些優勢
而這些優勢基本 HTTP2也繼承下來了..
Q: 你對 HTTP 的狀態嗎瞭解多少,
這裏列舉一丟丟常見的..
If-Modified-Since or If-Match
去比對服務器的資源,緩存)Q: HTTP的請求報文是怎麼樣的,能大致的說下麼?
HTTP 的請求報文 = 請求行 + 請求頭 + 請求體;
accept
,content-type
,user-agent
這類值鍵對,服務端能夠直接讀取的想深刻了解的具體引擎搜索
Q: 請求報文知道,那你說說cookie
是如何跟隨請求的?
Cookie 就是保存在 HTTP 協議的請求或者應答頭部(Cookie 是由服務端生成),這樣一路漂泊,
Q: Cookie 隔離是什麼,如何作;
cookie 隔離就是下降
header
的數據包含,以達到加快訪問速度的目的
方案: 靜態資源丟 CDN或者非主域來加載
Last-Modified
:
If-Modified-Since
的時間,沒變更則使用本地的(狀態304)Expires(過時時間:緩存的載止時間)
,跟隨請求一塊兒發出..資源沒過時拿本地,不然從新請求Cache-control
是 HTTP1.1
的東西,判斷資源過時結合max-age
來替代Expires[http 1.0]
Etag
:
If-None-Match
,沒有改動依舊拿緩存(304)if(!("a" in window)){
var a = 10;
}
console.log(a); // undefined
// !("a" i n window) , 返回 true
/* var a; if(!("a" in window)){ a = 10; } */
// 變種題
(function(){
var x = c = b = {a:1}
})()
console.log(x.a); // error , x is not defined
console.log(c,b) // {a: 1} {a: 1}
複製代碼
var count = 0;
console.log(typeof count === "number"); // true , 這個不用解釋了
console.log(!!typeof count === "number"); // false
// 這裏涉及到就是優先級和布爾值的問題
// typeof count 就是字符串"number"
// !!是轉爲布爾值(三目運算符的變種),非空字符串布爾值爲 true
// 最後才=== 比較 , true === "number" , return false
複製代碼
(function(){
var a = b = 3;
})()
console.log(typeof a === "undefined"); // false
console.log(typeof b === "undefined"); // false
// 這裏涉及的就是當即執行和閉包的問題,還有變量提高,運算符執行方向(=號自左向右)
// 那個函數能夠拆成這樣
(function() var a; /* 局部變量,外部無法訪問*/ b = 3; /* 全局變量,so . window.b === 3 , 外部能夠訪問到*/ a = b; })() // 如果改爲這樣,這道題應該是對的 console.log(typeof b === "number" && b ===3 ); // true 複製代碼
function foo(something){
this.a = something;
}
var obj1 = {
foo:foo
};
var obj2 = {};
obj1.foo(2)
console.log(obj1.a) // 2 ,此時的 this 上下文還在 obj1內,如果 obj1.foo 先保存當作引用再執行傳參,則上下文爲 window
obj1.foo.call(obj2,3); // 用 call 強行改變上下文爲 obj2內
console.log(obj2.a); // 3
var bar = new obj1.foo(4); // 這裏產生了一個實例
console.log(obj1.a); // 2
console.log(bar.a); // 4; new的綁定比隱式和顯式綁定優先級更高
複製代碼
function fn(){
alert(a);
var a = 200;
alert(a);
}
fn(); // undefined / 200 ; 涉及變量提高
alert(a); // undefined
var a;
alert(a); // undefined
var a = 300;
alert(a); // 300
複製代碼
var obj1= {
name:'obj1',
fn:function(){
console.log(this.name);
}
};
var obj2 = {name:'obj2'};
var obj3 = {name:'obj3'};
// 這道題主要涉及的是 this 指向的問題..
obj1.fn(); // obj1
var newFn = obj1.fn;
newFn(); // undefined, this 指向 window
newFn.call(obj2);// obj2, this 指向 obj2
obj3.fn = newFn;
/* ƒ (){ console.log(this.name); } */
obj3.fn(); // 這裏指向的是 obj3 .因此輸出 obj3
複製代碼
// 這道題來做爲筆試題很繞,由於要回答的答案不少(腦海構思)..反正我是遇到了..
// 這道題主要考覈的是對原型鏈繼承這塊的理解
function Parent(){
this.a = 1;
this.b = [1,2,this.a];
this.c = {demo:5};
this.show = function(){
console.log(this.a + '' + this.c.demo + ':' + this.b)
}
}
function Child(){
this.a = 2;
this.change = function(){
this.b.push(this.a);
this.a = this.b.length;
this.c.demo = this.a++;
}
}
Child.prototype = new Parent();
var parent = new Parent();
var child1 = new Child();
var child2 = new Child();
child1.a = 11;
child2.a = 12;
// 這前面幾個還算簡單,繼續看下去
parent.show(); // 15:1,2,1
// 由於 Child 自身沒有 show 的方法,因此往原型鏈的上游找;
// 找到父類的,this 由於沒更改,因此輸出結果以下
child1.show(); // 115:1,2,1
child2.show(); // 125:1,2,1
child1.change(); // 改變一些數據,沒有輸出
child2.change(); // +1
parent.show(); // 15:1,2,1
child1.show(); // 55:1,2,1,11,12
child2.show(); // 65:1,2,1,11,12
複製代碼
// 這道題也很繞,函數遞歸調用的
function test(a,b){
console.log(b);
return {
test:function(c){
return test(c,a);
}
};
// 這道題的理解,拆成這樣就好理解了
/*function test(a,b){ console.log("a:"+a,"b:"+b); return { test:function(c){ console.log("a:"+a,"b:"+b,"c"+c); return test(c,a); } } }*/
var a = test(100); // undefined, 這個是不言而喻的;
a.test(200); // 100;
a.test(300); // 100;
var b = test(101).test(201).test(301); // undefined/101/201
var c = test(102).test(202); // undefined / 102
c.test(302); // 202
複製代碼
test.replace(/[abc]/g,''); // "345efg"
複製代碼
test.replace(/\d/g,'[$&]'); // "abc[3][4][5]efgabcab"
// 如果有分組則按照$1, $2, $3的形式進行引用,而 $& 則表示的是整個正則表達式匹配的內容。
複製代碼
var temp = test.split('').map(function(item){
return /^\d$/.test(item) ? item * 2 : item;
}).join('');
// "abc6810efgabcab"
複製代碼
"dream"
改爲"package"
,提供字符串"I have a dream"
;// 這是最簡單的代碼量了..
var str = "I have a dream";
str.replace(/dream/g,"package");
// 不用正則也能夠直接字符串替換
str.replace("dream","package")
複製代碼
// 很直白的大腦回路
var str = "I have a dream";
str.split(" ").map(function(item){
return item === "dream" ? item = "package":item;
}).join(" ");
複製代碼
var str = "I have a dream";
var tempArr = str.split(" "); // ["I", "have", "a", "dream"]
var removeIndex = tempArr.indexOf('dream'); // 3
tempArr.splice(removeIndex,1,"package");
var transStr = tempArr.join(" "); // "I have a package";
複製代碼
這類東東弄成數組仍是挺好弄的
這個是留言區小夥伴提供的方法..大同小異,以下;
// 源代碼
// 字符串也有數組的 slice 以及 concat 的方法..思路和數組差很少
var str = 'I haved a dream';
str.indexOf('dream') !== -1 ? str.slice(0,str.indexOf('dream')).concat('package'):str;
複製代碼
就是 macrotask
和microtask
相關的, 具體記不起來了,那時候給了答案雖然對了。
要說出因此然,給秀了一臉,回來找了下相關的資料;
來,這紙給你,寫個快排試試,
// 快排的大致思路是這樣的,
// 找個中位值,從原數組切割出來,
// 剩下的做爲兩個數組,每次都去比較;
// 直到遞歸的結果出來, 平均複雜度O(nlog n)
function quickSort(arr) {
//若是數組長度<=1,則直接返回
if (arr.length <= 1) {
return arr;
}
// 中間位(基準)取長度的一半向下取整
var pivotIndex = Math.floor(arr.length / 2);
//把中間位從原數組切割出來, splice 會改變原數組!!!!
var pivot = arr.splice(pivotIndex, 1)[0];
//定義兩個空數組來存放比對後的值
var left = [];
var right = [];
//比基準小的放在left,比基準大的放在right
for (var i = 0 , j = arr.length; i < j; i++) {
if (arr[i] <= pivot) {
left.push(arr[i]);
} else {
right.push(arr[i]);
}
}
//遞歸下去 arr = [ left , pivot , right]
// 怎麼個遞歸法,就是比對後的數組仍是會重複以前的取基準再切開比較..直到最後沒有能夠切了
return quickSort(left).concat([pivot], quickSort(right));
}
複製代碼
Q: 寫一個二分法查找
// 二分法跟快排的思路差很少,對半比較
// 這個只用於排序好數組內的查詢,高低位都知道的狀況下
function binSearch(target, arr, start, end) {
var start = start || 0; // 容許從什麼位置開始,下標
var end = end || arr.length - 1; // 什麼位置結束,下標
start >= end ? -1 : ''; // 沒有找到,直接返回-1
var mid = Math.floor((start + end) / 2); // 中位下標
if (target == arr[mid]) {
return mid; // 找到直接返回下標
} else if (target > arr[mid]) {
//目標值如果大於中位值,則下標往前走一位
return binSearch(target, arr, start, mid - 1);
} else {
//如果目標值小於中位值,則下標日後退一位
return binSearch(target, arr, mid + 1, end);
}
}
// binSearch(5,[1,2,3,4,5,6,7,8]) => 4
// 無序的數組則須要先排序好數組,不然會堆棧溢出(死循環)
複製代碼
這類的文章不少,有興趣的能夠閱讀下面的一些文章
傳送門:
問題的要點: 玻璃球碎(有限個數) ,肯定樓層數 , 最少次數 => 就是求最優的公式
在這道題上給秀的一臉,個人第一次的思路
先折半,就變成[1-50][51-100], 那就是 1+50 = 51次 ,
面試大佬說,你用了快排的思路就確定不是最優的..
憋了許久,想到開平方 , 這樣的話,最多隻要20次
而後又說給我三個球,在1000米的高樓,判斷多少次,可是根據我上面的話,
開立方, , 那最多不超過30次;
至於第一次丟球的位置如何肯定, 就是開平以後的值做爲一個區間.
若 N 個球和 M 米的大廈,第一次丟球的高度區間就是這個了
面試大佬說這個還能夠,那就暫且告一段落
,回來用萬能的搜索引擎找了下..最優方案+最少次數須要考慮的東西不少,沒那麼簡單
傳送門: 知乎有人討論了這個問題;
可是高數還老師了..這種帖子看的一臉懵逼,.抽空再好好研究下
大致常見的手段瞭解.
css sprite
)chunk
,減小單一 chunk
過大requestAnimationFrame
繪製動畫,儘量減小頁面重繪(DOM 改變)preload
這些預加載資源service worker
來緩存資源(好比移動端打算搞 PWA)固然,這是這些都是很片面的點到,實際工做中去開展要複雜的多;
好比咱們要多個維度去考慮的話,要去優化 DOM 的繪製時間,資源的加載時間,域名解析這些;
要全面的優化一個項目是一個大工程,
MySQL索引類型:
UNIQUE
索引有利有弊,用的好加快查詢速度,濫用索引會形成大量磁盤空間佔用,維護性也會增多; 索引不會包含null
的列;
索引的數據結構儲存方式,我只簡單瞭解過B-Tree
至於MySQL 和 MongoDB的差別;
前者是關係型數據庫, 後者非關係型數據庫(數據是以文檔的方式儲存,值爲 key-value
);
MySQL
應用層面很廣,有事務系統這些,鏈表查詢這些都很方便.常常做爲不少系統的主力數據庫
而MongoDB
做爲NoSQL
,雖然有些層面不如 MySQL
,可是應用層面也挺廣, 好比結合前端作一些用戶的概要信息的維護,一些緩存信息的維護.
em,.後端瞭解很少,也能點到即止,.大學的時候學過一些..都差很少還給老師,.
給定一個時間段和步長,枚舉該時間段內步長的劃分
例如:時間段
3:00-5:00
,步長爲20
分鐘那麼返回的數組爲
['3:00-3:20', '3:20-3:40',.]
等
這類問題,通常都要先梳理好思路再來寫;
// 這個東東個人小夥伴也寫出來了.個人是在它的解答方式上加以註釋和對參數的判斷作了考慮
// 他的解法方案在他的 github 上 https://github.com/lyh2668/blog/issues/1 , by lyh2668
// 方便一些小夥伴的理解,如下代碼包含ES6的姿式(參數默認值,剪頭函數)
let inputDateRange = (date, step = 30, separator = '-') => {
let startTime, endTime; // 開始時間和結束時間
if (Object.prototype.toString.call(date) === '[object String]') {
date = date.trim(); // 去除兩邊的空格
var tempDate = '';
if (separator) {
tempDate = date.split(separator);
} else {
if (date.indexOf('-') !== -1) {
tempDate = date.split('-');
} else if (date.indexOf('~')) {
tempDate = date.split('~');
} else {
console.log('您傳入的也許不是一個時間段!!!');
}
}
startTime = time2min(tempDate[0]); // 傳入的開始時間
endTime = time2min(tempDate[1]); //傳入的結束時間
} else if (Object.prototype.toString.call(date) === '[object Array]') {
if (date.length === 2) {
startTime = time2min(date[0]); // 傳入的開始時間
endTime = time2min(date[1]); //傳入的結束時間
}
} else {
console.log('您傳入的也許不是一個時間段!!!');
}
// 傳入的 step 是否爲數字,不然截圖數字部分轉化
// 爲何和 NaN 比較(自身不等性),如果傳入的連正則都無法識別,那隻能給默認值了
Object.prototype.toString.call(step) === '[object Number]'
? (step = parseInt(step, 10))
: parseInt(step.replace(/[W\s\b]/g, ''), 10) === NaN
? (step = parseInt(step.replace(/[W\s\b]/g, ''), 10))
: (step = 30);
// 如果開始時間大於結束時間則結束時間日後追加一天
startTime > endTime ? (endTime += 24 * 60) : '';
let transformDate = []; // 儲存轉換後的數組,時間分段
// 開始遍歷判斷,用 while
while (startTime < endTime) {
// 若是開始時間+步長大於結束時間,則這個分段結束,不然結束時間是步長遞增
let right = startTime + step > endTime ? endTime : startTime + step;
transformDate.push(`${min2time(startTime)}-${min2time(right)}`);
startTime += step; // 步長遞增
}
return transformDate;
};
// 時間轉化爲分鐘
let time2min = time => {
// 獲取切割的
time.indexOf(':') ? (time = time.trim().split(':')) : '';
return time[0] * 60 + parseInt(time[1]); // 返回轉化的分鐘
};
// 分鐘轉會字符串時間
let min2time = minutes => {
let hour = parseInt(minutes / 60); // 返回多少小時
let minute = minutes - hour * 60; // 扣除小時後剩餘的分鐘數
hour >= 24 ? (hour = hour - 24) : ''; // 如果大於等於24小時須要扣除一天獲得所剩下的小時
minute < 10 ? (minute = '0' + minute) : ''; // 小於10的都要補零
hour < 10 ? (hour = '0' + hour) : ''; // 小於10的都要補零
return `${hour}:${minute}`;
};
// test ,支持字符串傳入時間段
inputDateRange('3:00-5:00','20d'); // ["03:00-03:20", "03:20-03:40", "03:40-04:00", "04:00-04:20", "04:20-04:40", "04:40-05:00"]
// 亦或者數組傳入
inputDateRange(['3:00','5:00'],'45df.3d'); // ["03:00-03:45", "03:45-04:30", "04:30-05:00"]
// step 支持數字亦或者帶特殊字符的數字
inputDateRange(['6:00','8:00'],'55df.3d'); // ["06:00-06:55", "06:55-07:50", "07:50-08:00"]
inputDateRange('3:00-5:00',60); // ["03:00-04:00", "04:00-05:00"]
複製代碼
Vue-Router
的兩種模式主要依賴什麼實現的hash
主要依賴location.hash
來改動 URL,達到不刷新跳轉的效果.每次 hash
改變都會觸發hashchange
事件(來響應路由的變化,好比頁面的更換)history
主要利用了 HTML5
的 history
API 來實現,用pushState
和replaceState
來操做瀏覽歷史記錄棧這類的文章好多,三個開發模式的誕生都有先後,不是同時出現的.
傳送門:
153=1^3+5^3+3^3
function threeWaterFlower(rangeStart, rangeEnd) {
var temp = [];
rangeStart = rangeStart || 100;
rangeEnd = rangeEnd || 999;
for (var i = rangeStart; i <= rangeEnd; i++) {
var t = i.toString().split('');
Math.pow(t[0], 3) + Math.pow(t[1], 3) + Math.pow(t[2], 3) == i
? temp.push(i)
: '';
}
return temp;
}
threeWaterFlower(100,999); // [153, 370, 371, 407]
threeWaterFlower(); // [153, 370, 371, 407]
複製代碼
let manyWaterFlower = (rangeStart = 100, rangeEnd = 999, flower = 3) => {
let temp = [];
for (let i = rangeStart; i <= rangeEnd; i++) {
let t = i
.toString()
.split('')
.map(item => Math.pow(item, flower))
.reduce((cur,next)=> parseInt(cur)+parseInt(next));
let transformT = parseInt(t, 10);
transformT == i ? temp.push(i) : '';
}
return temp;
}
manyWaterFlower(); // [153, 370, 371, 407]
manyWaterFlower(100,10000,4); // [1634, 8208, 9474]
manyWaterFlower(100,10000,5); // [4150, 4151]
複製代碼
這種是窮舉遍歷,如果要快一點呢(考慮的周全一點呢),以及傳參範圍的矯正
相信小夥伴都看得懂,我已經儘可能註釋了..
let manyWaterFlower = (flower = 3,rangeStart, rangeEnd ) => {
let temp = [];// 緩存全部找到的花值
// 這一段就是填充開始循環的範圍,處理完畢後轉爲數字,推薦的開始值
let flowerRecommandStart = Number(
''.padStart(flower, '0').replace(/^(\d{1})/g, '1')
);
let flowerRecommandEnd = Number(''.padStart(flower, '9'));
// 判斷是否傳入開始值
if (rangeStart) {
rangeStart > flowerRecommandStart
? (rangeStart = flowerRecommandStart)
: rangeStart;
} else {
rangeStart = flowerRecommandStart;
}
// 判斷是否有傳入結束值
if (rangeEnd) {
rangeEnd > flowerRecommandEnd ? (rangeEnd = flowerRecommandEnd) : rangeEnd;
} else {
rangeEnd = flowerRecommandEnd;
}
// 如果初始值大於結束值
if (rangeStart > rangeEnd) {
rangeEnd = flowerRecommandEnd;
}
for (let i = rangeStart; i <= rangeEnd; i++) {
let t = i
.toString()
.split('')
.map(item => Math.pow(item, flower))
.reduce((cur, next) => parseInt(cur) + parseInt(next));
let transformT = parseInt(t, 10);
transformT == i ? temp.push(i) : '';
}
return temp;
};
console.time('manyWaterFlower');
manyWaterFlower(4)
console.timeEnd('manyWaterFlower');
// VM34013:4 manyWaterFlower: 8.112060546875ms ,這個是跑出來的時間
用上個例子的代碼,從100到9999的,咱們跑一下看看
console.time('manyWaterFlower');
manyWaterFlower(100,9999,4)
console.timeEnd('manyWaterFlower');
// VM3135:4 manyWaterFlower: 10.51904296875ms
// 個人 MBP 跑10花直接卡死,跑7花有點久,
console.time('7 flower')
manyWaterFlower(7);
console.timeEnd('7 flower')
// 7 flower: 6489.608154296875ms
// 8 花 CPU 的風扇狂叫,.
console.time('8 flower')
manyWaterFlower(8);
console.timeEnd('8 flower')
// VM644:3 8 flower: 68010.26489257812ms
// 對了咱們尚未考慮數值溢出的問題..由於正整數在 JS 的範圍是有限的.
// 有興趣的小夥伴能夠自行完善
複製代碼
好比console.log(findNode(['a1', 'b2'], data)) === data.a1.b2
// 請使用遞歸算法在 TODO 註釋後實現經過節點 key 數組尋找 json 對象中的對應值
var data = {
a1: {
b1: 1,
b2: 2,
b3: {
b4: 5
}
},
a2: {
b1: 3,
b2: 4
}
};
function findNode(inPath, inData) {
// TODO
// 判斷傳入的是不是一個數組
if (Array.isArray(inPath)) {
// 當長度爲1的時候尋找該 key 是否有值,有則返回,無則返回-1
if (inPath.length === 1) {
return inData[inPath[0]] ? inData[inPath[0]]: -1;
}else{
return findNode(inPath.slice(1), inData[inPath[0]]);
}
} else{
console.log('您傳入的不是一個數組')
}
}
console.log(findNode(['a1', 'b2'], data)); // 2
console.log(findNode(['a1', 'b3','b4'], data)); // 5
複製代碼
findNode('a1.b2',data)
?var data = {
a1: {
b1: 1,
b2: 2,
b3: {
b4: 5
}
},
a2: {
b1: 3,
b2: 4
}
};
// 判斷格式
function isType(params) {
let type = Object.prototype.toString.call(params);
if (type === '[object String]') {
params = params.split('.');
return params;
}
if (type === '[object Array]') {
return params;
}
}
function findNode(inPath, inData) {
inPath = isType(inPath);
// 判斷傳入的是不是一個數組
if (Array.isArray(inPath)) {
// 當長度爲1的時候尋找該 key 是否有值,有則返回,無則返回-1
if (inPath.length === 1) {
return inData[inPath[0]] ? inData[inPath[0]]: -1;
}else{
return findNode(inPath.slice(1), inData[inPath[0]]);
}
} else {
console.log('您傳入的不是一個數組');
}
}
console.log(findNode(['a1', 'b2'], data)); // 2
console.log(findNode('a1.b3.b4', data)); // 5
複製代碼
webpack 是一個資源處理工具,它的出現節省了咱們的人力和時間; 能夠對資源打包,解析,區分開發模式等等,
常見的優化手段:
dll
happypack
commonChunkPlugin
UglifyJS
bundle chunk
的大小,好比ExtractTextPlugin
tree shaking
目前webpack3/4已經默認集成大致過程是這樣的,想了解很細緻的能夠自行引擎;
props
on
+emit
on.sync
(語法糖)來的event bus
| vuex
Vuex
你怎麼理解?vuex
是一個狀態管理容器(你也能夠理解爲全局變量),數據的流向是是單向數據流,
且數據並不具備持久化的特性(默認狀況下刷新就重置全部狀態);
裏面的一些數據乃至方法,能夠大體理解爲 vue 的一些特性,好比
Vuex | Vue |
---|---|
state | data |
getter | computed |
mutation/actions | methods |
至於單向數據流(全局單例模式)怎麼理解
state
只能給mutation(同步操做)
改動, action
只能反饋給mutation
,能夠進行異步操做(好比和後端交互拉取數據), state
能觸發 render,action
能用dispatch
分發..如圖
還有一些題目記不起來了,就沒轍了,還有一些題目是看你我的發揮的,無法寫,好比
React
,Angular
,Vue
的比較?VNode
的理解,diff
的過程;Vue
的雙向綁定如何實現,用了什麼模式(訂閱模式),大致如何實現的。cmd
/amd
/commonjs
的差別React Native
的差別..等等面試的過程當中磕磕碰碰才能發現自身的不少不足和須要去努力的方向.
有不對之處請留言,會及時跟進修正,謝謝各位大佬
掘金技術徵文活動連接: juejin.im/post/5aaf2a…