記八月份中小公司前端面試,本文更適合中級

  • 本文是本身在面試時遇到的,面的都是十幾k的職位
  • 全部的答案都是我在翻閱資料,思考驗證以後寫出的,但能力有限,本人的答案未必是最優的,若是您有更好的答案,歡迎給我留言
  • 本文答案也借用優秀答案,已經添加連接,若有侵權,請聯繫我刪除
  • 若是有錯誤或者不嚴謹的地方,請務必給予指正,以避免誤導他人
  • 若是喜歡或者有所啓發,歡迎點贊,對我也是一種鼓勵

面面試,收穫真的挺大的,感謝能有此次機會,感受打開了前進的路, 建議看到題後本身先寫一下試試,知其然還需知其因此然,把原理搞明白javascript

最好重點看下js打印結果那些,考察的基礎, 原本想着再花幾天時間把下面那些js爲何打印解釋下,但一想不如本身去花時間去找一下比較好,就沒再細寫,由於本文挺長的,更詳細的會發到博客

js

1. 以 let str = 'abc' 實現reverse

let str = 'abc'
    function rev(str) {
      let arr = str.split('')
      let tem = []
      for (let i = arr.length-1; i >= 0; i--) {
         tem.push(arr[i])
      }
      return tem.join('')
    }
    rev(str)
    console.log(rev(str))
複製代碼

2. 針對 var arr = [3,4,5,22,1,3]; 寫一個排序函數,對數組進行由小到大排序 (注意不要使用js內置的排序相關函數)

// 冒泡排序: 隨便拿出一個數與後者比較,若是前者比後者大,那麼二者交換位置,
    let arr = [5,2,3,1,4]
    function bubbleSort(arr) {
      let arrLen = arr.length
      for (let i = 0; i < arrLen; i++){
        for (let j = i; j < arrLen; j++){
          let tempi = arr[i]; 
          let tempj = arr[j];
          if (tempi > tempj) {
            arr[i] = tempj;
            arr[j] = tempi;
          }
        }
      } 
      return arr
    }

    console.log(bubbleSort(arr))
  /* 快速排序 : 
    * 1. 以一個數爲基準(基準值能夠任意選擇,選擇中間的值容易理解 
    * 2. 按照順序,將每一個元素與"基準"進行比較,造成兩個子集,一個"小於3",另外一個"大於等於3"。
    * 3. 對兩個子集不斷重複第一步和第二步,直到全部子集只剩下一個元素爲止
  */
    
  let arr = [5, 2, 3, 1, 4]
  function quickSort(arr) {
    // 若是數組爲1那就不必比較了
  &emsp;if (arr.length <= 1) { return arr }
    // 取中間索引值
    let pivotIndex = Math.floor(arr.length / 2)
    // 獲取中間值
    let pivot = arr.splice(pivotIndex, 1)[0]
    let left = []
    let right = []
    for (let i = 0; i < arr.length; i ++) {
      if(arr[i] < pivot) {
        left.push(arr[i])
      } else {
        right.push(arr[i])
      }
    }
    // 使用遞歸不斷重複這個過程
    return quickSort(left).concat([pivot], quickSort(right))
  }
  console.log(quickSort(arr)) 
    
複製代碼

3. 數組去重至少2種

// 1. from && set
 let arr = [1, 1, 4, 50, 50, 6, 2, 2]
 let res = Array.from(new Set(arr))
 console.log(res)

// 2. filter && indexOf
 let arr = [2, 2, 33, 44, 33]
 let res = arr.filter((item, index, arr) => {
    return arr.indexOf(item) == index
 })
  console.log(res)
  
// 3. forEach && includes
  let arr = [2, 2, 33, 44, 33]
  let res = []
  arr.forEach((item) => {
    if (!res.includes(item)) {
      res.push(item)
    }
  })
  console.log(res)
  
// 4. filter &&  Map
 let arr = [2, 2, 33, 44, 33]
 const tem = new Map();
 let res = arr.filter((item) => !tem.has(item) && tem.set(item, 1))
 console.log(res)
複製代碼

3. 去掉 var str = 「 abc beijing 」;中的全部空格

let str = ' adb ddd '
 let res = str.replace(/\s+/g, "")
 console.log(res)
複製代碼

4. 判斷字符串 var str = ‘abdcddsseeed’ 出現最多的字符,並統計出現次數

let str = 'asdasddsfdsfadsfdghdadsdfdgdasd';
function getMax(str) {
  let obj = {};
  for (let i in str) {
    if (obj[str[i]]) {
      obj[str[i]]++
    } else {
      obj[str[i]] = 1
    }
  }
  
  let num = 0
  let number = 0
  for (var i in obj) {
    //若是當前項大於下一項
    if (obj[i] > num) {
      //就讓當前值更改成出現最屢次數的值
      num = obj[i]
      number = i
    }
  }
  console.log('最多的值是' +number+ '出現次數爲' + num);
}

getMax(str);

複製代碼

5. js 實現繼承

// 構造函數繼承
function Super(){
	this.name = ["張三","李四"]
}
function Sub(){
	Super.call(this)
}
let a = new Sub();
a.name.push("王五")
 // 「張三","李四","王五" console.log(a.name); let b = new Sub() //// 「張三","李四"
console.log(b.name)


// Class 繼承
class Fathter {
    constructor(name) {
      this.name = name
    }
    hello() {
      console.log('Hello, ' + this.name)
    }
}
class Son extends Fathter {
    constructor(name) {
      // 記得用super調用父類的構造方法
        super(name)
        console.log(name)
    }
}
let res = new Son('張三')
res.hello()

複製代碼

6. 實現一個數據的深度拷貝,必問原生如何實現

  1. 簡單粗暴, 但函數、正則、Symbol都沒有被正確的複製
JSON.parse(JSON.stringify(obj));
複製代碼
  1. 考慮對象相互引用以及 Symbol 拷貝的狀況

7. 各打印什麼? 爲何?

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

   Foo.getName(); // 2
   getName(); // 4
   Foo().getName(); // 1
   getName(); // 1
   new Foo.getName(); // 2
   new Foo().getName(); // 3 至關於 var f = new Foo()  f.getName()     
   new new Foo().getName(); // 3
   
// 這道題至關經典了 花點時間本身去看下吧
複製代碼

8. 輸出什麼? 爲何

function fun() {
 this.a = 0
 this.b = function() {
   console.log(this)
   console.log(this.a)
 }
}
fun.prototype = {
 b: function() {
   this.a = 20
   console.log(this.a)
 },
 c: function() {
   this.a = 30
   console.log(this.a)
 }
}

var my_fun = new fun();
//私有方法	this=>my_fun
my_fun.b();	
console.log(my_fun.a);
//公有方法	this=>my_fun this.a = 30(私有屬性a修改成30)
my_fun.c();	
console.log(my_fun.a);
var my_fun2 = new fun();
console.log(my_fun2.a);
//this=>my_fun2.__proto__ 當前實例·經過原型鏈在共有屬性增長的了一a:30
my_fun2.__proto__.c();	
console.log(my_fun2.a);
console.log(my_fun2.__proto__.a);
// 0,0,30,30,0,30,0,30

複製代碼

9. 輸出什麼 爲何

function setName(obj){
   obj.name = "Tom"
   obj = new Object()
   obj.name = 'Mike'
 }
  
 var person = new Object()
 setName(person)
 console.log(person.name) // "Tom"
 
複製代碼

10. 怎麼用min 或者是max 查找數組裏的最大值或者最小值

// ES5 的寫法
  let arr = [ 2,4,5,1]
  console.log(Math.min.apply(null, arr))
  
  // ES6 的寫法
   console.log(Math.max(...[14, 3, 77, 30]))
複製代碼

11. javascript 12345678 改成 12,345,678, 也就是千位分隔

  1. 寫不出來才能夠這樣寫哈 要不面試官打你啊哈哈
let num = 12345678
console.log(num.toLocaleString())

複製代碼
  1. 求模
let num = 12345678
function toThousands(num) {
    var result = '', counter = 0;
    num = (num || 0).toString();
    for (var i = num.length - 1; i >= 0; i--) {
        counter++;
        result = num.charAt(i) + result;
        if (!(counter % 3) && i != 0) { result = ',' + result; }
    }
    return result;
}
console.log(toThousands(num))

複製代碼
  1. 正則
// 3-1
let num = 12345678
function toThousands(num) {
    return (num || 0).toString().replace(/(\d)(?=(?:\d{3})+$)/g, '$1,');
}
console.log(toThousands(num))
// 3-2
let num = 12345678
function toCurrency(num){
    var parts = num.toString().split('.');
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    return parts.join('.');
}
console.log(toCurrency(num))
複製代碼

相關連接前端

12. 閉包問題

function f1(){
      var n=999;
      nAdd=function(){n+=1}
      function f2(){
          console.log(n);
      }
      return f2;
  }
  var result=f1();
  result(); // 999
  nAdd();
  result(); // 1000

複製代碼

13. 輸出結果, 爲何

var name = "The Window";
  var object = {
      name : "My Object",
      getNameFunc : function(){
          return function(){
              return this.name;
          };
      }
  };
console.log(object.getNameFunc()()); // the window

複製代碼

14. 輸出結果, 爲何

var length = 1
  function fn() {
      console.log(this.length)
  } 
  
  var obj = {
    length: 3,
    me:function(fn){
      fn() // 1
      arguments[0]() // 2
    }
  }
  obj.me(fn, 1)

複製代碼

15. let str = '你好,abc' 字符串長度

let str = '你好,abc'
function getLength(str){
  let length = 0
  let reg = /[\u4e00-\u9fa5]/
  for (let i = 0; i < str.length; i++) {
      if (reg.test(str.charAt(i))) {
        length +=2
      } else {
        length ++
      }
  }
  return length
}
console.log(getLength(str))

複製代碼

16. Object.defineProperty()有什麼缺點 有什麼方法

  1. 沒法監控到數組下標的變化,致使直接經過數組的下標給數組設置值,不能實時響應。
  2. 只能劫持對象的屬性,所以咱們須要對每一個對象的每一個屬性進行遍歷。Vue裏,是經過遞歸以及遍歷data 對象來實現對數據的監控的,若是屬性值也是對象那麼須要深度遍歷,顯然若是能劫持一個完整的對象,無論是對操做性仍是性能都會有一個很大的提高。

利用 Proxyvue

參考 -- 摒棄 Object.defineProperty,基於 Proxy 的觀察者機制探索java

17. prototype 和 proto 區別是什麼

prototype是構造函數的屬性。node

proto 是每一個實例都有的屬性,能夠訪問 [[prototype]] 屬性。webpack

實例的__proto__ 與其構造函數的prototype指向的是同一個對象。ios

function Student(name) {
    this.name = name;
}
Student.prototype.setAge = function(){
    this.age=20;
}
let Jack = new Student('jack');
console.log(Jack.__proto__);
//console.log(Object.getPrototypeOf(Jack));;
console.log(Student.prototype);
console.log(Jack.__proto__ === Student.prototype);//true複製代碼

參考劉小夕解答git

18. 打印什麼 爲何

var a = {n:1};  
var b = a; // 持有a,以回查  
a.x = a = {n:2};  
console.log(a.x);// --> undefined  
console.log(b.x);// --> {n:2}

複製代碼

19. 打印什麼 爲何

var y = 1;
if (function f(){}) {
    y += typeof f;
}
console.log(y); // 1undefined
複製代碼

20. 打印什麼 爲何

var a = 0
function b(){
  console.log(a) // fun a
  a = 10
  console.log(a) // 10
  return;
  function a(){}
}
b()
console.log(a) // 0
複製代碼

21. 說一下防抖和節流 什麼場景下用

防抖

概念:
    1. 在事件被觸發n秒後再執行回調,若是在這n秒內又被觸發,則從新計時。
    2. 屢次觸發事件後,事件處理函數只執行一次,而且是在觸發操做結束時執行。

應用場景: 
    1. 文本輸入的驗證(連續輸入文字後發送 ajax 請求進行驗證,驗證一次就好)
    2. 給按鈕加函數防抖防止表單屢次提交。

生活實例:
    若是有人進電梯(觸發事件),那電梯將在10秒鐘後出發(執行事件監聽器),這時若是又有人進電梯了(在10秒內再次觸發該事件),咱們又得等10秒再出發(從新計時)。
    
代碼


function debounce(func, interval = 100){
    let timer;
    return (...args) => {
      if (timer) {
        clearTimeout(timer);
      }
      timer = setTimeout(() => {
        func.apply(func, args);
      }, interval);
    }
  }
複製代碼

節流

概念:
    規定一個單位時間,在這個單位時間內,只能有一次觸發事件的回調函數執行,若是在同一個單位時間內某事件被觸發屢次,只有一次能生效

應用場景: 
    滾動刷新如 touchmove, mousemove, scroll。

生活實例:(實例忘記參考誰的了,看到我添加鏈接)
   1. 咱們知道目前的一種說法是當 1 秒內連續播放 24 張以上的圖片時,在人眼的視覺中就會造成一個連貫的動畫,因此在電影的播放(之前是,如今不知道)中基本是以每秒 24 張的速度播放的,爲何不 100 張或更可能是由於 24 張就能夠知足人類視覺需求的時候,100 張就會顯得很浪費資源
   2. 假設電梯一次只能載一人的話,10 我的要上樓的話電梯就得走 10 次,是一種浪費資源的行爲;而實際生活正顯然不是這樣的,當電梯裏有人準備上樓的時候若是外面又有人按電梯的話,電梯會再次打開直到滿載位置,從電梯的角度來講,這時一種節約資源的行爲(相對於一次只能載一我的)。。
    
代碼

function throttle(fn, interval = 100) {
      let canRun = true; // 經過閉包保存一個標記
      return (...args) => {
        if (!canRun) return; // 在函數開頭判斷標記是否爲true,不爲truereturn
        canRun = false; // 當即設置爲false
        setTimeout(() => { // 將外部傳入的函數的執行放在setTimeout中
          fn.apply(fn, args)
          // 最後在setTimeout執行完畢後再把標記設置爲true(關鍵)表示能夠執行下一次循環了。當定時器沒有執行的時候標記永遠是false,在開頭被return掉
          canRun = true;
        }, interval);
      };
    }
複製代碼

22. 監測數組類型有幾種方式 有什麼區別

  • instanceof
    • instanceof不必定能保證檢測的結果必定正確,由於只要是在原型鏈上的都會返回true ,arr instanceof Object 也返回true
  • Array.isArray()
    • 兼容性問題
  • Object.prototype.toString.call()
    • 較好方案

23. 觀察者模式和發佈訂閱模式的寫一下 說一下也行 區別是什麼

木易楊-觀察者模式和訂閱-發佈模式的區別,適用場景

發佈訂閱模式,在工做中它的能量超乎你的想象

很差意思,觀察者模式跟發佈訂閱模式就是不同

24. 打印什麼 爲何

function foo(a) {
  var a;
  return a;
}
function bar(a) {
    var a = 'bye';
    return a;
}
[foo('hello'), bar('hello')] // hello bye

// 在兩個函數裏, a做爲參數其實已經聲明瞭, 因此 var a; var a = 'bye' 其實就是 a; a ='bye'

複製代碼

25. 說一下原型鏈

原型鏈解決的主要是繼承問題。

每一個對象擁有一個原型對象,經過 proto (讀音: dunder proto) 指針指向其原型對象,並從中繼承方法和屬性,同時原型對象也可能擁有原型,這樣一層一層,最終指向 null(==Object.proptotype.proto 指向的是null==)。這種關係被稱爲原型鏈 (prototype chain),經過原型鏈一個對象能夠擁有定義在其餘對象中的屬性和方法。 構造函數 Parent、Parent.prototype 和 實例 p 的關係以下:(==p.proto === Parent.prototype==)

參考劉小夕解答

26 輸出什麼

var name = "World!";
(function() {
    if(typeof name=== 'undefined'){
        var name='Jack';
        console.log('Goodbye'+name);

    } else {
      console.log('hello'+name);
    }
})()

// Goodbye Jack
複製代碼

27. 一隻青蛙一次能夠跳上 1 級臺階,也能夠跳上 2 級。求該青蛙跳上一個 n 級的臺階總共有多少種跳法。

跳到 n 階假設有 f(n)種方法。

往前倒退,若是青蛙最後一次是跳了 2 階,那麼以前有 f(n-2)種跳法; 若是最後一次跳了 1 階,那麼以前有 f(n-1)種跳法。

因此:f(n) = f(n-1) + f(n-2)。就是斐波那契數列
複製代碼

參考

28. 打印什麼

class Chameleon {
  static colorChange(newColor) {
    this.newColor = newColor
    return this.newColor
  }

  constructor({ newColor = 'green' } = {}) {
    this.newColor = newColor
  }
}

const freddie = new Chameleon({ newColor: 'purple' })
freddie.colorChange('orange')

// 會報錯
colorChange是一個靜態方法。靜態方法被設計爲只能被建立它們的構造器使用(也就是 Chameleon),而且不能傳遞給實例。由於 freddie 是一個實例,靜態方法不能被實例使用,所以拋出了 TypeError 錯誤。
複製代碼

解答參考

29. 打印什麼 爲何

function* generator(i) {
  yield i;
  yield i * 2;
}

const gen = generator(10);

console.log(gen.next().value); // 10
console.log(gen.next().value); // 20

通常的函數在執行以後是不能中途停下的。可是,生成器函數卻能夠中途「停下」,以後能夠再從停下的地方繼續。當生成器遇到yield關鍵字的時候,會生成yield後面的值。注意,生成器在這種狀況下不 返回 (return )值,而是 生成 (yield)值。

首先,咱們用10做爲參數i來初始化生成器函數。而後使用next()方法一步步執行生成器。第一次執行生成器的時候,i的值爲10,遇到第一個yield關鍵字,它要生成i的值。此時,生成器「暫停」,生成了10。

而後,咱們再執行next()方法。生成器會從剛纔暫停的地方繼續,這個時候i仍是10。因而咱們走到了第二個yield關鍵字處,這時候須要生成的值是i*2,i爲10,那麼此時生成的值即是20。因此這道題的最終結果是10,20。

複製代碼

參考MDN

解答參考

30 打印什麼

const num = parseInt("7*6", 10);
console.log(num) // 7

parseInt檢查字符串中的字符是否合法. 一旦遇到一個在指定進制中不合法的字符後,當即中止解析而且忽略後面全部的字符。
複製代碼

31. 繼承優缺點

參考JS原型鏈與繼承別再被問倒了

32. class 實現隊列 鏈表

艾倫-前端數據結構與算法系列

33. array.sort如何實現的

參考githubarray源碼-

34. 實現object.create

function create(proto) { 
    function F() {};
    F.prototype = proto; 
    F.prototype.constructor = F; 
    return new F();
}

複製代碼

關於JS中一些重要的api實現, 鞏固你的原生JS功底

35. 說一下Reflect

只能貼下MDN了

36. 說一下generator

zhangxiang958-理解 ES6 generator

阮一峯

37 .說一下proxy

Proxy及其優點

快來圍觀一下JavaScript的Proxy

Proxy 的巧用

框架(vue)本人一直在用vue

1. mvvm

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
    <div id='app'>
        <h3>姓名</h3>
        <p>{{name}}</p>
        <h3>年齡</h3>
        <p>{{age}}</p>
    </div>
</body>
</html>
<script>
document.addEventListener('DOMContentLoaded', function(){
    let opt = {el:'#app', data:{name:'檢索中...', age:30}}
    let vm = new Vue(opt)
    setTimeout(() => {
        opt.data.name = '王永峯'
    }, 2000);
}, false)
class Vue{
    constructor(opt){
        this.opt = opt
        this.observe(opt.data)
        let root = document.querySelector(opt.el)
        this.compile(root)
    }
    // 爲響應式對象 data 裏的每個 key 綁定一個觀察者對象
    observe(data){ 
        Object.keys(data).forEach(key => {
            let obv = new Observer() 
            data["_"+key] = data[key]
            // 經過 getter setter 暴露 for 循環中做用域下的 obv,閉包產生
            Object.defineProperty(data, key, {
                get(){
                    Observer.target && obv.addSubNode(Observer.target);
                    return data['_'+key]
                }, 
                set(newVal){
                    obv.update(newVal)
                    data['_'+key] = newVal
                }
            })
        })
    }
    // 初始化頁面,遍歷 DOM,收集每個key變化時,隨之調整的位置,以觀察者方法存放起來    
    compile(node){
        [].forEach.call(node.childNodes, child =>{
            if(!child.firstElementChild && /\{\{(.*)\}\}/.test(child.innerHTML)){
                let key = RegExp.$1.trim()
                child.innerHTML = child.innerHTML.replace(new RegExp('\\{\\{\\s*'+ key +'\\s*\\}\\}', 'gm'),this.opt.data[key]) 
                Observer.target = child
                this.opt.data[key] 
                Observer.target = null
            }
            else if (child.firstElementChild) 
            this.compile(child)
        })
    }    
}
// 常規觀察者類
class Observer{
    constructor(){
        this.subNode = []    
    }
    addSubNode(node){
        this.subNode.push(node)
    }
    update(newVal){
        this.subNode.forEach(node=>{
            node.innerHTML = newVal
        })
    }
}
</script>

複製代碼

參考-50行代碼的MVVM,感覺閉包的藝術

DMQ-剖析vue實現原理,本身動手實現mvvm

2. computed 和 methods 區別

  1. computed 會基於響應數據緩存,methods不會緩存
  2. diff以前先看data裏的數據是否發生變化,若是沒有變化computed的方法不會執行,但methods裏的方法會執行

3. webpack經常使用配置有哪些, 如何進行打包優化 , 原理是什麼

提取公共模塊,區分開發環境,移除重複沒必要要的 css 和 js 文件等方面說。

Webpack打包優化

Webpack打包原理

Array-Huang-的博客

4. vuex數據流

參考- VUEX 中的數據流

5. 說一下數據雙向綁定

yck-數據雙向綁定

心譚-數據雙向綁定

Vue 雙向數據綁定原理分析

6. key的做用

使用 v-for更新已渲染的元素列表時,默認用就地複用策略。列表數據修改的時候,他會根據key值去判斷某個值是否修改:若是修改,則從新渲染這一項;不然複用以前的dom,僅修改value值。

vue開發看這篇文章就夠了

7. 什麼是函數式組件

函數式組件,即無狀態,沒法實例化,內部沒有任何生命週期處理方法,很是輕量,於是渲染性能高,特別適合用來只依賴外部數據傳遞而變化的組件。

官網

8. webpack 如何打包scss

webpack編譯打包scss

關於webpack4的14個知識點,童叟無欺

webpack實戰場景系列

webpack相關的面試題

9. template編譯原理

關於 Vue 編譯原理這塊的總體邏輯主要分三個部分,也能夠說是分三步,這三個部分是有先後關係的:

  • 第一步是將 模板字符串 轉換成 element ASTs(解析器)
  • 第二步是對 AST 進行靜態節點標記,主要用來作虛擬DOM的渲染優化(優化器)
  • 第三步是 使用 element ASTs 生成 render 函數代碼字符串(代碼生成器)

Vue 模板編譯原理

vue源碼解析

其餘

1. 說下你遇到的難題 講下你的項目吧。不要說業務邏輯

該題是遇到問題最多的 根據自身狀況回答

2. rem的原理 和 vw相比有什麼區別

vw: 兼容性問題 ios八、安卓4.4及以上才徹底支持

rem:和根元素font-size值強耦合,系統字體放大或縮小時,會致使佈局錯亂;弊端之二:html文件頭部需插入一段js代碼

3. 說下重繪和迴流 怎麼避免

參考yck面試經下面有連接

重繪和迴流是渲染步驟中的一小節,可是這兩個步驟對於性能影響很大。

  • 重繪是當節點須要更改外觀而不會影響佈局的,好比改變 color 就叫稱爲重繪
  • 迴流是佈局或者幾何屬性須要改變就稱爲迴流。

迴流一定會發生重繪,重繪不必定會引起迴流。迴流所需的成本比重繪高的多,改變深層次的節點極可能致使父節點的一系列迴流。

  • 改變 window 大小
  • 改變字體
  • 添加或刪除樣式
  • 文字改變
  • 定位或者浮動
  • 盒模型

重繪和迴流其實和 Event loop 有關

  1. 當 Event loop 執行完 Microtasks 後,會判斷 document 是否須要更新。由於瀏覽器是 60Hz 的刷新率,每 16ms 纔會更新一次。
  2. 而後判斷是否有 resize 或者 scroll ,有的話會去觸發事件,因此 resize 和 scroll 事件也是至少 16ms 纔會觸發一次,而且自帶節流功能。
  3. 判斷是否觸發了 media query 更新動畫而且發送事件
  4. 判斷是否有全屏操做事件
  5. 執行 requestAnimationFrame 回調
  6. 執行 IntersectionObserver
  7. 回調,該方法用於判斷元素是否可見,能夠用於懶加載上,可是兼容性很差
  8. 更新界面
  9. 以上就是一幀中可能會作的事情。若是在一幀中有空閒時間,就會去執行 requestIdleCallback 回調。

以上參考yck面試經

騰訊IVWEB團隊-你真的瞭解迴流和重繪嗎

4. 說下跨域 原理是什麼、

浪裏行舟-九種跨域方式實現原理(完整版)

5. 怎麼判斷頁面是否加載完成?

Load 事件觸發表明頁面中的 DOM,CSS,JS,圖片已經所有加載完畢。

DOMContentLoaded 事件觸發表明初始的 HTML 被徹底加載和解析,不須要等待 CSS,JS,圖片加載。

6. cdn 的原理

因爲用戶訪問源站業務有性能瓶頸,經過cdn技術把源站的內容緩存到多個節點。用戶向源站域名發起請求時,請求會被調度至最接近用戶的服務節點,直接由服務節點直接快速響應,有效下降用戶訪問延遲,提高可用性。

7. 從URL輸入到頁面展示到底發生什麼

  • DNS 解析:將域名解析成 IP 地址
  • TCP 鏈接:TCP 三次握手
  • 發送 HTTP 請求
  • 服務器處理請求並返回 HTTP 報文
  • 瀏覽器解析渲染頁面
  • 斷開鏈接:TCP 四次揮手

浪裏行舟-從URL輸入到頁面展示到底發生什麼

說一下 import 和 require 的區別

參考import、require、export、module.exports 混合使用詳解

css

1. 高度已知,三欄佈局,左右寬度300,中間自適應

/* 浮動佈局 */
  .layout.float .left{
    float:left;
    width:300px;
    background: red;
  }
  .layout.float .center{
    background: yellow;
  }
  .layout.float .right{
    float:right;
    width:300px;
    background: blue;
  }
  
  
 /* 絕對定位佈局 */
 .layout.absolute .left-center-right>div{
  position: absolute;
 }
.layout.absolute .left{
  left:0;
  width: 300px;
  background: red;
}
.layout.absolute .center{
  left: 300px;
  right: 300px;
  background: yellow;
}
.layout.absolute .right{
  right:0;
  width: 300px;
  background: blue;
}

 /* flex佈局 */
.layout.flexbox{
  margin-top: 110px;
}
.layout.flexbox .left-center-right{
  display: flex;
}
.layout.flexbox .left{
  width: 300px;
  background: red;
}
.layout.flexbox .center{
  flex:1;
  background: yellow;
}
.layout.flexbox .right{
  width: 300px;
  background: blue;
}

複製代碼

參考 snowLu做者

2. 水平垂直居中

按照固定寬高和不固定寬高分類各說幾個方法

參考16種方法實現水平居中垂直居中

3. css動畫和js動畫有什麼區別

developers

CSS動畫 VS JavaScript

css動畫與js動畫的區別

相關文章
相關標籤/搜索