1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        【秋招求職之路】字節(jié)跳動一面復盤總結

        共 14149字,需瀏覽 29分鐘

         ·

        2021-06-11 02:34

        往期精彩文章推薦



        字節(jié)跳動廣告系統(tǒng) 面經(jīng)

        一面

        自我介紹

        手撕防抖(如果滾動條判斷一個div是否存在會用什么來做?節(jié)流)

        <!DOCTYPE html>
        <html lang="en">
          <head>
            <meta charset="UTF-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1.0" />
            <title>實現(xiàn)防抖</title>
            <style>
              .container {
                width200px;
                height200px;
                background-color: aqua;
                font-size30px;
                line-height200px;
                text-align: center;
              }
            
        </style>
          </head>
          <body>
            <div class="container"></div>
            <script>
              var btn = document.getElementsByClassName('container')[0]
              // let cnt = 0
              // let timeId = null
              // btn.onmouseover = () => {
              //   clearTimeout(timeId)
              //   timeId = setTimeout(() => {
              //     btn.innerHTML = ++cnt
              //   }, 2000)
              // }
              let cnt = 0
              let doSomething = () => {
                btn.innerHTML = ++cnt
              }
              let debounce = (fn,time,triggerNow) => {
                let timeId = null
                let debounced = (...args) => {
                  if(timeId){
                      clearTimeout(timeId)
                    }
                  if(triggerNow){
                    let exec = !timeId
                    timeId =setTimeout(()=>{
                      timeId = null
                    },time)
                    if(exec){
                      fn.apply(this,args)
                    }
                  }else{
                    timeId = setTimeout(()=>{
                      fn.apply(this,args)
                    },time)
                  }
                }
                debounced.remove = () => {
                  clearTimeout(timeId)
                  timeId = null
                }
                return debounced
              }
              btn.onmouseover = debounce(doSomething,2000,false)
            
        </script>
          </body>
        </html>

        CSS實現(xiàn)三角形

        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>畫三角形</title>
            <style>
                .triggle{
                    width0px;
                    height0px;
                    border-top40px solid transparent;
                    border-left40px solid transparent;
                    border-bottom40px solid red;
                    border-right40px solid transparent;
                    margin40px;
                }
            
        </style>
        </head>
        <body>
            <div class="triggle"></div>
        </body>
        </html>

        了解偽元素和偽類嗎?

        參考:CSS偽類和偽元素的區(qū)別 - Web前端工程師面試題講解

        盒模型

        div
        width=100px;
        border: 10px;
        padding: 15px;
        margin: 10px;
        height=100px;

        content-box => 100px

        border-box => 150px

        Vue雙向綁定實現(xiàn) Object.defineProperty()  它有哪些不足點?

        • 只能監(jiān)聽某個屬性,不能對全對象進行監(jiān)聽
        • 需要 for in遍歷找對象中的屬性
        • 不能監(jiān)聽數(shù)組,需要單獨的對數(shù)組進行特異性操作
        • 會污染原對象
        data : {
        name; 'abc';
        age: 23,
        },


        this.name = 'brown';
        this.gender = '男';

        如何讓 gender 改變也會讓視圖變化(面試官意思是如何用Vue動態(tài)新增對象屬性,觸發(fā)dom渲染)

        背景:項目中因為一些需求需要在JSON中新增一個屬性,也能console出來,但是就是不能在頁面渲染,即不能觸發(fā)視圖更新

        其實在vue 中新增屬性應該用 $set 這個方法的

        1. 添加單個屬性

        $set()方法,既可以新增屬性,又可以觸發(fā)視圖更新。

        this.$set(this.data,”key”,value)

        2.添加多個屬性

        使用 Object.assign()用原對象與要混合進去的對象的屬性一起創(chuàng)建一個新的對象。

        this.obj = Object.assign({}, this.obj, {
          age18,
          name'Chocolate',
        })

        詢問輸出結果

        function Foo({
            getName = function ({ alert (1); };
            return this;
        }
        Foo.getName = function ({ alert (2);};
        Foo.prototype.getName = function ({ alert (3);};
        var getName = function ({ alert (4);};
        function getName({ alert (5);}

        //請寫出以下輸出結果:
        Foo.getName();
        getName();
        Foo().getName();
        getName();
        new Foo.getName();
        new Foo().getName();
        new new Foo().getName();

        參考:一道常被人輕視的前端JS面試題

        第一問

        先看此題的上半部分做了什么,首先定義了一個叫「Foo的函數(shù)」,之后為Foo創(chuàng)建了一個叫getName「靜態(tài)屬性」存儲了一個匿名函數(shù),之后為Foo的「原型對象」新創(chuàng)建了一個叫getName的匿名函數(shù)。之后又通過「函數(shù)變量表達式」創(chuàng)建了一個getName的函數(shù),最后再聲明一個叫getName函數(shù)。

        第一問的Foo.getName 自然是訪問Foo函數(shù)上存儲的「靜態(tài)屬性」,自然是2,沒什么可說的。

        第二問

        第二問,直接調(diào)用 getName 函數(shù)。既然是直接調(diào)用那么就是訪問「當前上文作用域內(nèi)」的叫getName的函數(shù),所以跟1 2 3都沒什么關系。此題有無數(shù)面試者回答為5。此處有兩個坑,「一是變量聲明提升,二是函數(shù)表達式?!?/strong>

        「變量聲明提升」

        所有聲明變量或聲明函數(shù)都會被提升到當前函數(shù)的頂部。例如下代碼:

        console.log('x' in window);//true
        var x;
        x = 0;

        代碼執(zhí)行時js引擎會將聲明語句提升至代碼最上方,變?yōu)椋?/p>

        var x;
        console.log('x' in window);//true
        x = 0;

        「函數(shù)表達式」

        var getNamefunction getName 都是聲明語句,區(qū)別在于var getName「函數(shù)表達式」,而function getName「函數(shù)聲明」。關于JS中的各種函數(shù)創(chuàng)建方式可以看 大部分人都會做錯的經(jīng)典JS閉包面試題 這篇文章有詳細說明。

        函數(shù)表達式最大的問題,在于js會將此代碼拆分為兩行代碼分別執(zhí)行。例如下代碼:

        console.log(x);//輸出:function x(){}
        var x=1;
        function x(){}

        實際執(zhí)行的代碼為,先將 var x=1拆分為var x;x = 1;兩行,再將 var x;function x(){}兩行提升至最上方變成:

        var x;
        function x(){}
        console.log(x);
        x=1;

        所以最終函數(shù)聲明的x覆蓋了變量聲明的x,log輸出為x函數(shù)。同理,原題中代碼最終執(zhí)行時的是:

        function Foo({
            getName = function ({ alert (1); };
            return this;
        }
        var getName;//只提升變量聲明
        function getName({ alert (5);}//提升函數(shù)聲明,覆蓋var的聲明

        Foo.getName = function ({ alert (2);};
        Foo.prototype.getName = function ({ alert (3);};
        getName = function ({ alert (4);};//最終的賦值再次覆蓋function getName聲明

        getName();//最終輸出4

        第三問

        第三問的Foo().getName(); 先執(zhí)行了Foo函數(shù),然后調(diào)用Foo函數(shù)的返回值對象的getName屬性函數(shù)。

        Foo函數(shù)的第一句  getName = function () { alert (1); }; 是一句函數(shù)賦值語句,注意它沒有var聲明,所以先向當前Foo函數(shù)作用域內(nèi)尋找getName變量,沒有。再向當前函數(shù)作用域上層,即外層作用域內(nèi)尋找是否含有getName變量,找到了,也就是第二問中的alert(4)函數(shù),將此變量的值賦值為 function(){alert(1)}。

        「此處實際上是將外層作用域內(nèi)的getName函數(shù)修改了?!?/strong>

        注意:此處若依然沒有找到會一直向上查找到window對象,若window對象中也沒有getName屬性,就在window對象中創(chuàng)建一個getName變量。

        簡單的講,「this的指向是由所在函數(shù)的調(diào)用方式?jīng)Q定的」。而此處的直接調(diào)用方式,this指向window對象

        遂Foo函數(shù)返回的是window對象,相當于執(zhí)行 window.getName() ,而window中的getName已經(jīng)被修改為alert(1),所以最終會輸出1

        此處考察了兩個知識點,一個是「變量作用域問題」,一個是「this指向問題」。

        第四問

        直接調(diào)用getName函數(shù),相當于 window.getName() ,因為這個變量已經(jīng)被Foo函數(shù)執(zhí)行時修改了,遂結果與第三問相同,為1

        第五問

        new Foo.getName(); ,此處考察的是js的運算符優(yōu)先級問題。

        js運算符優(yōu)先級:通過查上表可以得知點(.)的優(yōu)先級高于new操作,遂相當于是:

        new (Foo.getName)();

        所以實際上將getName函數(shù)作為了構造函數(shù)來執(zhí)行,遂彈出2

        第六問

        第六問 new Foo().getName(),首先看運算符優(yōu)先級「括號高于new」,并且?guī)?shù)的new操作符是優(yōu)先級最高的,實際執(zhí)行為

        (new Foo()).getName()

        遂先執(zhí)行Foo函數(shù),而Foo此時作為構造函數(shù)卻有返回值,所以這里需要說明下js中的「構造函數(shù)返回值問題」。

        原題中,返回的是this,而this在構造函數(shù)中本來就代表當前實例化對象,遂最終Foo函數(shù)「返回實例化對象」。之后調(diào)用實例化對象的getName函數(shù),因為在「Foo構造函數(shù)中沒有為實例化對象添加任何屬性」,遂到當前對象的原型對象(prototype)中尋找getName,找到了。

        遂最終輸出3。

        第七問

        最終實際執(zhí)行為:

        new ((new Foo()).getName)();

        先初始化Foo的實例化對象,然后將其原型上的getName函數(shù)作為構造函數(shù)再次new。

        遂最終結果為3

        答案

        function Foo({
            getName = function ({ alert (1); };
            return this;
        }
        Foo.getName = function ({ alert (2);};
        Foo.prototype.getName = function ({ alert (3);};
        var getName = function ({ alert (4);};
        function getName({ alert (5);}

        //答案:
        Foo.getName();//2
        getName();//4
        Foo().getName();//1
        getName();//1
        new Foo.getName();//2
        new Foo().getName();//3
        new new Foo().getName();//3

        promise相關,下面代碼輸出結果

        Promise.reject(2).catch(e => e).then(d => {
        console.log(d);
        });
        // 輸出2

        一般總是建議,Promise 對象后面要跟catch方法,這樣可以處理 Promise 內(nèi)部發(fā)生的錯誤。「catch方法返回的還是一個 Promise 對象,因此后面還可以接著調(diào)用then方法。」

        參考:你真的完全掌握了promise么?

        Promise 必知必會(十道題)

        關于 Promise 的 9 個面試題

        cookie 和 session 區(qū)別(session 存放哪)

        http是一個無狀態(tài)協(xié)議

        什么是無狀態(tài)呢?就是說這一次請求和上一次請求是沒有任何關系的,互不認識的,沒有關聯(lián)的。這種無狀態(tài)的的好處是快速。壞處是假如我們想要把www.zhihu.com/login.htmlwww.zhihu.com/index.html關聯(lián)起來,必須使用某些手段和工具

        cookie和session

        由于http的無狀態(tài)性,為了使某個域名下的所有網(wǎng)頁能夠共享某些數(shù)據(jù),session和cookie出現(xiàn)了??蛻舳嗽L問服務器的流程如下:

        • 首先,客戶端會發(fā)送一個http請求到服務器端。
        • 服務器端接受客戶端請求后,建立一個session,并發(fā)送一個http響應到客戶端,這個響應頭,其中就包含Set-Cookie頭部。該頭部包含了sessionId。Set-Cookie格式如下:Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure]
        • 在客戶端發(fā)起的第二次請求,假如服務器給了set-Cookie,瀏覽器會自動在請求頭中添加cookie
        • 服務器接收請求,分解cookie,驗證信息,核對成功后返回response給客戶端

        「注意」

        • cookie只是實現(xiàn)session的其中一種方案。雖然是最常用的,但并不是唯一的方法。禁用cookie后還有其他方法存儲,比如放在url中
        • 「現(xiàn)在大多都是Session + Cookie」,但是只用session不用cookie,或是只用cookie,不用session在理論上都可以保持會話狀態(tài)??墒菍嶋H中因為多種原因,一般不會單獨使用
        • 用session只需要在客戶端保存一個id,實際上「大量數(shù)據(jù)都是保存在服務端」。如果全部用cookie,數(shù)據(jù)量大的時候客戶端是沒有那么多空間的。
        • 如果只用cookie不用session,那么賬戶信息全部保存在客戶端,一旦被劫持,全部信息都會泄露。并且客戶端數(shù)據(jù)量變大,網(wǎng)絡傳輸?shù)臄?shù)據(jù)量也會變大

        拓展:token

        token 也稱作令牌,由uid+time+sign[+固定參數(shù)] token 的認證方式類似于「臨時的證書簽名」, 并且是一種服務端無狀態(tài)的認證方式, 非常適合于 REST API(表現(xiàn)層狀態(tài)轉(zhuǎn)換) 的場景. 所謂無狀態(tài)就是服務端并不會保存身份認證相關的數(shù)據(jù)。

        「組成」

        • uid: 用戶唯一身份標識
        • time: 當前時間的時間戳
        • sign: 簽名, 使用 hash/encrypt 壓縮成定長的十六進制字符串,以防止第三方惡意拼接 固定參數(shù)(可選): 將一些常用的固定參數(shù)加入到 token 中是為了避免重復查庫

        「存放」

        token在客戶端一般存放于localStorage,cookie,或sessionStorage中。在服務器一般存于數(shù)據(jù)庫

        token認證流程

        token 的認證流程與cookie很相似

        • 用戶登錄,成功后服務器返回Token給客戶端。
        • 客戶端收到數(shù)據(jù)后保存在客戶端
        • 客戶端再次訪問服務器,將token放入headers
        • 服務器端「采用filter過濾器校驗」。校驗成功則返回請求數(shù)據(jù),校驗失敗則返回錯誤碼

        token可以抵抗csrf,cookie+session不行

        假如用戶正在登陸銀行網(wǎng)頁,同時登陸了攻擊者的網(wǎng)頁,并且銀行網(wǎng)頁未對csrf攻擊進行防護。攻擊者就可以在網(wǎng)頁放一個表單,該表單提交src為http://www.bank.com/api/transfer,body為count=1000&to=Tom。倘若是session+cookie,用戶打開網(wǎng)頁的時候就已經(jīng)轉(zhuǎn)給Tom1000元了.因為「form 發(fā)起的 POST 請求并不受到瀏覽器同源策略的限制」,因此可以任意地使用其他域的 Cookie 向其他域發(fā)送 POST 請求,形成 CSRF 攻擊。在post請求的瞬間,cookie會被瀏覽器自動添加到請求頭中。但token不同,token是開發(fā)者「為了防范csrf而特別設計的令牌」,瀏覽器不會自動添加到headers里,攻擊者也無法訪問用戶的token,所以提交的表單「無法通過服務器過濾」,也就無法形成攻擊。

        分布式情況下的session和token

        負載均衡多服務器的情況,不好確認當前用戶是否登錄,因為多服務器不共享session。該解決方案是 session 數(shù)據(jù)持久化,「寫入數(shù)據(jù)庫或別的持久層」。各種服務收到請求后,都向持久層請求數(shù)據(jù)。這種方案的優(yōu)點是架構清晰,缺點是工程量比較大。另外,持久層萬一掛了,就會單點失敗。

        而token是無狀態(tài)的,token字符串里就「保存了所有的用戶信息」

        客戶端登陸傳遞信息給服務端,服務端收到后把用戶信息加密(token)傳給客戶端,客戶端將token存放于localStroage等容器中??蛻舳嗣看卧L問都傳遞token,服務端解密token,就知道這個用戶是誰了。通過cpu加解密,服務端就不需要存儲session占用存儲空間,就很好的解決負載均衡多服務器的問題了。這個方法叫做JWT(Json Web Token)

        Json web token (JWT), 是為了在網(wǎng)絡應用環(huán)境間傳遞聲明而執(zhí)行的一種基于JSON的開放標準((RFC 7519).該token被設計為緊湊且安全的,特別適用于分布式站點的單點登錄(SSO)場景。JWT的聲明一般被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息,以便于從資源服務器獲取資源,也可以增加一些額外的其它業(yè)務邏輯所必須的聲明信息,該token也可直接被用于認證,也可被加密。

        參考:阮一峰 JSON Web Token 入門教程

        總結

        • session存儲于服務器,可以理解為一個狀態(tài)列表,擁有一個唯一識別符號sessionId,通常存放于cookie中。服務器收到cookie后解析出sessionId,再去session列表中查找,才能找到相應session所依賴cookie
        • cookie類似一個令牌,裝有sessionId,存儲在客戶端,瀏覽器通常會自動添加。
        • token也類似一個令牌,無狀態(tài),用戶信息都被加密到token中,服務器收到token后解密就可知道是哪個用戶。需要開發(fā)者手動添加。
        • jwt只是一個跨域認證的方案

        如何保護cookie

        Secure和HttpOnly

        Secure屬性意味著把cookie通信限制在加密傳輸中,指示瀏覽器只能通過安全/加密連接使用cookie。然而如果一個web服務器在非安全連接中給cookie設置了一個secure屬性,這個cookie在發(fā)送給用戶時仍然可以通過「中間人攻擊」攔截到。因此,為了安全「必須通過安全連接」設置cookie的Secure屬性。

        HttpOnly屬性指示瀏覽器除了HTTP/HTTPS請求之外不要顯示cookie。這意味著這種cookie不能在客戶端通過腳本獲取,因此也不會輕易的被跨站腳本竊取。

        瀏覽器設置

        大部分瀏覽器都支持cookie,并且允許用戶禁止掉他們。下面是一些常用的選項:

        • 完全允許或者禁止cookie,以便瀏覽器總是接受或者總是阻止cookie
        • 通過cookie管理器查看或者刪除cookie
        • 徹底清除所有的隱私數(shù)據(jù),包括cookie

        HTTPS中 TLS握手過程簡述

        參考:三元博客 (傳統(tǒng)RSA版本)HTTPS為什么讓數(shù)據(jù)傳輸更安全?

        參考:TLS1.2 握手的過程是怎樣的?

        Koa 中間件 passport

        仿美團項目登錄怎么實現(xiàn)的

        瀏覽器緩存 強緩存 和 協(xié)商緩存 狀態(tài)碼

        結果

        一面通過

        小獅子有話說

        我是小獅子團隊的【一百個Chocolate】,全網(wǎng)同名,周更的前端博主,分享一些前端技術干貨與程序員生活日常,歡迎各位小伙伴的持續(xù)關注,一起變優(yōu)秀~



        學如逆水行舟,不進則退

        點擊【在看】可能會有紅包福利出現(xiàn)~

        瀏覽 39
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

          <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            欧美国产视频在线观看 | 二区三区偷拍浴室洗澡视频 | 妖精视频一区二区 | 俺去也www俺去也com | 強姦婬片A片AAA毛片Mⅴ | 毛片十八 | 公交车上伦理片 | 久久国产操 | 娇妻在粗大的胯下受辱 | 免费成人无码电影 |