中高級(jí)前端面試題

事件循環(huán)機(jī)制

同步:執(zhí)行棧

異步:任務(wù)隊(duì)列

1.宏任務(wù)

  • 點(diǎn)擊回調(diào)
  • settimeout

2.微任務(wù)

  • 當(dāng)前task執(zhí)行結(jié)束后立即執(zhí)行的任務(wù)
  • 新微任務(wù)將放到隊(duì)列尾部
  • promise

微任務(wù)會(huì)在下一個(gè)宏任務(wù)前,全部執(zhí)行完

3.事件隊(duì)列

同步任務(wù) → 主線(xiàn)程(執(zhí)行棧)→ 執(zhí)行完成 → 任務(wù)隊(duì)列

瀏覽器渲染

  1. 處理 HTML 標(biāo)記并構(gòu)建 DOM 樹(shù)。
  2. 處理 CSS 標(biāo)記并構(gòu)建 CSSOM(Style Rules) 樹(shù)。
  3. 將 DOM 與 CSSOM 合并成一個(gè)渲染樹(shù)(Render Tree)。
  4. 根據(jù)渲染樹(shù)(Layout)來(lái)布局,以計(jì)算每個(gè)節(jié)點(diǎn)的幾何信息。
  5. 將各個(gè)節(jié)點(diǎn)繪制(Painting)到屏幕上

深拷貝&淺拷貝

  • 首先可以通過(guò) Object.assign 來(lái)解決這個(gè)問(wèn)題,很多人認(rèn)為這個(gè)函數(shù)是用來(lái)深拷貝的。其實(shí)并不是,Object.assign 只會(huì)拷貝所有的屬性值到新的對(duì)象中,如果屬性值是對(duì)象的話(huà),拷貝的是地址,所以并不是深拷貝。 淺拷貝就只是拷貝的對(duì)象的地址。
let a = {
  age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age) // 1
  • 另外我們還可以通過(guò)展開(kāi)運(yùn)算符 ... 來(lái)實(shí)現(xiàn)淺拷貝
let a = {
  age: 1
}
let b = { ...a }
a.age = 2
console.log(b.age) // 1

解構(gòu)賦值的拷貝是淺拷貝,不能復(fù)制繼承自原型對(duì)象的屬性。

  • 深拷貝 這個(gè)問(wèn)題通??梢酝ㄟ^(guò) JSON.parse(JSON.stringify(object)) 來(lái)解決。
let a = {
  age: 1,
  jobs: {
    first: 'FE'
  }
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE

但是該方法也是有局限性的:

  • 會(huì)忽略 undefined
  • 會(huì)忽略 symbol
  • 不能序列化函數(shù)
  • 不能解決循環(huán)引用的對(duì)象

關(guān)于枚舉

四個(gè)操作會(huì)忽略enumerable為false的屬性。

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

屬性的遍歷
ES6 一共有 5 種方法可以遍歷對(duì)象的屬性。

  • (1)for...in

for...in循環(huán)遍歷對(duì)象自身的和繼承的可枚舉屬性(不含 Symbol 屬性)。

  • (2)Object.keys(obj)

Object.keys返回一個(gè)數(shù)組,包括對(duì)象自身的(不含繼承的)所有可枚舉屬性(不含 Symbol 屬性)的鍵名。

  • (3)Object.getOwnPropertyNames(obj)

Object.getOwnPropertyNames返回一個(gè)數(shù)組,包含對(duì)象自身的所有屬性(不含 Symbol 屬性,但是包括不可枚舉屬性)的鍵名。

  • (4)object.getOwnPropertySymbols返回一個(gè)數(shù)組,包含對(duì)象自身的所有 Symbol 屬性的鍵名。

  • (5)Reflect.ownKeys(obj)

Reflect.ownKeys()返回一個(gè)包含所有自身屬性(不包含繼承屬性)的數(shù)組。(類(lèi)似于 Object.keys(), 但不會(huì)受enumerable影響).

js原型

1、proto ( [[Prototype]] )

對(duì)象原型鏈,可以直接通過(guò)屬性訪(fǎng)問(wèn);如果屬性不在當(dāng)前對(duì)象中,就通過(guò)原型鏈查找

var anotherObject = { a:2 };
//自行了解 Object.create(..) 的原理,現(xiàn)在只需要知道它會(huì)創(chuàng)建一個(gè)
對(duì)象并把這個(gè)對(duì)象的 [[Prototype]] 關(guān)聯(lián)到指定的對(duì)象。

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

myObject.__proto__ === anotherObject  //true;

所有普通的 [[Prototype]] 鏈最終都會(huì)指向內(nèi)置的 Object.prototype
都是Object實(shí)例出來(lái)的;

anotherObject 改變  myObject.a改變

myObject.a 改變后,脫離anotherObject

myObject.hasOwnProperty( "a" ); // true

**myObject.foo 總是會(huì)選擇原型鏈中最底層的 foo 屬性 **

2、prototype

所有的函數(shù)默認(rèn)都會(huì)擁有一個(gè) 名為prototyp的公有并且不可枚舉的屬性,它會(huì)指向另一個(gè)對(duì)象 ,這個(gè)對(duì)象通常被稱(chēng)為 Foo 的原型

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

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

new Foo() 只是間接完成了我們的目 標(biāo):一個(gè)關(guān)聯(lián)到其他對(duì)象的新對(duì)象。

3、constructor

function Foo() { // ...   }
 Foo.prototype.constructor === Foo; // true
//Foo.prototype 的 .constructor 屬性只是 Foo 函數(shù)在聲明時(shí)的默認(rèn)屬性。
如果 你創(chuàng)建了一個(gè)新對(duì)象并替換了函數(shù)默認(rèn)的 .prototype
對(duì)象引用,那么新對(duì)象并不會(huì)自動(dòng)獲 得 .constructor 屬性。 
 var a = new Foo();
 a.constructor === Foo; // true


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

a.constructor  === Foo.prototype.constructor === Foo; // true

實(shí)際上 a 本身并沒(méi)有 .constructor 屬性。而且,雖然 a.constructor 確實(shí)指 向 Foo 函數(shù),但是這個(gè)屬性并不是表示 a 由 Foo“構(gòu)造”.

function NothingSpecial() { console.log( "Don't mind me!" ); }
var a = new NothingSpecial(); 
// "Don't mind me!" a; 
// {} 

小結(jié)

  • Object 是所有對(duì)象的爸爸,所有對(duì)象都可以通過(guò)__proto__找到它
  • Function 是所有函數(shù)的爸爸,所有函數(shù)都可以通過(guò)__proto__找到它
  • 函數(shù)的prototype是一個(gè)對(duì)象
  • 對(duì)象的__proto__屬性指向原型,__proto__將對(duì)象和原型連接起來(lái)組成了原型鏈

面向?qū)ο缶幊?/h3>

JavaScript不區(qū)分類(lèi)和實(shí)例的概念,而是通過(guò)原型(prototype)來(lái)實(shí)現(xiàn)面向?qū)ο缶幊獭?/p>

所有對(duì)象都是實(shí)例,所謂繼承關(guān)系不過(guò)是把一個(gè)對(duì)象的原型指向另一個(gè)對(duì)象而已。

Object.create()方法可以傳入一個(gè)原型對(duì)象,并創(chuàng)建一個(gè)基于該原型的新對(duì)象,但是新對(duì)象什么屬性都沒(méi)有,因此,我們可以編寫(xiě)一個(gè)函數(shù)來(lái)創(chuàng)建.

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容