前端面試錦集之基礎題總結

一、面試基礎題

  1. 作用域和值類型引用類型的傳遞,代碼如下所示:
<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>

	<body>
		<script type="text/javascript">
			//第1題 作用域
			var num1 = 55;
			var num2 = 66;//100

			function f1(num, num1) {
				// var num =55;
				// var num1 = 66;
				num = 100;//100
				num1 = 100;//100
				num2 = 100;//100
				console.log(num);//100
				console.log(num1);//100
				console.log(num2);//100
			}
			//  55    66
			f1(num1, num2);
			console.log(num1);//55
			console.log(num2);//100
			console.log(num);// 報錯

			//第2題  值類型和引用類型的傳遞
			function Person(name, age, salary) {
				this.name = name;
				this.age = age;
				this.salary = salary;
			}

			function f1(person) {
				//var person = p;
				person.name = "ls";
				person = new Person("aa", 18, 10);
			}

			var p = new Person("zs", 18, 1000);
			console.log(p.name);//zs
			f1(p);
			console.log(p.name);//ls
		</script>
	</body>

</html>
  1. 封裝函數進行字符串駝峯命名的轉換,代碼如下所示:
<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>

	<body>
		<script type="text/javascript">
			//已知有字符串foo='get-element-by-id',寫一個function將其轉化成駝峯表示法”getElementById”

			//自定義函數
			function toString(foo) {
//				var foo = 'get-element-by-id';
				//根據某個字符進行切割
				var arr = foo.split('-');
				//獲取每個元素中的第一個字符並轉換成大寫
				console.log(arr[1].charAt(0).toUpperCase() + arr[1].substr(1, arr[1].length - 1));
				for(var i = 1; i < arr.length; i++) {

					arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].substr(1, arr[i].length - 1)
				}
				//根據某個字符將數組轉成字符串
				return arr.join('');
			}
			
		 	console.log(toString('get-element-by-id'));
		</script>
	</body>

</html>
  1. 冒泡排序的實現,代碼如下所示:
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>

	<body>
		<script type="text/javascript">
			var arr = [32,4,67,82,21,11];
			
			///輪數
			for(var i = 0; i<arr.length-1;i++){
				//次數
				for(var j = 0;j<arr.length-1-i;j++){
					
					//判斷前一個大於後一個數時進行交換
					if(arr[j]>arr[j+1]){
						//藉助第三方變量交換兩個變量的值
						var temp = arr[j];
						arr[j] = arr[j+1];
						arr[j+1] = temp;
					}
				}
			}
			console.log(arr);
		</script>
	</body>
</html>
  1. 反轉數組,代碼如下所示:
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<script type="text/javascript">
			var arr = [1,2,3,4,5,6,7,8];
			for(var i = 0;i<arr.length/2;i++){
				//arr[0]    arr[arr.length-1-0];
				//arr[1]    arr[arr.length-1-1];
				//arr[2]    arr[arr.length-1-2];
				//arr[3]    arr[arr.length-1-3];
				
				//藉助第三方變量交換兩個變量的值
				var temp = arr[i];
				arr[i] = arr[arr.length-1-i];
				arr[arr.length-1-i] = temp;
			}
			console.log(arr);
		</script>
	</body>
</html>

  1. 去掉數組中重複性的數據,代碼如下所示:
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<script type="text/javascript">
			/*
			 * 1.創建一個新數組,把原數組中的第一個元素插入到新數組中
			 * 2.遍歷原數組中的每一個元素分別和新數組中的每一個元素進行比較
			 */
			//原數組
			var arr = [8,11,20,5,20,8,0,2,4,0,8];
			// 新數組
			var  t = [];//var  t = [8,11];
			t[0] = arr[0];
			//arr中的每個元素
			for(var i=0;i<arr.length;i++){
				//t中的每個元素
				for(var k = 0;k<t.length;k++){
					
					//當原數組中的值和新數組中的值相同的時候,就沒有必要再繼續比較了,跳出內循環
					if(t[k] == arr[i]){
						break;
					}
					//拿原數組中的某個元素比較到新數組中的最後一個元素還沒有重複
					if(k == t.length-1){
						//將數據插入新數組
						t.push(arr[i]);
					}
				}
			}
			console.log(t);
		</script>
	</body>
</html>

  1. 1 物理像素,有兩種方式,如下所示:
  • 第一種方式,代碼如下所示:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />
        <title></title>
        <style type="text/css">
            *{
                margin: 0;
                padding: 0;
            }
            #box{
                width: 8rem;
                height: 8rem;
                border: 1px solid #000000;
            }
        </style>
    </head>
    <body>
    <div id="box"></div>
    </body>
    <script type="text/javascript">
        var box = document.getElementById('box');
    
        //獲取設備像素比
        var dpr = window.devicePixelRatio;
        //比例
        var scale = 1/dpr;
    
        //獲取屏幕寬度 375
        var width = document.documentElement.clientWidth;
    
        //獲取meta標籤
        var metaNode = document.querySelector('meta[name="viewport"]')
        metaNode.setAttribute('content','width=device-width,initial-scale='+ scale +',user-scalable=no')
    
        //元素比例乘回來
        var htmlNode = document.querySelector('html');
        htmlNode.style.fontSize = width/16*dpr + 'px';
    
    </script>
    </html>
    
    
  • 第二種方式,代碼如下所示:

 <!DOCTYPE html>
   <html>
   <head>
       <meta charset="UTF-8">
       <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />
       <title></title>
       <style type="text/css">
           *{
               margin: 0;
               padding: 0;
           }
           #box{
               width: 200px;
               height: 200px;
               position: relative;
           }
           #box:after{
               content: '';
               position: absolute;
               left: 0;
               bottom: 0;
               width: 100%;
               height: 1px;
               background: #000000;
           }
           @media screen and ( -webkit-min-device-pixel-ratio:2 ) {
               #box:after{
                   transform: scaleY(0.5);
               }
           }
           @media screen and ( -webkit-min-device-pixel-ratio:3 ) {
               #box:after{
                   transform: scaleY(0.333333333333);
               }
           }
       </style>
   </head>
   <body>
   <div id="box"></div>
   </body>

</html>
  1. flex 元素水平垂直居中,如下所示:
  • 新版本的垂直居中,代碼如下:
 <!DOCTYPE html>
   <html lang="en">
   <head>
       <meta charset="UTF-8">
       <title>Title</title>
   
       <style type="text/css">
           * {
               margin: 0;
               padding: 0;
           }
   
           #wrap {
               width: 500px;
               height: 500px;
               background: grey;
   
               display: flex;
               justify-content: center;
               align-items: center;
           }
           #box{
               width: 200px;
               height: 200px;
               background: deeppink;
           }
       </style>
   </head>
   <body>
   <div id="wrap">
       <div id="box"></div>
   </div>
   </body>
   <script type="text/javascript">
       window.onload = function () {
           var box = document.getElementById('box');
   
   
       }
   </script>
</html>
  • 老版本的垂直居中,代碼如下:

     <!DOCTYPE html>
      <html lang="en">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
      
          <style type="text/css">
              * {
                  margin: 0;
                  padding: 0;
              }
      
              #wrap {
                  width: 500px;
                  height: 500px;
                  background: grey;
      
                  display: -webkit-box;
                  -webkit-box-pack: center;
                  -webkit-box-align: center;
              }
              #box{
                  width: 200px;
                  height: 200px;
                  background: deeppink;
              }
          </style>
      </head>
      <body>
      <div id="wrap">
          <div id="box"></div>
      </div>
      </body>
      <script type="text/javascript">
          window.onload = function () {
              var box = document.getElementById('box');
      
      
          }
      </script>
      </html>
    
  1. css 實現三角形,代碼如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
        }

        #box {
            width: 0px;
            height: 0px;

            border: 100px solid transparent;

            border-top-color: deeppink;
            border-left-color: deeppink;
            /*border-right-color: deeppink;*/
            /*border-bottom-color: deeppink;*/
        }
    </style>
</head>
<body>
<div id="box"></div>
</body>
<script type="text/javascript">
    window.onload = function () {
        var box = document.getElementById('box');


    }
</script>
</html>
  1. rem 適配,代碼如下所示:
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no" />
    <title></title>
    <style type="text/css">
        *{
            margin: 0;
            padding: 0;
        }
        #box{
            width: 8rem;
            height: 8rem;
            background: deeppink;
        }

    </style>
</head>
<body>
<div id="box"></div>
</body>
<script type="text/javascript">
    //獲取屏幕寬度
    var width = document.documentElement.clientWidth;

    //獲取html
    var htmlNode = document.querySelector('html');

    //設置html字體大小
    htmlNode.style.fontSize = width/16 + 'px';

</script>
</html>

  1. 背景圖片的距離,代碼如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
        }

        #box{
            width: 100px;
            height: 200px;
            background: pink;
            padding: 100px;
            border: 80px solid blue;
            background-image: url("img/1.png");
            background-repeat: no-repeat;
            background-origin: content-box;
            background-position: -50px 0;
        }

        /*答案:130px*/
    </style>
</head>
<body>
<div id="box"></div>
</body>
</html>
  1. 對於函數節流與函數防抖的理解,如下所示:
  • 函數節流,一個函數執行一次後,只有大於設定的執行週期後纔會執行第二次。有個需要頻繁觸發函數,出於優化性能的角度,在規定時間內,只讓函數觸發的第一次生效,後面不生效。具體來說,記錄上一次函數觸發的時間,記錄當前函數觸發的時間,同步時間。
  • 防抖函數,一個需要頻繁觸發的函數,在規定時間內,只讓最後一次生效,前面的不生效。具體來說,記錄上一次的延時器,清除上一次的延時器,重新設置新的延時器。
  1. 對於跨域的理解,解決跨域的方法有哪些,如下所示:
  • 同源策略,是瀏覽器安全策略,協議名、域名和端口號必須完全一致。
  • 跨域,違背同源策略就會產生跨域
  • 解決跨域, jsonpcors 服務器代理
  • 對於跨域的具體實現,創建 script 標籤,設置回調函數,數據請求回來會被觸發的函數,設置 scriptsrc 屬性,設置請求地址,讓 script 生效
  1. 對於 node.js 的事件輪詢機制的理解,可以藉助 libuv 庫實現的,概括事件輪詢機制,分爲六個階段,如下所示:
  • timers 定時器階段,計時和執行到點的定時器回調函數
  • pending callbacks,某些操作系統的回調函數,比如 TCP 錯誤類型
  • idle,prepare,準備工作
  • poll 輪詢階段,輪詢隊列,如果輪詢隊列不爲空,依次同步取出輪詢隊列中第一個回調函數執行,直到輪詢隊列爲空或者達到系統最大的限制。如果輪詢隊列爲空,如果之前設置過 setImmediate 函數,直接進入下一個 check 階段。如果之前沒有設置過 setImmediate 函數,在當前 poll 階段等待,直到輪詢隊列添加回調函數,就去第一個情況執行。如果定時器到點了,也會去下一個階段。
  • check 查階段,執行 setImmediate 設置的回調函數
  • close callbacks 關閉階段,執行 close 事件回調函數
  • process.nextTick 能在任意階段優先執行,process.nextTick() > setTimeout() > setImmediate()
  1. 對於從一個 url 地址到最終頁面渲染完成,發生了什麼,如下所示:
  • DNS 解析,將域名地址解析爲 IP 地址,如下所示:
    • 瀏覽器 DNS 緩存
    • 系統 DNS 緩存
    • 路由器 DNS 緩存
    • 網絡運營商 DNS 緩存
    • 遞歸搜索,如 blog.baidu.com.com 域名下查找 DNS 解析,.baidu 域名下查找 DNS 解析,blog 域名下查找 DNS 解析,出錯了
  • TCP連接,TCP 三次握手,如下所示:
    • 第一次握手,由瀏覽器發起,告訴服務器我要發送請求了
    • 第二次握手,由服務器發起,告訴瀏覽器我準備接受了,你趕緊發送吧
    • 第三次握手,由瀏覽器發送,告訴服務器,我馬上就發了,準備接受吧
  • 發送請求,請求報文,HTTP 協議的通信內容
  • 接受響應,響應報文
  • 渲染頁面,如下所示:
    • 遇見 HTML 標記,瀏覽器調用 HTML 解析器解析完成 Token 並構建 DOM
    • 遇見 style/link 標記,瀏覽器調用 css 解析器,處理 css 標記並構建 CSSOM
    • 遇見 script 標記,調用 javascript 解析器,處理 script 代碼,綁定事件,修改 DOM 樹/CSSOm
    • DOM 樹和 CSSOM 樹合併成一個渲染樹
    • 根據渲染樹來計算佈局,計算每個節點的幾個信息,佈局
    • 將各個節點顏色繪製到屏幕上,渲染
    • 值得注意的是,這幾個步驟不一定按照順序執行,如果 DOM 樹或 CSSOM 樹被修改了,可能會執行多次佈局和渲染,往往實際頁面中,這些步驟都會執行多次的
  • 斷開連接,TCP 四次揮手,如下所示:
    • 第一次揮手,由瀏覽器發起的,發送給服務器,我東西發送完了,請求報文,你準備關閉吧
    • 第二次揮手,由服務器發起的,告訴瀏覽器,我東西接收完了,請求報文,我準備關閉了,你也準備吧
    • 第三次揮手,有服務器發起,告訴瀏覽器,我東西發送完了,響應報文,你準備關閉吧
    • 第四次揮手,由瀏覽器發起,告訴服務器,我東西接收完了,我準備關閉了,響應報文,你也準備吧
  1. 對於閉包的理解,如下所示:
  • 閉包,密閉的容器,類似於setmap容器,存儲數據的。閉包是一個對象,存放數據的格式: key: value
  • 閉包的形成的條件,函數嵌套,內部函數引用外部函數的局部變量
  • 閉包的優點,延長外部函數局部變量的生命週期
  • 閉包的缺點,容易造成內存泄漏
  • 注意的是,合理的使用閉包,用完閉包要及時清除(銷燬)
  • 閉包的實例代碼,如下所示:
    
    // 閉包的應用場景
    // function fun() {
    //   var count = 1;
    //   return function () {
    //     count++;
    //     console.log(count);
    //   }
    // }
    //
    // var fun2 = fun();
    // fun2(); // 2
    // fun2(); // 3
    //
    
    
    /*
       說說它們的輸出情況
       */
    
    function fun(n, o) {
      // var n = 1, o;
      console.log(o)
      return {
        fun: function (m) {
          // var m = 1;
          return fun(m, n)
        }
      }
    }
    var a = fun(0)
    a.fun(1)
    a.fun(2)
    a.fun(3) //undefined,0,0,0
    
    var b = fun(0).fun(1).fun(2).fun(3).fun(50).fun(22) //undefined,0,1,2,3,50
    
    var c = fun(0).fun(1)
    c.fun(2)
    c.fun(3) //undefined,0,1,1
    
    
    
  1. 對於變量提升與執行上下文的理解,如下所示:
  • 變量提升,JS 引擎在代碼正式執行之前會做一個預處理的工作,收集變量和收集函數。依據是 varvar 後邊的變量定義但是不賦值 var username = undefined; function() {} 提前定義該函數
  • 執行上下文,execute context EC,代碼執行的環境,代碼正式執行之前會進入到執行環境,對於它的工作,如下所示:
    • 創建變量對象,變量,函數及函數的對象,全局是 window,局部是抽象的但是確實存在
    • 確認 this 的指向,全局 this 指向 window,局部 this 指向調用其的對象
    • 創建作用域鏈,父級作用域鏈 + 當前的變量對象
    • 擴展,ECObj = { 變量對象:{變量,函數,函數的形參}, scopeChain:父級作用域鏈 + 當前的變量對象,this:{ window || 調用其的對象}}
  1. 對於宏任務和微任務的理解,如下所示:
  • 宏任務,分類: setTimeout setInterval requrestAnimationFrame,如下所示:
    • 宏任務所處的隊列就是宏任務隊列
    • 第一個宏任務隊列中只有一個任務: 執行主線程的 js 代碼
    • 宏任務隊列可以有多個
    • 當宏任務隊列的中的任務全部執行完以後會查看是否有微任務隊列如果有先執行微任務隊列中的所有任務,如果沒有就查看是否有宏任務隊列
  • 微任務,分類: new Promise().then(回調) process.nextTick,如下所示:
    • 微任務所處的隊列就是微任務隊列
    • 只有一個微任務隊列
    • 在上一個宏任務隊列執行完畢後如果有微任務隊列就會執行微任務隊列中的所有任務
  • 宏任務和微任務的代碼,如下所示:
    
    setTimeout(() => {
      console.log('setTimeout');
    }, 0)
    
    new Promise((resolve, reject) =>{
      for (var i = 0; i < 5; i++) {
        console.log(i);
      }
      resolve();  // 修改promise實例對象的狀態爲成功的狀態
    }).then(() => {
      console.log('promise實例成功回調執行');
    })
    
    
    
  1. 比較一下 ReactVue 之間的相同點與不同點,如下所示:
  • 相同點,如下所示:
    • 都有組件化開發和 Virtual DOM
    • 都支持 props 進行父子組件間數據通信
    • 都支持數據驅動視圖, 不直接操作真實 DOM, 更新狀態數據界面就自動更新
    • 都支持服務器端渲染
    • 都有支持 native 的方案, ReactReact Native,VueWeex
  • 不同點,如下所示:
    • 數據綁定: vue實現了數據的雙向綁定,react數據流動是單向的
    • 組件寫法不一樣, React推薦的做法是 JSX , 也就是把HTMLCSS全都寫進JavaScript了,即'all in js'; Vue推薦的做法是webpack+vue-loader的單文件組件格式,即html,css,js寫在同一個文件
    • state對象在react應用中不可變的,需要使用setState方法更新狀態;在vue中,state對象不是必須的,數據由data屬性在vue對象中管理
    • virtual DOM不一樣,vue會跟蹤每一個組件的依賴關係,不需要重新渲染整個組件樹.而對於React而言,每當應用的狀態被改變時,全部組件都會重新渲染,所以react中會需要shouldComponentUpdate這個生命週期函數方法來進行控制
    • React嚴格上只針對MVCview層,Vue則是MVVM模式
  1. 對於Redux管理狀態的機制的理解,如下所示:
  • Redux 基本理解,如下所示:
    • redux是一個獨立專門用於做狀態管理的JS庫, 不是react插件庫
    • 它可以用在react, angular, vue項目中, 但基本與 react 配合使用
    • 作用是集中式管理 react 應用中多個組件共享的狀態和從後臺獲取的數據
  • Redux使用擴展,如下所示:
    • 使用react-redux簡化redux的編碼
    • 使用redux-thunk實現redux的異步編程
    • 使用Redux DevTools實現chromeredux的調試
  1. 對於 Vue 組件間通信方式的理解,如下所示:
  • 通信種類,如下所示:
    • 父組件向子組件通信
    • 子組件向父組件通信
    • 隔代組件間通信
    • 兄弟組件間通信
  • 實現通信方式,如下所示:
    • props
    • vue自定義事件
    • 消息訂閱與發佈
    • vuex
    • slot
  • 方式1: props,如下所示:
    • 通過一般屬性實現父向子通信
    • 通過函數屬性實現子向父通信
    • 缺點是隔代組件和兄弟組件間通信比較麻煩
  • 方式2: vue 自定義事件,如下所示:
    • vue 內置實現, 可以代替函數類型的props,綁定監聽: <MyComp @eventName="callback",觸發(分發)事件: this.$emit("eventName", data)
    • 缺點是隻適合於子向父通信
  • 方式3: 消息訂閱與發佈,如下所示:
    • 需要引入消息訂閱與發佈的實現庫, 如: pubsub-js,訂閱消息: PubSub.subscribe('msg', (msg, data)=>{}),發佈消息: PubSub.publish(‘msg’, data)
    • 優點是此方式可用於任意關係組件間通信
  • 方式4: vuex,如下所示:
    • vuexvue官方提供的集中式管理vue多組件共享狀態數據的vue插件
    • 優點是對組件間關係沒有限制, 且相比於pubsub庫管理更集中, 更方便
  • 方式5: slot,如下所示:
    • 專門用來實現父向子傳遞帶數據的標籤,子組件和父組件
    • 注意的是,通信的標籤模板是在父組件中解析好後再傳遞給子組件的
  1. 對於 Vuex管理狀態的機制的理解,如下所示:
  • Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理的vue插件
  • 作用是集中式管理vue多個組件共享的狀態和從後臺獲取的數據
  1. 對於VueMVVM實現原理的理解,如下所示:
  • Vue作爲MVVM模式的實現庫的2種技術,模板解析和數據綁定
  • 模板解析,實現初始化顯示,解析大括號表達式和解析指令
  • 數據綁定,實現更新顯示,通過數據劫持實現
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章