主頁 > 後端開發 > JavaScipt 面試題+知識點

JavaScipt 面試題+知識點

2021-09-26 13:04:39 後端開發

變數型別

前置知識

  • 值型別 vs 參考型別

    // 值型別
    let a = 100;
    let b = a;
    a = 200;
    console.log(b); //100
    
    // 參考型別
    let a = { age: 20 };
    let b = a;
    b.age = 21;
    console.log(a.age); //21
    

    image-20210906141809809


    image-20210906142017216

    // 常見值型別
    let  a // undefined
    const s = 'abc' 
    const n = 100
    const b = true
    const m = Symbol('m');
    
    // 常見參考型別
    const obj = { x: 100 };
    const arr = ['a', 'b', 'c'];
    const n = null // 特殊參考型別 指標指向空地址
    
    // 特殊參考型別 因為不用于存盤資料,所以沒有“拷貝、復制函式”一說
    function fn(){}
    
  • 邏輯運算

    • truthy變數:!!a === true 的變數

      let a = 100;
      !a; //false
      !!a; //true
      
    • falsy變數:!!a === false 的變數

      在 JavaScript 中只有 8 falsy 值,

      // 以下是falsely變數 除此之外都是truely變數
      !!0 === false
      !!-0 ===false
      !!NaN === false
      !!0n ===false (bigInt)
      !!'' === false
      !!null === false
      !!undefined === false
      !!false === false
      
    1. if 陳述句 判斷的是否為truthy或者falsy,

    2. 與或非同樣判斷的是 truthy或者falsy

      console.log(10&&0); //0
      console.log(''||'abc') //'abc'
      console.log(!window.abc) //true
      

題目

  1. typeof 能判斷哪些型別

    // typeof 可以判斷所有值型別
    let a;                     typeof a; //undefined
    let str = 'abc';           typeof str; // string
    const n = 100;             typeof n; // number
    const b = true;            typeof b; // boolean
    const s = Symbol('s');     typeof s; // symbol
    let big = BigInt(10e15);   typeof big; // bigint
    
    // 能判斷參考型別
    typeof console.log         // function
    typeof function(){}        // function
    
    // 能識別參考型別
    typeof null;               // object
    typeof [1, 2, 3];          // object
    typeof {x:100};            // object
    
  2. 何時使用 === 何時使用 ==

    // 除了 == null以外,其他一律用 ===, 例如
    const obj = {x:100}
    if(obj.a == null) {}
    // 相當于
    if(obj.a === null || obj===undefined){}
    
  3. 值型別和參考型別的區別

    值型別的值直接存盤在堆疊中,而參考型別在堆疊中存盤的是地址,地址指向其在堆中對應的值,

  4. 手寫深拷貝

    const obj = {
        age: 20,
        name: '張三',
        address: {
            city: 'beijing'
        },
        arr: [1, 2, 3, [4, 5, 6]]
    }
    
    /**
     * 深拷貝
     * @param {Object} obj  要拷貝的物件
     */
    
    function deepClone(obj) {
        if (typeof obj !== 'object' || obj === undefined) {
            // 如果obj不是object型別或者為undefined
    
            return obj;
        }
        //  初始化回傳結果
        let result;
        if (obj instanceof Array) {
            result = [];
        } else {
            result = {};
        }
        for(let key in obj){
            // 保證key 不為原型的屬性
            if(obj.hasOwnProperty(key)){
                // 遞回 如果是陣列,此時的key為索引
                result[key] = deepClone(obj[key]);
            }
        }
        return result;
    }
    const obj2 = deepClone(obj);
    

前置知識

  1. class

    • constructor
    • 屬性
    • 方法
    class Student{
        constructor(name,number){
            this.name = name;
            this.number = number;
        }
        sayHi(){
            console.log(`姓名${this.name}  學號:${this.number}`);
        }
    }
    // 實體化物件
    const Alex = new Student('Alex','001');
    console.log(Alex.name);
    console.log(Alex.number);
    Alex.sayHi();
    
  2. 繼承

    • extends
    • super
      • 執行 super.method(...) 來呼叫一個父類方法,
      • 執行 super(...) 來呼叫一個父類 constructor(只能在我們的 constructor 中),
    // 父類
    class People{
        constructor(name){
            this.name = name;
        }
        eat(){
            console.log(`${this.name} can eat`);
        }
    } 
    
    // 子類
    class Student extends People{
        constructor(name,number){
            super(name);
            this.number = number;
        }
        sayHi(){
            super.eat();
            console.log(`姓名${this.name}  學號:${this.number}`);
        }
    }
    
    const Alex = new Student('Alex','001');
    console.log(Alex.name);
    console.log(Alex.number);
    Alex.sayHi();
    

題目

  1. 如何準確判斷一個變數是否為陣列?

    Array.isArray(xx) 或者 xx instanceof Array

  2. 手寫一個簡易的jQuery,考慮插件和拓展性?

    class jQuery{
        constructor(selector){
            this.selector = selector;
            const result = document.querySelectorAll(selector);
            for(let i =0; i<result.length;i++){
                this[i] = result[i];
            }
            this.length = result.length;
        }
        get(index){
            return this[index];
        }
        each(fn){
            for(let i=0;i<this.length;i++){
                fn(this[i])
            }
        }
        on(type,fn){
            return this.each(elem=>{
                elem.addEventListener(type,fn,false);
            })
        }
    }
    
    // 插件
    jQuery.prototype.dialog =function(info){
        alert(info);
    }
    
    // 復寫
    class myJQuery extends jQuery{
        constructor(selector){
            super(selector);
        }
        getLenth(){
            console.log(this.length);
        }
    }
    
     new myJQuery('p').getLenth();
    
    
  3. 如何理解class的原型本質

    人們常說 class 是一個語法糖,因為我們實際上可以在沒有 class 的情況下宣告相同的內容,

    盡管,它們之間存在著重大差異:

    1. 首先,通過 class 創建的函式具有特殊的內部屬性標記 [[IsClassConstructor]]: true,因此,它與手動創建并不完全相同,

      編程語言會在許多地方檢查該屬性,例如,與普通函式不同,必須使用 new 來呼叫它:

    2. 類方法不可列舉, 類定義將 "prototype" 中的所有方法的 enumerable 標志設定為 false

      這很好,因為如果我們對一個物件呼叫 for..in 方法,我們通常不希望 class 方法出現,

    3. 類總是使用 use strict, 在類構造中的所有代碼都將自動進入嚴格模式,

作用域和閉包

前置知識

  • 自由變數

    • 一個變數在當前作用域沒有定義,但是被使用了
    • 向上一級作用域,一層一層依次尋找,直至找到為止
    • 如果到全域作用域都沒有找到,則報錯xx is not defined
  • 作用域

    • 全域作用域
    • 函式作用域
    • 塊級作用域
  • 閉包

    • 作用域應用的特殊情況,有兩種表現:①函式作為引數傳遞 ②函式作為回傳值被回傳

    • 最關鍵的地方:在函式定義的位置找!

    • 所有的自由變數的查找,是在函式定義的地方,向上級作用域查找,不是在執行的地方,

      // 函式作為回傳值
      function create() {
          let a = 100;
          return function () {
              console.log(a);
          }
      }
      
      let fn = create();
      
      let a = 200;
      
      fn(); //100
      
      // 函式作為引數
      function print(fn){
          let a = 200;
          fn();
      }
      
      let a =100;
      
      function fn(){
          console.log(a);
      }
      print(fn); //100
      
  • this

    this的值是在函式呼叫時確定的,不是在函式定義時確定的,

    • 作為普通函式

      function fn1(){
          console.log(this);
      }
      
      fn1(); // window
      
    • 使用call apply bind

      fn1.call({x:100});  // this指向 {x:100}
      
      const fn2 = fn1.bind({x:200});
      fn2();  //{x:200}
      
    • 作為物件方法被呼叫

      const zhangsan = {
          name: '張三',
          sayHi(){
              // this 即當前物件
              console.log(this);
          },
          wait(){
              setTimeout(function(){
                  // this指向window
                  console.log(this);
              },10);
          },
          waitAbitLonger(){
              setTimeout(() => {
                  console.log(this);
              }, 100);
          }
      }
      
      zhangsan.sayHi();
      zhangsan.wait(); //window
      zhangsan.waitAbitLonger(); //指向物件張三
      
      const wait = zhangsan.waitAbitLonger;
      wait(); // window
      
    • 在class方法中被呼叫

      class People{
          constructor(name){
              this.name = name;
              this.age = 20;
          }
          sayHi(){
              console.log(this);
          }
      }
      
      const zhangsan = new People('張三');
      zhangsan.sayHi(); // zhangsan 物件
      
    • 箭頭函式

題目

  1. this 的不同應用場景,如何取值?

  2. 手寫 bind 函式

    function fn1(...args){
        console.log('this',this);
        console.log(...args);
        return 'this is fn1'
    }
    
    
    // const fn2 = fn1.bind({x:200},10,20,30);  原生bind
    // const res = fn2();
    // console.log(res);
    
    // 手寫bind
    Function.prototype.bind1= function(){
        // 將引數變為陣列
        const args = [...arguments];
        // 獲取this
        const t = args.shift();
          
        // 此時的this指向呼叫bind1的函式 比如fn1.bind1() 則bind1()中的this指向fn1
         const self = this;
    
        //回傳一個函式
         return function(){
              return self.apply(t,args);
         }
    
    }
    
    let test = fn1.bind1({x:200},10,20,30);
    console.log(test());
    
    // 手寫apply
    function fn(...args) {
        console.log(this);  //(**)
        console.log('I got called with ' + [...args].join(' '));
        return [...args].reduce((total, curr) => total + curr, 0);
    }
    
    
    Function.prototype.applyTest = function (t, args) {
        // 此時的this 指向呼叫applyTest的函式
        // t為需要被指定的背景關系
        t.__proto__.fn = this; 
        // 為什么要在原型鏈上添加,因為如果不在原型鏈添加 在(**)中列印this時就多了這個函式
    
        let result = t.fn(...args);
        delete t.__proto__.fn;
        return result
    }
    
    let result = fn.apply({ zs: 100 }, [2, 3, 4]);
    console.log(result);
    
    // 瞎寫補充一點
    Function.prototype.applyTest = function (t, args) {
        if (t == undefined) {
            if (args == undefined) {
                // 此時沒有背景關系 也沒有引數 直接呼叫函式即可
                return this(args);
            } else {
                // 展開引數
                return this(...args);
            }
        }
        t.__proto__.fn = this;
        let result;
        if (args == undefined) {
            result = t.fn(args);
        } else {
            result = t.fn(...args);
        }
        delete t.__proto__.fn;
        return result;
    }
    
  3. 閉包在實際開發中的應用場景,舉例說明

    // 隱藏閉包中的資料 快取資料
    // 例子1
    function createCache(){
        const data = {}; // 閉包中的資料被隱藏 不被外界訪問
        return {
            set: function(key,val){
                data[key] = val;
            },
            get:function(key){
                return data[key];
            }
        }
    }
    
    const c = createCache();
    c.set('a',100);
    console.log(c.get('a'));
    
    
    // 例子2
    function slow(x) {
      // 這里可能會有重負載的 CPU 密集型作業
      alert(`Called with ${x}`);
      return x;
    }
    
    function cachingDecorator(func) {
      let cache = new Map();
    
      return function(x) {
        if (cache.has(x)) {    // 如果快取中有對應的結果
          return cache.get(x); // 從快取中讀取結果
        }
    
        let result = func(x);  // 否則就呼叫 func
    
        cache.set(x, result);  // 然后將結果快取(記住)下來
        return result;
      };
    }
    
    slow = cachingDecorator(slow);
    
    alert( slow(1) ); // slow(1) 被快取下來了
    alert( "Again: " + slow(1) ); // 一樣的
    
  4. 創建10個 <a> 標簽,點擊的時候彈出對應的序號,

    這個題目和這里一模一樣:

    // 創建10個a標簽 點擊的時候彈出對應的序號
    // 方法一
    for(let i = 0; i<10;i++){
        a = document.createElement('a');
        a.innerHTML = i +' ';
        a.addEventListener('click',(e)=>{
            e.preventDefault();
            alert(i);
        })
        document.body.appendChild(a);
    }
    // 方法二
    for (i = 0; i < 10; i++) {
        (function (i) {
            a = document.createElement('a');
            a.innerHTML = i + ' ';
            a.addEventListener('click', (e) => {
                e.preventDefault();
                alert(i);
            })
            document.body.appendChild(a);
        })(i)
    }
    
    const div = document.querySelector('div');
    // 創建一個檔案片段,還沒有插入到檔案片段中
    const frag = document.createDocumentFragment();
    for(let i = 0; i<10;i++){
        const a = document.createElement('a');
        a.innerHTML = `list item ${i}`;
        // 將a標簽插入到檔案片段中
        frag.appendChild(a);
        a.addEventListener('click',()=>{
            console.log(i);
        })
    }
    div.appendChild(frag);
    

異步和單執行緒

前置知識

  • 單執行緒和異步
    • 單執行緒:js是單執行緒語言,只能同時做一件事情,因為js可以修改DOM結構,所以js和dom渲染必須共用同一個執行緒,
    • 異步:遇到等待(網路請求,定時任務)不能卡住,因此需要異步,異步是基于callback函式形式,當存在許多callback時,容易導致回呼地獄,因此又誕生了promise,
      • 因為js是單執行緒語言,異步不會阻塞代碼執行,同步會阻塞代碼執行
    • 應用場景:
      • 網路請求:如ajax加載圖片
      • 定時任務:如setTimeOut

題目

  1. 同步和異步的區別是什么?

    • 基于Js是單執行緒語言,異步不會阻塞代碼執行,同步會阻塞代碼執行,
  2. promise 加載一張圖片

    const url = 'https://gitee.com/zyxbj/image-warehouse/raw/master/pics/202109101448581.png';
    
    function loadImg(url){
        return new Promise((resolve,reject)=>{
            const img = document.createElement('img');
            img.src = url;
            img.onload= ()=>{
                resolve(img);
            }
            img.onerror=()=>{
                reject(new Error(`圖片加載失敗 ${src}`))
            }
        })
    }
    loadImg(url).then((img)=>{
        document.body.appendChild(img);
    }).catch(err=>console.log(err));
    
  3. 前端使用異步的場景有哪些?

    • 網路請求:如ajax加載圖片
    • 定時任務:如setTimeOut

DOM

前置知識

  • DOM 本質

    • 檔案物件模型(Document Object Model),簡稱 DOM,將所有頁面內容表示為可以修改的物件,DOM 將 HTML 表示為標簽的樹形結構,
    • image-20210910153552147
  • DOM 節點的操作

    • 獲取DOM節點

      方法名搜索方式可以在元素上呼叫?實時的?
      querySelectorCSS-selector?-
      querySelectorAllCSS-selector?-
      getElementByIdid--
      getElementsByNamename-?
      getElementsByTagNametag or '*'??
      getElementsByClassNameclass??
      • elem.getElementsByTagName(tag) 查找具有給定標簽的元素,并回傳它們的集合,tag 引數也可以是對于“任何標簽”的星號 "*"
      • elem.getElementsByClassName(className) 回傳具有給定CSS類的元素,
      • document.getElementsByName(name) 回傳在檔案范圍內具有給定 name 特性的元素,很少使用,
    • attribute

      • attribute是HTML標簽上的特性,它的值只能夠是字串;修改標簽的屬性,會改變html結構,

        const span = document.querySelector('span');
        span.setAttribute('data-name','hello');
        console.log(span.getAttribute('data-name')); //hello
        span.setAttribute('class','hello')
        
    • property

      • property是DOM中的屬性,是JavaScript里的物件;修改物件屬性,不會體現到html結構中,

        const span = document.querySelector('span');
        console.log(span.style.width);
        console.log(span.className); // hello work 字串
        console.log(span.classList);// ['hello', 'work', length: 2 value: 'hello work']
        console.log(span.parentNode);
        console.log(span.nodeName); //SPAN
        console.log(span.nodeType); //1
        

        property和attribute兩者都可能導致重新渲染dom,

  • DOM 結構操作

    • 新增節點

      • appenChild:

        target.appendChild(newChild)

        newChild作為target的子節點插入最后的一子節點之后

        const box = document.querySelector('.box');
        // 新建節點
        const p = document.createElement('p');
        p.innerHTML = 'this is p';
        // 插入節點
        box.appendChild(p);
        
      • insertBefore

        target.insertBefore(newChild,existingChild)

        newChild作為target的子節點插入到existingChild節點之前

        existingChild為可選項引數,當為null時其效果與appendChild一樣

        const box = document.querySelector('.box');
        const ul = document.querySelector('ul');
        const p = document.createElement('p');
        p.innerHTML = 'hello world';
        // box為父盒子 p為新增元素 ul為已經存在的元素
        box.insertBefore(p,ul)
        
    • 移動節點

      如果元素已經存在,使用insertBefore或者appendChild即可移動元素,

    • 獲取子元素或者父元素

      功能獲取節點獲取純元素
      獲取父節點parentElementparentNode
      獲取上一個節點(元素)previousSiblingpreviousElementSibling
      獲取下一個節點(元素)nextSiblingnextElementSibling
      獲取第一個節點(元素)firstChildfirstElementChild
      獲取最后一個節點(元素)lastChildlastElementChild
      獲取子節點(元素)childNodeschildren
    • 洗掉子元素:

      const box = document.querySelector('.box');
      const ul = document.querySelector('ul');
      box.removeChild(ul);
      
  • DOM 性能

    • Dom操作非常昂貴,避免頻繁的DOM操作

    • 對DOM查詢做快取

      image-20210912195331814

    • 將頻繁操作改為一次性操作

      const list = document.querySelector('ul');
      // 創建一個檔案片段,還沒有插入到檔案片段中
      const frag = document.createDocumentFragment();
      for(let i = 0; i<10;i++){
          const li = document.createElement('li');
          li.innerHTML = `list item ${i}`;
          // 將li標簽插入到檔案片段中
          frag.appendChild(li);
      }
      list.appendChild(frag);
      

題目

  1. DOM 是哪種資料結構?

    檔案物件模型(Document Object Model),簡稱 DOM,將所有頁面內容表示為可以修改的物件,DOM 將 HTML 表示為標簽的樹形結構,(樹)

  2. DOM 操作的常用API?

  3. attributeproperty 的區別?

    • attribute是HTML標簽上的特性,它的值只能夠是字串;修改標簽的屬性,會改變html結構,
    • property是DOM中的屬性,是JavaScript里的物件;修改物件屬性,不會體現到html結構中,
    • 兩者都可能引起DOM重新渲染,
  4. 一次性插入多個 DOM 節點,考慮性能

    const list = document.querySelector('ul');
    // 創建一個檔案片段,還沒有插入到檔案片段中
    const frag = document.createDocumentFragment();
    for(let i = 0; i<10;i++){
        const li = document.createElement('li');
        li.innerHTML = `list item ${i}`;
        // 將li標簽插入到檔案片段中
        frag.appendChild(li);
    }
    list.appendChild(frag);
    

BOM 操作

前置知識

  • navigator

    navigator 物件提供了有關瀏覽器和作業系統的背景資訊,navigator 有許多屬性,但是最廣為人知的兩個屬性是:navigator.userAgent — 關于當前瀏覽器,navigator.platform — 關于平臺(可以幫助區分 Windows/Linux/Mac 等),

    console.log(navigator.userAgent);
    // Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.63 Safari/537.36
    console.log(navigator.platform);
    // Win32
    
  • location

    // 在resume.jiaqicoder.com測驗
    location.href //'https://resume.jiaqicoder.com/#about'
    location.protocol //'https:'
    location.host //'resume.jiaqicoder.com'
    location.search //'?a=100&b=200'
    location.hash //'#about'
    location.pathname // '/'
    
  • history

    history.back(); // history.go(-1);
    history.forward();//history.go(1);
    

題目

  1. 如何識別瀏覽器的型別?
  2. 分析拆解url各個部分?

事件

前置知識

  • 事件系結

    const button = document.querySelector('button');
    // 通用的事件系結函式
    
    function bindEvent(elem,type,fn){
        elem.addEventListener(type,fn);
    }
    bindEvent(button,'click',(e)=>{
        e.preventDefault();
        console.log(e.target);
    })
    
  • 事件冒泡

    event.stopPropagation();阻止事件冒泡,

    event.stopImmediatePropagation(); 阻止事件冒泡并且阻止該元素之后的相同事件型別的監聽器觸發,

  • 事件代理

    <div class="box">
        <a href="#">1</a>
        <a href="#">2</a>
        <a href="#">3</a>
        <a href="#">4</a>
        <button>加載更多...</button>
    </div>
    <script>
        const box = document.querySelector('.box');
        box.addEventListener('click',e=>{
            e.preventDefault();
            if(e.target.nodeName= 'A'){
                console.log(e.target.innerHTML);  
            }
        })
    </script>
    

題目

  1. 撰寫一個通用的事件監聽函式

    <div class="box">
        <a href="#">1</a>
        <a href="#">2</a>
        <a href="#">3</a>
        <a href="#">4</a>
        <button>加載更多...</button>
    </div>
    <script>
    
        // elem:添加事件監聽的元素 type 事件監聽的型別
        // seletor:被事件代理的元素(可選)fn:觸發監聽后執行的回呼函式
        function bindEvent(elem, type, selector, fn) {
            if (fn == undefined) {
                // 說明是三個引數的這種情況 selector的值為傳入的fn
                // 交換fn和selector的值
                [fn, selector] = [selector, fn];
                console.log(3);
            }
            elem.addEventListener(type, e => {
                if (selector) {
                    // 需要被代理
                    // matches它檢查 elem 是否與給定的 CSS 選擇器匹配,它回傳 true 或 false,
                    if (e.target.matches(selector)) {
    
                        fn.call(e.target, e); // 讓this指向觸發的元素
                    }
    
                } else {
                    // 普通系結
                    fn.call(e.target, e);
                }
            })
        }
        const box = document.querySelector('.box');
        bindEvent(box, 'click', 'a', function (e) {
            e.preventDefault();
            console.log(this.innerHTML) //因為要使用this此時無法使用箭頭函式
        })
    </script> 
    
  2. 描述事件冒泡的流程

    事件冒泡基于DOM樹形結構,會順著觸發元素往上冒泡,

  3. 無線下拉的圖片串列,如何監聽每個圖片的點擊

    • 通過事件代理
    • 用e.target 獲取觸發元素
    • 用matches來判斷是否為觸發元素

ajax

前置知識

  • fetch

    fetch('https://reqres.in/api/users/',{
        method:'POST',
        headers:{
            'Content-Type':'applicaton/json'
        },
        body:JSON.stringify(
            {
            name:'User 21'
        }
        )
    }).then(res=>{
        return res.json();
    }).then(data=>{
        console.log(data);
    })
    
  • XMLHttpRequest

    // get 請求
    const xhr = new XMLHttpRequest();
    xhr.open('GET', './0.data.json', true); //代表異步
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {
            if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
                // console.log(xhr.responseText);
                // 決議為json格式
                console.log(JSON.parse(xhr.responseText))
            }
        }
    }
    xhr.send(null);
    
    // send 請求
    const xhr = new XMLHttpRequest();
    xhr.open('POST','./0.data.json',true);
    xhr.onreadystatechange = function(){
      if(xhr.readyState === 4){
        if(xhr.status >= 200 &&xhr.status<300 ||xhr.status===304){
          console.log(xhr.responseText);
        }
      }
    }  
    const postData ={
      userName:'zhangsan',
      age:32
    };
    xhr.send(JSON.stringify(postData));
    
    • xhr.readyState

      • 0 - (未初始化) 還沒有呼叫send()方法
      • 1 - (載入)已經呼叫send()方法,正在發送請求
      • 2 - (載入完成)send()方法,已經接收到全部回應內容
      • 3 - (互動)正在決議回應內容
      • 4 - (完成) 回應內容決議完成,可以在客戶端呼叫
    • xhr.status

      • 2xx - 表示成功處理請求 如200
      • 3xx - 需要重新定向,瀏覽器直接跳轉,如301,302,304
      • 4xx - 客戶端請求錯誤,如404,403
      • 5xx - 服務器端錯誤
  • 同源策略

    • ajax請求時,瀏覽器要求當前網頁必須和server端同源

    • 同源:協議、域名、埠,三者必須一致

    • 加載圖片、css、js可以無視同源策略

      • <img src=''/> 可以用于統計打點,使用第三方統計服務
      • <link/> <script/> 可以使用CDN,CDN一般都是外域
      • <script> 可以實作 JSONP
  • 跨域

    • 所有的跨域,都必須經過server端運行和配合
    • 未經server端運行就實作跨域,說明瀏覽器有漏洞,危險信號
  • JSONP

    <script> 可以繞過跨域限制,服務器可以任意動態拼接資料回傳,所以,<script> 就可以獲得跨域的資料,只要服務端愿意回傳,

    <script>
        // 在 這個頁面http://127.0.0.1:5500/24.jsonp.html
        window.callback = function (data) {
            console.log(data);
        }
    </script>
    <!-- 訪問不同埠的服務器的資料 -->
    <!-- 該服務器的回傳結果為callback({name:'zhangsan'}) -->
    <script src="http://localhost/24.jsonp.js"></script>
    
    
    <!--或者說這樣寫-->
    <script>
        const jsonp = document.createElement('script');
        jsonp.src ='http://localhost/24.jsonp.js'
        document.body.appendChild(jsonp);
        const callback = function (data) {
            console.log(data);
        }
    </script>
    
  • 服務器設定header

    const express = require('express')
    const bodyParser = require('body-parser')
    
    const app = express()
    // 處理引數
    app.use(bodyParser.json());
    app.use(bodyParser.urlencoded({ extended: false }));
    
    // 設定允許跨域訪問該服務
    app.all('*', function (req, res, next) {
      res.header("Access-Control-Allow-Origin", "*");
      res.header('Access-Control-Allow-Methods', 'PUT, GET, POST, DELETE, OPTIONS');
      res.header("Access-Control-Allow-Headers", "X-Requested-With");
      res.header('Access-Control-Allow-Headers', 'Content-Type');
      next();
    });
    
    // 啟動監聽
    app.listen(3000, () => {
      console.log('running...')
    })
    

題目

  1. 手寫一個簡易的ajax

    function ajax(url) {
        const p = new Promise((resolve, reject) => {
            const xhr = new XMLHttpRequest();
            xhr.open('GET', url, true);
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                    if (xhr.status > 199 && xhr.status < 300 || xhr.status === 304) {
                        resolve(xhr.responseText);
                    } else {
                        reject('someting went wrong');
                    }
                }
            }
            xhr.send(null);
    
        });
    
        return p;
    }
    ajax('https://reqres.in/api/users/').then(data => console.log(JSON.parse(data))).catch(err => console.log(err));
    
  2. 跨域的常見方式

  • jsonp

  • cors

存盤

前置知識

  • cookie

    cookie全稱為HTTP cookie,簡稱cookie,是瀏覽器存盤資料的一種方式,cookie是本地存盤,一般會自動隨著瀏覽器發送請求時發送到服務器端,本身用于瀏覽器和服務器通訊,一般最大為4kb,

    document.cookie = 'username=zs';
    document.cookie = `user=${encodeURIComponent('張三')}`; //中文需要用到encodeURIComponent
    // 告知失效時間 如果不設定,默認會是session
    document.cookie = `hobby=sleep;expires=${new Date('2022-09-09')}`
    // 還可以設定domain path 當domain、path以及name的值完全相同時,下一個cookie才會覆寫上一個
    document.cookie = `hobby=eat;path='/info';domain='jiaqicoder.com;max-age=100 `; 
    // 該cookie只能在 jiaqicoder.com/info下讀寫 且100s后cookie被洗掉
    // 一個一個的設定但是會一起列印 
    console.log(document.cookie); //username=zs; user=%E5%BC%A0%E4%B8%89;  hobby=sleep
    
  • localStorage和sessionStorage

    localStorage也是一種瀏覽器存盤資料的方式(本地存盤),它只是存盤在本地,不會發送到服務器端,而cookie會隨著瀏覽器向服務器發送請求時發送到服務器,localStorage 中的鍵值對總是以字串的形式存盤,

    localStorage.setItem('name','jiaqii');
    localStorage.setItem('age',332);
    console.log(localStorage.getItem('age'));
    localStorage.removeItem('age');
    localStorage.clear();//清空所有的
    

    localStorage是持久化本地存盤,除非手動清除(比如通過JavaScript洗掉,或者清除瀏覽器快取),否則資料是永遠不會過期的,

    但是當會話結束(比如關閉瀏覽器)的時候, sessionStorage中的資料會被清空,它的方法和localStorage完全一樣,

題目

  1. 描述cookielocalStoragesessionStorage的區別

HTTP

前置知識

  • http狀態碼

    • 狀態碼分類
      • 1xx 服務器收到請求
      • 2xx 請求成功
      • 3xx 重定向
      • 4xx 客戶端錯誤
      • 5xx 服務端錯誤
    • 常見的狀態碼
      • 200 成功
      • 301 永久重定向 (配合location,瀏覽器自動處理)
      • 302 臨時重定向 (配合location,瀏覽器自動處理)
      • 304 資源未被修改,從快取中讀取資料
      • 403 沒有權限
      • 404 資源不存在
      • 500 服務器錯誤
      • 504 網關超時
  • http方法

    • 傳統的 methods

      • get 獲取服務器的資料
      • post 向服務器提交資料
    • 現在的methods

      • get 獲取資料

      • post 新建資料

      • patch/put 更新資料

      • delete 洗掉資料

        這些方法只是一個規范,比如get可以用來新建資料,但是盡量遵守規范

    • Restful API

      • 傳統的api設計:把每個url當做一個功能

      • restful api設計:把每個url當做一個唯一的資源(標識)

      • 如何將url設定為資源?

        • 盡量不用url引數

          傳統的api設計:/api/list?pageIndex=2

          restful api設計:/api/list/2

        • 用 method 表示操作型別

          傳統的api:

          • post請求 /api/create-blog
          • put請求 /api/update-blog?id=100
          • get請求 /api/get-blog?id=100

          restful api:用method 表示操作型別

          • post請求 /api/blog 如axios.post('/api/blog',{name:12,age:18})
          • put請求 /api/blog/100 如axios.put('/api/blog/100',{age:12})
          • get請求 /api/blog/100 如axio.get('/api/blog/100')
  • http headers

    • 常見的request headers
      • Accept 瀏覽器可接收的資料格式
      • Accept-Encoding 瀏覽器可接收的壓縮演算法,如gzip
      • Accept-Language 瀏覽器可接收的語言,如zh-CN
      • Connection: keep-alive 一次TCP連接重復使用
      • cookie 同域一般瀏覽器會自動發送cookie
      • Host 域名
      • UserAgent 瀏覽器資訊
      • Content-Type 發送資料的格式,如果application/json
    • 常見的response headers
      • Content-Type 回傳資料的格式,如果application/json
      • Content-Length 回傳的資料的大小
      • Content-Encoding 回傳資料的壓縮演算法,如gzip
      • Set-Cookie 設定cookie
    • 快取相關的headers:
      • Cache-Control:Expires
      • Last-Modified:If-Modified-Since
      • Etag:If-None-Match
  • http 快取

    https://juejin.cn/post/6844903763665240072

    • 關于快取的介紹

      • 什么是快取?

      • 為什么需要快取?

        部分資料可以直接從快取中讀取,減少網路請求的資料,加快頁面加載速度,

    • http快取策略(強制快取 + 協商快取)

      • 強制快取

        簡單粗暴,如果資源沒過期,就取快取,如果過期了,則請求服務器,

        image-20210914161638760

        Cache-Control 在Response-Headers中,控制強制快取的邏輯,

        Cache-Control 的幾個取值含義:

        private: 僅瀏覽器可以快取

        public: 瀏覽器和代理服務器都可以快取(對于private和public,前端可以認為一樣,不用深究)

        max-age=xxx 過期時間(重要)

        no-cache 不進行強快取(重要)

        no-store 不強快取,也不協商快取,基本不用,快取越多才越好呢

        注意:規則可以同時多個,

      • 協商快取

        觸發條件:

        1. Cache-Control 的值為 no-cache (不強快取)
        2. 或者 max-age 過期了 (強快取,但總有過期的時候)

        也就是說,不管怎樣,都可能最后要進行協商快取(no-store除外)

        服務器端判斷客戶端資源,是否和服務端資源一樣,如果判斷一直則回傳304,否則回傳200和最新的資源,

        協商快取

        response header里面的設定

        etag: '5c20abbd-e2e8'
        last-modified: Mon, 24 Dec 2018 09:49:49 GMT
        

        etag:每個檔案有一個,改動檔案了就變了,就是個檔案hash,每個檔案唯一,

        last-modified:檔案的修改時間,精確到秒,

        也就是說,每次請求回傳來 response header 中的 etaglast-modified,在下次請求時在 request header 就把這兩個帶上,服務端把你帶過來的標識進行對比,然后判斷資源是否更改了,如果更改就直接回傳新的資源,和更新對應的 response header 的標識 etaglast-modified ,如果資源沒有變,那就不變 etaglast-modified,這時候對客戶端來說,每次請求都是要進行協商快取了,即:發請求–>看資源是否過期–>過期–>請求服務器–>服務器對比資源是否真的過期–>沒過期–>回傳304狀態碼–>客戶端用快取的老資源,

        這就是一條完整的協商快取的程序,

    • 重繪操作方式,對快取的影響

題目

  1. http 常見的狀態碼有哪些?

  2. http 常見的header有哪些?

  3. 什么是Restful Api?

  4. 描述http的快取機制?(重要

手寫

防抖

  • 監聽輸入框,文字變化后會觸發change事件
  • 直接用keyup事件,則會頻繁觸發change事件
  • 防抖:用戶輸入結束或暫停時,才會觸發change事件

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/303035.html

標籤:java

上一篇:javaSE初階 String

下一篇:簡單圖書管理系統練習-Java+Mysql

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more