中高級前端面試題(一)基礎篇

事件循環機制

同步:執行棧

異步:任務隊列

1.宏任務前端

  • 點擊回調
  • settimeout

2.微任務面試

  • 當前task執行結束後當即執行的任務
  • 新微任務將放到隊列尾部
  • promise

微任務會在下一個宏任務前,所有執行完編程

3.事件隊列數組

同步任務 → 主線程(執行棧)→ 執行完成 → 任務隊列
複製代碼

瀏覽器渲染

  1. 處理 HTML 標記並構建 DOM 樹。
  2. 處理 CSS 標記並構建 CSSOM(Style Rules) 樹。
  3. 將 DOM 與 CSSOM 合併成一個渲染樹(Render Tree)。
  4. 根據渲染樹(Layout)來佈局,以計算每一個節點的幾何信息。
  5. 將各個節點繪製(Painting)到屏幕上

深拷貝&淺拷貝

  • 首先能夠經過 Object.assign 來解決這個問題,不少人認爲這個函數是用來深拷貝的。其實並非,Object.assign 只會拷貝全部的屬性值到新的對象中,若是屬性值是對象的話,拷貝的是地址,因此並非深拷貝。 淺拷貝就只是拷貝的對象的地址。
let a = {
  age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age) // 1
複製代碼
  • 另外咱們還能夠經過展開運算符 ... 來實現淺拷貝
let a = {
  age: 1
}
let b = { ...a }
a.age = 2
console.log(b.age) // 1
複製代碼

解構賦值的拷貝是淺拷貝,不能複製繼承自原型對象的屬性。promise

  • 深拷貝 這個問題一般能夠經過 JSON.parse(JSON.stringify(object)) 來解決。
let a = {
  age: 1,
  jobs: {
    first: 'FE'
  }
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE
複製代碼

可是該方法也是有侷限性的:瀏覽器

  • 會忽略 undefined
  • 會忽略 symbol
  • 不能序列化函數
  • 不能解決循環引用的對象

關於枚舉

四個操做會忽略enumerable爲false的屬性。bash

  1. for...in循環:只遍歷對象自身的和繼承的可枚舉的屬性。含原型鏈
  2. Object.keys():返回對象自身的全部可枚舉的屬性的鍵名。含原型鏈
  3. JSON.stringify():只串行化對象自身的可枚舉的屬性。
  4. Object.assign(): 忽略enumerable爲false的屬性,只拷貝對象自身的可枚舉的屬性。

屬性的遍歷 ES6 一共有 5 種方法能夠遍歷對象的屬性。框架

  • (1)for...in

for...in循環遍歷對象自身的和繼承的可枚舉屬性(不含 Symbol 屬性)。異步

  • (2)Object.keys(obj)

Object.keys返回一個數組,包括對象自身的(不含繼承的)全部可枚舉屬性(不含 Symbol 屬性)的鍵名。函數

  • (3)Object.getOwnPropertyNames(obj)

Object.getOwnPropertyNames返回一個數組,包含對象自身的全部屬性(不含 Symbol 屬性,可是包括不可枚舉屬性)的鍵名。

  • (4)object.getOwnPropertySymbols返回一個數組,包含對象自身的全部 Symbol 屬性的鍵名。

  • (5)Reflect.ownKeys(obj)

Reflect.ownKeys()返回一個包含全部自身屬性(不包含繼承屬性)的數組。(相似於 Object.keys(), 但不會受enumerable影響).

  • (6)for…of循環:只遍歷對象自身的可枚舉的屬性。不會輸出原型鏈

js原型

一、proto ( [[Prototype]] )

對象原型鏈,能夠直接經過屬性訪問;若是屬性不在當前對象中,就經過原型鏈查找

var anotherObject = { a:2 };
//自行了解 Object.create(..) 的原理,如今只須要知道它會建立一個
對象並把這個對象的 [[Prototype]] 關聯到指定的對象。

var myObject = Object.create( anotherObject ); 
myObject.a; // 2 

myObject.__proto__ === anotherObject  //true;
複製代碼

全部普通的 [[Prototype]] 鏈最終都會指向內置的 Object.prototype 都是Object實例出來的;

anotherObject 改變  myObject.a改變

myObject.a 改變後,脫離anotherObject

myObject.hasOwnProperty( "a" ); // true
複製代碼

**myObject.foo 老是會選擇原型鏈中最底層的 foo 屬性 **

二、prototype

全部的函數默認都會擁有一個 名爲prototyp的公有而且不可枚舉的屬性,它會指向另外一個對象 ,這個對象一般被稱爲 Foo 的原型

function Foo() { // ...
}
var a = new Foo();

a.__proto__ === Foo.prototype// true複製代碼

new Foo() 只是間接完成了咱們的目 標:一個關聯到其餘對象的新對象。

三、constructor

function Foo() { // ...   }
 Foo.prototype.constructor === Foo; // true
//Foo.prototype 的 .constructor 屬性只是 Foo 函數在聲明時的默認屬性。
若是 你建立了一個新對象並替換了函數默認的 .prototype
對象引用,那麼新對象並不會自動獲 得 .constructor 屬性。 
複製代碼
var a = new Foo();
 a.constructor === Foo; // true


a.__proto__ === NothingSpecial.prototype //true;

a.constructor  === Foo.prototype.constructor === Foo; // true
複製代碼

實際上 a 自己並無 .constructor 屬性。並且,雖然 a.constructor 確實指 向 Foo 函數,可是這個屬性並非表示 a 由 Foo「構造」.

function NothingSpecial() { console.log( "Don't mind me!" ); }

var a = new NothingSpecial(); 
// "Don't mind me!" a; 
// {} 
複製代碼

小結

  • Object 是全部對象的爸爸,全部對象均可以經過__proto__找到它
  • Function 是全部函數的爸爸,全部函數均可以經過__proto__找到它
  • 函數的prototype是一個對象
  • 對象的__proto__屬性指向原型,__proto__將對象和原型鏈接起來組成了原型鏈

面向對象編程

JavaScript不區分類和實例的概念,而是經過原型(prototype)來實現面向對象編程。

全部對象都是實例,所謂繼承關係不過是把一個對象的原型指向另外一個對象而已。

Object.create()方法能夠傳入一個原型對象,並建立一個基於該原型的新對象,可是新對象什麼屬性都沒有,所以,咱們能夠編寫一個函數來建立.

下一篇,框架篇中高級前端面試題(二)框架篇

相關文章
相關標籤/搜索