前端一些須要掌握的簡單知識點

快速排序算法

'這應該是最簡單的快速排序實現,什麼是快速排序呢?'

'快速排序(Quicksort)是對冒泡排序的一種改進。
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:
經過一趟排序將要排序的數據分割成獨立的兩部分,其中一
部分的全部數據都比另一部分的全部數據都要小,而後再
按此方法對這兩部分數據分別進行快速排序,整個排序過程
能夠遞歸進行,以此達到整個數據變成有序序列。'
function quickSort(arr) {
        if (arr.length <= 1) { return arr; }
        var left = [],
            right = [],
            baseDot = Math.round(arr.length / 2)
            base = arr.splice(baseDot, 1)[0];

        for (var i = 0; i < arr.length; i++) {
            if (arr[i] < base) {
                left.push(arr[i])
            } else {
                right.push(arr[i])
            }
        }
        return quickSort(left).concat([base], quickSort(right));
    }
    let arr = [5, 3, 4, 12];
    
    const newarr = quickSort(arr);
    console.log(newarr);
    
    
    '每次遞歸調用,都會直到數組中只有一個數字爲止,而後
    執行上下文棧出棧,返回上一個執行上下文循環遞歸,拼接數組'

冒泡排序算法

'什麼是冒泡排序算法?'

'冒泡排序(Bubble Sort),是一種計算機科學領域的較簡單的排序算法。
它重複地走訪過要排序的元素列,依次比較兩個相鄰的元素,若是他們的順
序(如從大到小、首字母從A到Z)錯誤就把他們交換過來。走訪元素的工做
是重複地進行直到沒有相鄰元素須要交換,也就是說該元素已經排序完成。
這個算法的名字由來是由於越大的元素會經由交換慢慢「浮」到數列的頂端
(升序或降序排列),就如同碳酸飲料中二氧化碳的氣泡最終會上浮到頂端
同樣,故名「冒泡排序」。'


    bubbleSortSoul1 = (arr = []) => {
        let count = 0;
        // i爲輪數(因i從0開始 即i<arr.length-1)
        for (let i = 0; i < arr.length - 1; i++) {
            count++;
            // 第i輪僅需比較length-1-i次
            for (let j = 0; j < arr.length - 1 - i; j++) {
                // 這裏能不能寫成arr[j-1]>arr[j]? 若是有這種特殊癖好 那麼j就從1開始吧,而後j<arr.length-i
                if (arr[j] > arr[j + 1]) {
                    let temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }
        console.log(`bubbleSortSoul1排序完成用了${count}輪`);
        return arr;
    }

深度克隆

'爲何咱們須要深度克隆?並且面試必問?'php

'由於引用數據類型存儲在堆空間中,當兩個變量同時指向同一個地址時,
只要一個改變,那麼另一個也會跟着變,咱們的原意是想一個改變,另
一個不變,那麼就須要從新開拓一個堆空間出來,因此就有了深度克隆。'

'第一種方法(只適用於基礎類型)'

const newObj = JSON.parse(JSON.stringify(oldObj));


'第二種方法,涵蓋全部的類型'

const getType = (obj)=> {
    var toString = Object.prototype.toString;
    var map = {
        '[object Boolean]'  : 'boolean', 
        '[object Number]'   : 'number', 
        '[object String]'   : 'string', 
        '[object Function]' : 'function', 
        '[object Array]'    : 'array', 
        '[object Date]'     : 'date', 
        '[object RegExp]'   : 'regExp', 
        '[object Undefined]': 'undefined',
        '[object Null]'     : 'null', 
        '[object Object]'   : 'object',
        '[object Symbol]'   : 'symbol'
    };
    if(obj instanceof Element) {//由於對不一樣標籤,toString會返回對應不一樣標籤的構造函數
        return 'element';
    }
    return map[toString.call(obj)];
}

const getRegExp = re => {
  var flags = '';
  if (re.global) flags += 'g';
  if (re.ignoreCase) flags += 'i';
  if (re.multiline) flags += 'm';
  return flags;
};

/**
* deep clone
* @param  {[type]} parent object 須要進行克隆的對象
* @return {[type]}        深克隆後的對象
*/
const deepClone = oldObj => {
  // 維護兩個儲存循環引用的數組
  const oldObjArr = [];
  const newObjArr = [];

  const clone = oldObj => { 
      
    let newObj, proto;

    const type = getType(oldObj);

    switch(type){
        case 'boolean':
        case 'number':
        case 'string':
        case 'null':
        case 'undefined':
        case 'function':{
            return oldObj;
            break;
        }
        case 'symbol':{
            return Symbol(Symbol.keyFor(oldObj).toString());
            break;
        }
        case 'array':{
            newObj = [];
            break;
        }
        case 'regExp':{
            newObj = new RegExp(oldObj.source, getRegExp(oldObj));
            if (oldObj.lastIndex) newObj.lastIndex = oldObj.lastIndex;
            break;
        }
        case 'date':{
            newObj = new Date(oldObj.getTime());            
            break;
        }
        //case 'obj':
        default:{
            // 處理對象原型
            proto = Object.getPrototypeOf(oldObj);
            // 利用Object.create切斷原型鏈
            newObj = Object.create(proto);
            break;
        }
   }

   // 處理循環引用
   const index = oldObjArr.indexOf(oldObj);
   if (index != -1) {// 若是父數組存在本對象,說明以前已經被引用過,直接返回此對象    
     return newObjArr[index];
   }

   oldObjArr.push(oldObj);
   newObjArr.push(newObj);
  /*數組和對象均可以用forin語句,雖然數組使用forin會有一個問題(具體看最下面)。
  可是這裏不會影響,因此這麼用 
  */
   for (let i in oldObj) {// 遞歸     
     newObj[i] = clone(oldObj[i]);
   }

   return newObj;
 };


 return clone(oldObj);
}

/*
測試成功
*/
function person(pname) {
    this.name = pname;
}
  
const Messi = new person('Messi');
  
function say() {
    console.log('hi');
};
  
const oldObj = {
    a: say,
    b: new Array(1),
    c: new RegExp('ab+c', 'i'),
    d: Messi
  };
  
  const newObj = deepClone(oldObj);
  
  console.log(newObj.a, oldObj.a); //[Function: say] [Function: say]
  console.log(newObj.b[0], oldObj.b[0]); // undefined undefined
  console.log(newObj.c, oldObj.c); // /ab+c/i /ab+c/i
  console.log(newObj.d.constructor, oldObj.d.constructor); // [Function: person][Function: person]
  
 '全部的類型均可以被克隆,完美版'
  • 判斷對象是否一個數組的條件是:
  • Array.isArray(),這個在安卓的瀏覽器中兼容性通常
  • arr instanceof Array 這個兼容性不錯,可使用
  • 還有就是arr. _proto_ .consturctor == Array 這個也是能夠的 兼容性應該還不錯
  • Object.prototype.tostring.call(arr) == [object Array] 這個也能夠

如何提取用最原生的方法提取一個對象內部全部屬性的值,而且放在不一樣數組中?

  • 我的認爲第一題和第二題結合起來,能夠用來處理先後臺交互的數據,若是格式很複雜,也可使用這二者的模式結合,而後把他們分別提取出來進行操做。
const obj = {
        name: 'json',
        age: 1,
        friend: '夢露',
        info: {
            name: 'Aron',
            age: 2,
            friend: '傑西卡',
            info: {
                name: 'rose',
                age: 3,
                friend: '黴黴',
                info: {
                    name: 'jerry',
                    age: 4,
                    friend: '比伯',
                    info: {
                        name: 'damu',
                        age: 5,
                        friend: 'XJ',
                    },
                },
            },
        }
    }
    let namearr, agearr, friendarr;
    namearr = [];
    agearr = [];
    friendarr = [];
    check(obj);
    function check(obj) {
        const items = Object.getOwnPropertyNames(obj)
        items.forEach(function (item) {
            if (Object.prototype.toString.call(obj[item]) == '[object Object]') {
                check(obj[item]);
            } else {
                if (item.toString() === 'name') {
                    namearr.push(obj[item])
                } else if (item.toString() === 'age') {
                    agearr.push(obj[item])
                } else if (item.toString() === 'friend') {
                    friendarr.push(obj[item])
                }
            }
        })
    }
    /* 這種方法也是同樣的效果  使用for in循環代替的Object.getOwnPropertyNames(obj)方法
    function check(obj) {
        for (var item in obj) {
            if (Object.prototype.toString.call(obj[item]) == '[object Object]') {
                check(obj[item]);
            } else {
                if (item == 'name') {
                    namearr.push(obj[item])
                }
                else if (item == 'age') {
                    agearr.push(obj[item])
                }
                else if (item == 'friend') {
                    friendarr.push(obj[item])
                }
            }
        }
    }*/
    console.log(`namearr:${namearr}`)
    console.log(`agearr:${agearr}`)
    console.log(`friendarr:${friendarr}`)

請手寫一個數組由小到大排序並且去重,不得使用高階函數

let arr = [1, 1, 2, 2, 5, 5, 'a', 'a', '3', '3']
    arr = arr.sort();
    let realarr = [];
    for (let i = 0; i < arr.length; i++) { 
        if (i == 0) {
            realarr.push(arr[i])
        } else if (i !== 0 && arr[i] !== arr[i - 1]) {
            realarr.push(arr[i])
        }
    }
    console.log(realarr)

### 如何將一個對象深度凍結?html

跟上面的數組面試題同樣,利用了執行上下文棧,先進的後出,最早凍結最深層裏面的那個屬性,
再依次返回上一層繼續凍結
var obj = {
       name:"王寶強",
       age:18,
       wife:{
           name:"陳羽凡",
           age:17,
           son:{
               name:"賈乃亮",
               age:48,
               girlFriend:{
                   name:"吳秀波",
                   age:50,
                   zuo:function () {
                       console.log("翻舊帳")
                   },
                   foods:["棉花糖","粉色的棉花糖","各類棉花糖",{a:"a"}]
               }
           }
       }
   };



   Object.prototype.deepFreeze = function () {
       var keys = Object.getOwnPropertyNames(this);

       var that = this;
       keys.forEach(function (key) {
           var val = that[key];
           if(Object.prototype.toString.call(val) === "[object Object]" || Object.prototype.toString.call(val) === "[object Array]"){
               val.deepFreeze()
           }
       });
       return Object.freeze(this)
   }
   obj.deepFreeze()

## 請使用定時器和canvas寫一個隨機生成多個彩色泡前端

<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>Document</title>
   <style>
       * {
           margin: 0;
           padding: 0;
       }

       body,
       html {
           width: 100%;
           height: 100%;
           overflow: hidden;
       }

       canvas {
           position: absolute;
           top: 0;
           left: 0;
           bottom: 0;
           right: 0;
           margin: auto;
           border: 1px solid;
           
           background: white;
       }
   </style>
</head>

<body>
   <canvas width="400" height="400"></canvas>
</body>

<script>
   window.onload = function () {
       var canvasnode = document.querySelector("canvas");
       var arr=[];
       
       if (canvasnode.getContext) {
           var ctx = canvasnode.getContext("2d");
            
       }
       setInterval(function(){
           console.log(arr)
           ctx.clearRect(0,0,canvasnode.width,canvasnode.height)
           arr.forEach(function(item,index){
               item.r++;
               
                   item.opa-=0.01;
                   if(item.opa<=0){
                       arr.splice(index,1)
                   }
           } )

           arr.forEach(function(item){
           ctx.save()
                   ctx.fillStyle="rgba("+item.red+","+item.green+","+item.blue+","+item.opa+")";
                   ctx.beginPath()
                   ctx.arc(item.x,item.y,item.r,0,2*Math.PI)
                   ctx.fill()
                   ctx.restore()
       } )
       } ,10)
      
       
       setInterval(function(){
           var obj={x:0,y:0,r:0,red:0,green:0,blue:0,opa:0};
           obj.x=Math.random()*400;
           obj.y=Math.random()*400;
           obj.r=10;
           obj.opa=1;
           obj.red =Math.round(Math.random()*255);
           obj.green =Math.round(Math.random()*255);
           obj.blue =Math.round(Math.random()*255);
           arr.push(obj);
          
       },100 )
       
   }


</script>

</html>

請本身定義一個DOM節點的R操做,以此做爲queryselector在IE8如下的polifill。

(function(w){
    w.app = {};
    w.app.getElementByClassName=function(className){
        var allnode=document.getElementsByTagName("*");
        console.log(allnode)
        var arr=[];
        for(var i=0;i<allnode.length;i++){
            var newclass=" "+allnode[i].className+" ";
            var reg=new RegExp("\\s+"+className+"\\s+","i"); 
            if(reg.test(newclass)){
                arr.push(allnode[i]);
            }
             
        }
        return arr
    } 
    
}(window)

請你手寫一個ajax原生javaScript請求?

'因爲ajax通常用於比較舊的技術,這裏不適用ES6語法'

var xhr = new XMLHttpRuest();
 xhr.onreadystatechange = function () {
              if (xhr.readyState == 0) {
                  //xhr對象建立好了 初始化狀態
                  console.log(0)
              }
              if (xhr.readyState == 1) {
                  //表明xhr.send方法還未調用(還未發送請求),還能夠設置請求頭相關信息
                  console.log(1)
              }
              if (xhr.readyState == 2) {
                  //此時send方法被調用了  響應頭和首行已經回來了
                  console.log(xhr.getResponseHeader('etag'))
                  console.log(2)
              }
              if (xhr.readyState == 3) {
                  console.log(3)
              }
              if (xhr.readyState === 4 && xhr.status === 200) {
                  console.log(4)
                  console.log(xhr.responseText);
              }
          }
          xhr.open('GET', 'http://localhost:3000/ajax?username=123&password=456');
          // xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
          //  xhr.send('username=123&password=456');
          xhr.send()
      }*/
    '//上面是原生的ajax寫法,下面是jQuery中的兩種ajax寫法'
   ' 1. 原生jQuery寫法 '
     $('#btn').click(function () {
          $.ajax({
              url: 'http://localhost:3000/ajax',
              data: 'username=jack&password=123',
              method: 'POST',
              success: function (data) {
                 console.log(data)
              },
              error: function (error) {
                  console.log(error)
              }
          })
    

   '2.簡寫'
    
     $.post('http://localhost:3000/ajax', 'username=rose&age=12', (data) => {
            console.log(data)
        })
    '//若是是get請求直接上面改爲get就能夠了,data是服務器響應回來的數據'

而後這邊給一下服務器 Node.js的express代碼 響應上面的ajax請求的

const express = require('express');
const app = express();
app.use(express.static('public'))
app.use(express.urlencoded({ extended: true }));
app.get('/ajax', (req, res) => {
    console.log(req.query)
    res.send('這是ajax的get請求')
})
app.post('/ajax', (req, res) => {
    res.send('這是ajax的post請求')
     console.log(req.body)
})
app.listen(3000, err => {
    if (!err) {
        console.log('端口監聽成功');
    } else {
        console.log('端口監聽失敗' + err);
    }
})

如何使用原生javaScript方法提取一個多重對象的值,而且塞到不一樣對應的數組中?

'這裏使用了遞歸,還有Object原型上的方法,執行上下文棧先進後出的知識。'
    const obj = {
        name: 'json',
        age: 1,
        friend: '夢露',
        info: {
            name: 'Aron',
            age: 2,
            friend: '傑西卡',
            info: {
                name: 'rose',
                age: 3,
                friend: '黴黴',
                info: {
                    name: 'jerry',
                    age: 4,
                    friend: '比伯',
                    info: {
                        name: 'damu',
                        age: 5,
                        friend: 'XJ',
                    },
                },
            },
        }
    }
    let namearr, agearr, friendarr;
    namearr = [];
    agearr = [];
    friendarr = [];
    check(obj);
    /*  function check(obj) {
          const items = Object.getOwnPropertyNames(obj)
          items.forEach(function (item) {
              if (Object.prototype.toString.call(obj[item]) == '[object Object]') {
                  check(obj[item]);
              } else {
                  if (item.toString() === 'name') {
                      namearr.push(obj[item])
                  } else if (item.toString() === 'age') {
                      agearr.push(obj[item])
                  } else if (item.toString() === 'friend') {
                      friendarr.push(obj[item])
                  }
              }
          })
      }*/
    function check(obj) {
        for (var item in obj) {
            if (Object.prototype.toString.call(obj[item]) == '[object Object]') {
                check(obj[item]);
            } else {
                if (item == 'name') {
                    namearr.push(obj[item])
                }
                else if (item == 'age') {
                    agearr.push(obj[item])
                }
                else if (item == 'friend') {
                    friendarr.push(obj[item])
                }
            }
        }
    }
    console.log(`namearr:${namearr}`)
    console.log(`namearr:${agearr}`)
    console.log(`namearr:${friendarr}`)

## 請手寫一個jsonp和cors 解決跨域問題的代碼 ?java

'jsonp'
 document.getElementById('btn').onclick = function () {
   /*
     1. jsonp
       - 特色:
         1. 利用script標籤自然跨域跨域的特性解決跨域的, 民間推出的
         2. 兼容性極好
    */
   //建立一個script標籤
   const script = document.createElement('script');
   //設置了響應成功的回調函數
   window.jsoncallback = function (data) {
     console.log(data);
   }
   //設置script的src屬性, 向指定服務器發送請求
   script.src = 'http://localhost:3000/?callback=jsoncallback';
   //添加到body中生效
   document.body.appendChild(script);
 }
 
 
 ------
 
 'cors的解決方法:在Node.js的服務器代碼中設置一個響應頭'
   
   

app.get('/cors', (req, res) => {
 /*
   1. cors
     特色:
       - 官方推出解決跨域的方案,使用起來及其簡單,只需在服務器設置一個響應頭
       - 兼容性較差
  */
 //設置響應頭
 res.set('access-control-allow-origin', '*');  //容許全部網址跨域

瀏覽器的輪詢機制請簡述

'1.瀏覽器的事件輪詢機制 
瀏覽器中對於js依靠js引擎實現,js引擎是單線程,不像java,php這些能夠是多線程,高併發。若是要說到瀏覽器的輪詢機制,那麼咱們首先要說的
就是單線程的js引擎,前端的核心編程思惟模式是異步編程,不管是頁面效果、先後端的數據交互,都是以異步爲核心,每一個須要異步的場景,
每每伴隨着回調函數去執行,而單線程的JS引擎是沒法自身作這麼多工做,還須要異步線程。

1.每當JS引擎解析代碼時遇到異步代碼時,交給異步線程,繼續往下解析代碼。
2.異步線程處理這些異步代碼時,一旦他們的所對應的回調函數達到執行條件便會塞進異步隊列中,等待JS引擎的輪詢。
3.JS引擎會在解析完下面的全部代碼後,再去輪詢異步隊列,從左到右,依次執行,這也是說爲何定時器的時間不許確的緣由,在JS
解析代碼時,若是遇到下面代碼特別多的時候,那麼它就沒時間去輪詢異步隊列的代碼。

瀏覽器中的輪詢機制有一個特殊的 requestAnimationFrame(callbackname),它所對應的回調函數,是在瀏覽器下一次重繪重排時執行,它是一個宏任務,有待考證
,目前看只要觸發重繪重排就會調用回調函數,能夠避免掉幀,優化性能,減小重繪重排次數,即便一個空白頁面,它也會重繪重排,因此只要運用好,
它是徹底能夠替代定時器,還可使用cancelAnimationFrame(callbackname)清除。
'

Node.js中的事件輪詢機制 Event loop

'Node.js的事件輪詢機制外還有同步代碼,微任務,
要想完全弄懂Node的代碼執行,得結合下面的微任
務一塊兒學習。'

'1.執行已經到時間的setTimeout 和 setInterval 
2.執行延遲到一個循環迭代的i/o回調
3.系統內部的 idle prepare等
4.poll   輪詢回調隊列,依次取出,同步執行,與JS的異步隊列執行有點相像  直到回調隊列爲空 或者系統奔潰了  若是回調隊列沒有內容,那麼看
以前是否設置過setImmadiate(),若是有就去下一個階段,若是沒有,就在當前等待新的回調函數。  若是定時器的時間到了,那麼也會去下一個階段 
5. setImmediate
6.關閉的回調函數 ,一些準備關閉的函數等.

Node.js的事件輪詢機制也能夠當作是單線程,由上往下執行,可是到了第6階段,又會返回第一階段,死循環。  '

什麼是微任務什麼是宏任務?

'想得太多反而很差,把每一個宏任務當作銀行排隊的老大爺,把微任務當作老大爺須要的業務,
可能他須要辦存款,理財,買記念幣等,櫃檯人員不幫老大爺辦完
他所須要的任務 -- 微任務,就不會切換到下一個老大爺 -- 宏任務, 可是編程的邏輯不
能徹底抽象成現實生活,
照這種說法,只能先有老大爺纔會有業務須要,
。但是在Node中,先執行的是微任務,只有微任務若是有多層,先執行最頂層,再往下依次執
行)執行完後才能去執行宏任務,微任務有兩種,一種是process.nextTick()
中的函數,一種是Promise.then()中的函數,只有他們執行完後,纔會去執行宏任務:setTim
eout ,setIneterval,setImmadie。(即執行完了微任務纔會遵循Node.js的輪詢機制去執行,
一切微任務優先)'
相關文章
相關標籤/搜索