溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

web前端高頻知識(shí)點(diǎn)面試題有哪些

發(fā)布時(shí)間:2023-03-07 09:50:03 來源:億速云 閱讀:80 作者:iii 欄目:web開發(fā)

今天小編給大家分享一下web前端高頻知識(shí)點(diǎn)面試題有哪些的相關(guān)知識(shí)點(diǎn),內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識(shí),所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

var、let、const

三者的區(qū)別

區(qū)別letconstvar
重復(fù)聲明不能重復(fù)聲明,會(huì)報(bào)SyntaxError錯(cuò)const 定義常量,值不能修改的變量叫做常量,一定要賦初始值,因?yàn)椴荒苄薷摹?/td>可以重復(fù)聲明
塊級(jí)作用域擁有擁有不擁有
會(huì)不會(huì)污染全局變量(掛載在window上)不會(huì)不會(huì)會(huì)

說明
1.let和const也存在變量提升,只是提升的方式不同

  • var變量提升:變量的聲明提升到頂部,值為undefined

  • let、const變量提升: 變量聲明提升到頂部,只不過將該變量標(biāo)記為尚未初始化
    let 和 const存在暫時(shí)性死區(qū),代碼執(zhí)行過程中的一段時(shí)間內(nèi),在此期間無法使用標(biāo)識(shí)符,也不能引用外層作用域的變量。

let answer;
function fn(){
	//如果此時(shí)沒有將變量變量提升到這里,answer應(yīng)該取外層answer的值
	console.log(answer); //Uncaught ReferenceError: Cannot access 'answer' before initialization
	let answer=42;
}

2.var創(chuàng)建的全局變量->全局對(duì)象的屬性,let和const在全局作用域聲明的變量->不是全局對(duì)象的屬性

3.如果常量是個(gè)數(shù)組或?qū)ο螅瑢?duì)其內(nèi)部元素修改,不算對(duì)常量的修改,不會(huì)報(bào)錯(cuò)。常量指向了一個(gè)地址,地址不變就不會(huì)報(bào)錯(cuò)。

變量提升和函數(shù)提升
  • 變量聲明升級(jí)
    通過var定義(聲明)的變量,在定義語句之前的就可以訪問到
    但是值是undefined

  • 函數(shù)聲明提升
    通過function聲明的函數(shù),在之前就可以直接調(diào)用。
    值是函數(shù)體

//變量提升先于函數(shù)提升,提升后被函數(shù)聲明function覆蓋,所以就算換了順序也是function
function a(){
}
var a ;
console.log(typeof a); //function


var f1 = function () {
    console.log(1);
}
function f1 () {
    console.log(2);
}
f1() ; //1
//變量提升后
var f1;//變量提升
function f1(){};//函數(shù)提升
f1 = function () {
    console.log(1);
}
f1() ;

變量提升練習(xí)題

作用域和作用域鏈

理解:一個(gè)代碼段所在的區(qū)域,是靜態(tài)的,在編寫代碼時(shí)就確定了。
作用:變量綁定在這個(gè)作用域內(nèi)有效,隔離變量,不同作用域下同名變量不會(huì)有沖突。
作用域分類

  • 全局作用域

  • 函數(shù)作用域

  • 塊級(jí)作用域

作用域鏈:多個(gè)作用域嵌套,就近選擇,先在自己作用域找,然后去就近的作用域找。

函數(shù)的作用域在聲明的時(shí)候就已經(jīng)決定了,與調(diào)用位置無關(guān)
所以執(zhí)行aaa()的時(shí)候先在aaa的作用域里面找,沒有找到a,再去父級(jí)作用域window里面找,找到a=10

var a = 10;  
function aaa() {
    alert(a);
}
function bbb() {
    var a = 20;
    aaa();
}
bbb();

執(zhí)行上下文

對(duì)當(dāng)前JavaScript的執(zhí)行環(huán)境的抽象,每當(dāng)JavaScript開始執(zhí)行的時(shí)候,它都在執(zhí)行上下文中運(yùn)行。

  • 全局執(zhí)行上下文:在執(zhí)行全局代碼前將window確定為全局執(zhí)行上下文

對(duì)全局?jǐn)?shù)據(jù)進(jìn)行預(yù)處理

  • var定義的全局變量 --> undefined,添加為window的屬性

  • function聲明的全局函數(shù) --> 賦值(函數(shù)體),添加為window的方法

  • this --> 賦值window

  • 開始執(zhí)行全局代碼

  • 函數(shù)執(zhí)行上下文:在調(diào)用函數(shù),準(zhǔn)備執(zhí)行函數(shù)體之前,創(chuàng)建對(duì)應(yīng)的函數(shù)執(zhí)行上下文對(duì)象

對(duì)局部數(shù)據(jù)進(jìn)行預(yù)處理

  • 形參變量 --> 賦值(實(shí)參)–> 添加到函數(shù)執(zhí)行上下文的屬性

  • arguments(形參列表封裝成的偽數(shù)組)–>賦值(實(shí)參列表),添加到函數(shù)執(zhí)行上下文的屬性

  • var定義的局部變量–>undefined,添加為函數(shù)執(zhí)行上下文的屬性

  • function聲明的函數(shù)–>賦值(函數(shù)體),添加為函數(shù)執(zhí)行上下文的方法

  • this–>賦值(調(diào)用函數(shù)的對(duì)象)

  • 開始執(zhí)行函數(shù)體代碼

執(zhí)行上下文棧
1.在全局代碼執(zhí)行前,JS引擎就會(huì)創(chuàng)建一個(gè)棧來存儲(chǔ)管理所有的執(zhí)行上下文對(duì)象
2.在全局執(zhí)行上下文(window)確定后,將其添加到棧中(壓棧)
3.在函數(shù)執(zhí)行上下文創(chuàng)建后,將其添加到棧中(壓棧)
4.在當(dāng)前函數(shù)執(zhí)行完成后,將棧頂?shù)膶?duì)象移除(出棧)
5.當(dāng)所有的代碼執(zhí)行完后,棧中只剩下window

作用域執(zhí)行上下文
定義了幾個(gè)函數(shù) + 1 = 幾個(gè)作用域執(zhí)行了幾個(gè)函數(shù) + 1 = 幾個(gè)執(zhí)行上下文
函數(shù)定義時(shí)就確定了,一直存在,不會(huì)再變化,是靜態(tài)的全局執(zhí)行上下文環(huán)境實(shí)在全局作用域確定之后,js代碼執(zhí)行之前創(chuàng)建的
調(diào)用函數(shù)時(shí)創(chuàng)建,函數(shù)調(diào)用結(jié)束被釋放,是動(dòng)態(tài)的

web前端高頻知識(shí)點(diǎn)面試題有哪些

var foo = 1;
function bar () {
    console.log(foo);
    var foo = 10;
    console.log(foo);
}

bar();

//變量提升后
var foo = 1;
function bar () {
	var foo = undefined;
    console.log(foo); //undefined
    foo = 10;
    console.log(foo);//10
}

bar();

如何用ES5實(shí)現(xiàn)let和const

let :使用立即執(zhí)行函數(shù)創(chuàng)造出一個(gè)塊級(jí)作用域

(function(){
  var a = 1;
  console.log('內(nèi)部a:', a);
})();

const
1.使用立即執(zhí)行函數(shù)創(chuàng)造出一個(gè)塊級(jí)作用域。
2.對(duì)于不可變性,可以利用Object.defineProperty 將變量掛載在對(duì)象上

var __const = function __const(data, value) {
	this.data = value // 把要定義的data掛載到某個(gè)對(duì)象,并賦值value
	Object.defineProperty(this,data, { // 利用Object.defineProperty的能力劫持當(dāng)前對(duì)象,并修改其屬性描述符
		enumerable: false,
		configurable: false,
		get: function () {
			return value
		},
		set: function (data) {
		if (data !== value) { // 當(dāng)要對(duì)當(dāng)前屬性進(jìn)行賦值時(shí),則拋出錯(cuò)誤!
			throw new TypeError('Assignment to constant variable.')	
		} else {
			return value
		}
		}
		})
	}
	//然后和立即執(zhí)行函數(shù)結(jié)合
	(function(){
	 	var obj = {}
		_const.call(obj,'a',10)
	})()
	//當(dāng)執(zhí)行完畢后,全局上就不會(huì)有obj,也不會(huì)有obj.a這個(gè)變量,進(jìn)而實(shí)現(xiàn)了塊級(jí)作用域的功能

代碼輸出題

function a(){
  a.name ='aaa';
  return this.name;
}
var b = {
  a,
  name:'bbb',
  getName:function(){
    return this.name;
  }
}
var c =b.getName;
console.log(a()); //this指向window,window上沒有name,所以輸出undefined
console.log(b.a()); //b.a 是function,b調(diào)用a函數(shù),所以this指向b,所以輸出'bbb'
console.log(b.getName);//通過b調(diào)用getName,所以getName指向b,所以輸出'bbb'
console.log(c());//c是function,this指向window,window上沒有name,所以輸出undefined

數(shù)據(jù)類型

筆記鏈接

  • JS數(shù)據(jù)類型有哪些

  • 介紹一下Symbol和Bigint

  • 如何判斷一個(gè)數(shù)據(jù)類型

  • Object.prototype.toString.call() 的缺點(diǎn)?

  • 各個(gè)方法的原理是什么

  • typeof(NaN) typeof(Null)

  • 手寫 instanceof 方法

  • null==undefined 和 null===undefined

  • 隱式轉(zhuǎn)換規(guī)則 === 和 == 的區(qū)別

  • map和weakmap區(qū)別

  • map和object區(qū)別

  • for in、for of 區(qū)別,分別對(duì)對(duì)象和數(shù)組使用問結(jié)果

  • 講一下數(shù)組的遍歷方法,filter與map的使用場(chǎng)景,some,every的區(qū)別

  • map的操作原理

  • map和forEach的區(qū)別

  • 使用迭代器實(shí)現(xiàn)for-of

  • 手寫數(shù)組去重

  • 手寫數(shù)組扁平化

  • map和filter的區(qū)別

  • 數(shù)組的常用方法

  • 用reduce實(shí)現(xiàn)map

ES6 class和 ES5類的區(qū)別

ES5 function類ES6 class
可以new
可以調(diào)用
必須new調(diào)用,不能直接執(zhí)行
function存在變量提升class不存在變量提升
static靜態(tài)方法只能通過類調(diào)用,不會(huì)出現(xiàn)在實(shí)例上

this的指向

  • 一般函數(shù)中this的指向會(huì)在調(diào)用時(shí)向函數(shù)傳遞執(zhí)行上下文對(duì)象中設(shè)置。

    • 以函數(shù)形式調(diào)用,指向window

    • 以方法形式調(diào)用,this指向調(diào)用的方法

    • 以構(gòu)造函數(shù)的形式調(diào)用,this是新創(chuàng)建的對(duì)象

  • 箭頭函數(shù):本身沒有this,它的this可以沿作用域鏈(定義時(shí)就確定了的)查找

bind、call、apply的區(qū)別與實(shí)現(xiàn)

apply、call、bind 函數(shù)可以改變 this 的指向。

區(qū)別callapplybind
調(diào)用函數(shù)×
參數(shù)從第二個(gè)參數(shù)開始依次傳遞封裝成數(shù)組傳遞從第二個(gè)參數(shù)開始依次傳遞

bind函數(shù)的特殊點(diǎn)
多次綁定,只指向第一次綁定的obj對(duì)象。
多次綁定,一次生效。
原因:返回函數(shù),后續(xù)bind修改的是返回函數(shù)的this

call函數(shù)的實(shí)現(xiàn)

//從第二個(gè)參數(shù)開始依次傳入,所以接收時(shí)使用rest參數(shù)
Function.prototype.call=function(obj,...args){
	obj = obj || window;
	args = args ? args : [];
	//給obj新增一個(gè)獨(dú)一無二的屬性以免覆蓋原有屬性
    const key = Symbol()
	obj[key] = this;
	const res = obj[key](...args);
	delete obj[key];
	return res;	
}

apply函數(shù)的實(shí)現(xiàn)

Function.prototype.apply=function(obj,args){
	obj = obj || window;
	args = args ? args : [];
	//給obj新增一個(gè)獨(dú)一無二的屬性以免覆蓋原有屬性
    const key = Symbol()
	obj[key] = this;
	const res = obj[key](...args);
	delete obj[key];
	return res;	
}

bind函數(shù)的實(shí)現(xiàn)

Function.prototype.bind=function(obj,...args){
	obj = obj || window;
	args = args ? args : [];
	return (...args2) => {
		return this.apply(obj,[...args,...args2])
	}
}

一般函數(shù)和箭頭函數(shù)

箭頭函數(shù)的作用:確保函數(shù)內(nèi)部的this和外部的this是一樣的

箭頭函數(shù)是普通函數(shù)的語法糖,書寫要更加簡潔

區(qū)別一般函數(shù)箭頭函數(shù)
this指向調(diào)用時(shí)確定定義時(shí)確定,沒有自己的this,沿著作用域鏈找父級(jí)的this
改變this指向call,apply,bind不能改變,靜態(tài)
arguments沒有,可以用rest參數(shù)代替
作為構(gòu)造函數(shù)× 沒有prototype屬性
匿名函數(shù)可以匿名可以不匿名匿名函數(shù)
閉包

是什么
閉包就是在函數(shù)中能夠讀取其他函數(shù)內(nèi)部變量

本質(zhì)就是上級(jí)作用域內(nèi)變量的生命周期,因?yàn)楸幌录?jí)作用域內(nèi)引用,而沒有被釋放。
正常情況下,代碼執(zhí)行完成之后,函數(shù)的執(zhí)行上下文出棧被回收。但是如果當(dāng)前函數(shù)執(zhí)行上下文執(zhí)行完成之后中的某個(gè)東西被執(zhí)行上下文以外的東西占用,則當(dāng)前函數(shù)執(zhí)行上下文就不會(huì)出棧釋放,也就是形成了不被銷毀的上下文,閉包。

function foo(){
	var a=2;
	function bar(){ //覆蓋foo()內(nèi)部作用域的閉包
		console.log(a++);
	}
	return bar;
}
var bar = foo(); //foo執(zhí)行創(chuàng)建一個(gè)執(zhí)行上下文環(huán)境,由于bar引用了其內(nèi)部變量,也就是bar持有foo本次執(zhí)行上下文的引用,foo本次的執(zhí)行上下文不會(huì)被銷魂
bar();//2
bar();//3
var fn = foo(); //foo執(zhí)行創(chuàng)建一個(gè)新的執(zhí)行上下文環(huán)境,fn持有了foo本次執(zhí)行上下文的引用
fn();//2

有什么用
1.可以讀取函數(shù)內(nèi)部的變量
2.使函數(shù)的內(nèi)部變量執(zhí)行完后,仍然存活在棧內(nèi)存中(延長了局部變量的生命周期)。

JavaScript閉包就是在另一個(gè)作用域中保存了一份它從上一級(jí)函數(shù)或者作用域得到的變量,而這些變量是不會(huì)隨上一級(jí)函數(shù)的執(zhí)行完成而銷毀

常用場(chǎng)景:節(jié)流防抖
缺點(diǎn)是什么
1.函數(shù)執(zhí)行完后,函數(shù)內(nèi)的局部變量沒有釋放,占用內(nèi)存時(shí)間會(huì)變長
2.容易造成內(nèi)存泄露
怎么解決
及時(shí)釋放:讓內(nèi)部函數(shù)成為垃圾對(duì)象(將閉包手動(dòng)設(shè)置為null)–> 回收閉包

手寫節(jié)流和防抖函數(shù)

作用是:控制回調(diào)函數(shù)觸發(fā)的頻率,進(jìn)行性能優(yōu)化
參數(shù): 控制觸發(fā)頻率的回調(diào)函數(shù)和時(shí)間wait
輸出: 到時(shí)間后,返回callback函數(shù)

節(jié)流:在函數(shù)被頻繁觸發(fā)時(shí), 函數(shù)執(zhí)行一次后,只有大于設(shè)定的執(zhí)行周期后才會(huì)執(zhí)行第二次。一個(gè)時(shí)間段,只觸發(fā)一次
語法:throttle(callback, wait)
常用場(chǎng)景:比如拖動(dòng)、滾動(dòng)和輸入框聯(lián)想

//使用形式,綁定時(shí)候throttle函數(shù)就會(huì)執(zhí)行,所以this是window
window.addEventListener('scroll',throttle(()=>{},500))

/*
思路
需要記錄上一次觸發(fā)的時(shí)間,才可以和當(dāng)前時(shí)間比較,是否超過了間隔時(shí)間
第一次必然立刻觸發(fā)
*/
function throttle(callback,wait){
	let pre = new Date();
	//這里的this是window
	return function(...args){
		//這里的this是綁定的DOM
		const now = new Date();
		if(now-pre>=wait){
			callback.apply(this,args);
			pre = now;
		}
	}
}


/*
使用setTimeout實(shí)現(xiàn)
第一次需要延遲delay后觸發(fā)
*/
function throttle(callback,delay){
	let timer = null;
	//這里的this是window
	return function(...args){
		if(timer){//說明已經(jīng)觸發(fā)了
			return;
		}
		timer = setTimeout(()=>{
			callback.apply(this,args);
			timer = null;
		},delay)
	}
}

函數(shù)防抖:指定時(shí)間間隔內(nèi)只會(huì)執(zhí)行一次任務(wù)。如果在等待的過程中再一次觸發(fā)了事件,計(jì)時(shí)器重新開始計(jì)時(shí),直到達(dá)到時(shí)間后執(zhí)行最后一次的回調(diào)
語法:debounce(callback, wait)
常用場(chǎng)景: 登錄、發(fā)短信等按鈕避免用戶點(diǎn)擊太快,以致于發(fā)送了多次請(qǐng)求,需要防抖。

function debounce(callback,delay){
	let timer = null;
	//這里的this是window
	return function(){
		if(timer){//說明已經(jīng)觸發(fā)了
			clearTimeout(timer);
		}
		timer = setTimeout(()=>{
			callback.apply(this,arguments);
			timer = null;
		},delay)
	}
}

//立即執(zhí)行
function debounce(func,delay) {
  let timeout;
  return function (...args) {
      if (timeout) clearTimeout(timeout);
      const callNow = !timeout;
      timeout = setTimeout(() => {
          timeout = null;
      }, delay)
      if (callNow) func.apply(this, args)
  }
}

原型和原型鏈

筆記鏈接

  • 原型和原型鏈

  • 繼承

JavaScript 線程機(jī)制與事件循環(huán)機(jī)制

筆記鏈接

內(nèi)容

  • 進(jìn)程和線程

  • 進(jìn)程的通信方式

  • 瀏覽器多進(jìn)程架構(gòu)

  • 如何實(shí)現(xiàn)瀏覽器多標(biāo)簽之間的通訊

  • H5 Web Workers JS多線程運(yùn)行

  • 瀏覽器的事件循環(huán)機(jī)制

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

  • node事件循環(huán)代碼輸出題 用于理解

  • 代碼輸出題

DOM渲染

筆記

內(nèi)容

  • DOM的渲染過程

  • DOM渲染的時(shí)機(jī)與渲染進(jìn)程的概述
    -瀏覽器的渲染流程

  • CSS、JS、DOM解析和渲染阻塞問題

  • JS加載阻塞DOM渲染問題,怎么解決? - 異步JS,JS三種異步加載的方式

    • script 標(biāo)簽中的 async 和 defer 屬性

    • DOMContentLoaded和Load

  • DOM渲染優(yōu)化

重繪和回流

筆記

內(nèi)容

  • 什么是重繪和回流

    • 回流和重繪觸發(fā)的時(shí)機(jī)

  • 優(yōu)化方案

    • GPU加速,如何開啟GPU加速

    • JS優(yōu)化減少重繪和回流的觸發(fā)

setTimeout 、setInterval、requestAnimationFrame

筆記

內(nèi)容

  • setTimeout(cb, 0)會(huì)立刻執(zhí)行嗎?

  • settimeout定時(shí)的時(shí)間準(zhǔn)確嗎? 為什么不準(zhǔn)確? 怎么解決?

  • setTimeout和requestAnimation的區(qū)別

  • requestAnimationFrame講一下你的理解

  • setTimeout實(shí)際延遲時(shí)間

  • 用setTimeout實(shí)現(xiàn)setInterval,實(shí)現(xiàn)一個(gè)隨時(shí)停止的版本

  • setTimeout 和 setInterval區(qū)別

  • JS實(shí)現(xiàn)動(dòng)畫的方式

  • requestAnimationFrame與requestIdleCallback分別是什么?

  • requestAnimationFrame的執(zhí)行時(shí)機(jī)?

  • requestanimationframe回調(diào)函數(shù)中進(jìn)行大量計(jì)算,會(huì)阻塞頁面的渲染嗎

  • 每隔一秒輸出一個(gè)數(shù)字

觀察者模式和發(fā)布訂閱機(jī)制

觀察者是軟件設(shè)計(jì)模式中的一種,但發(fā)布訂閱只是軟件架構(gòu)中的一種消息范式

觀察者模式

觀察者模式定義對(duì)象間的一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得到通知并被自動(dòng)更新。

被依賴的對(duì)象叫做subject,依賴的對(duì)象叫做觀察者Observer 。被依賴的對(duì)象首先需要提供一個(gè)添加觀察者方法,以供觀察者調(diào)用。所以還需要維護(hù)一個(gè)觀察者列表,自身發(fā)生變化后,依次通知觀察者。

//subject 被觀察者
class Subject {
  constructor() {
    this.observerList = [];
  }
  addObserver(observer) {
    this.observerList.push(observer);
  }
  removeObserver(observer) {
    const index = this.observerList.findIndex(o => o.name === observer.name);
    this.observerList.splice(index, 1);
  }
  notifyObservers(message) {
    const observers = this.observeList;
    observers.forEach(observer => observer.notified(message));
  }
}

//Observer 觀察者
class Observer {
  constructor(name, subject) {
    this.name = name;
    if (subject) {
      subject.addObserver(this);
    }
  }
  notified(message) {
    console.log(this.name, 'got message', message);
  }
}

//使用
const subject = new Subject();
const observerA = new Observer('observerA', subject);
const observerB = new Observer('observerB');
subject.addObserver(observerB);
subject.notifyObservers('Hello from subject');
subject.removeObserver(observerA);
subject.notifyObservers('Hello again');

發(fā)布訂閱機(jī)制
發(fā)布者和訂閱者不直接進(jìn)行通信,通過事件調(diào)度中心進(jìn)行管理。發(fā)布者將要發(fā)布的消息交由事件調(diào)度中心管理,訂閱者也是根據(jù)自己的情況,按需訂閱事件調(diào)度中心的消息。

//事件調(diào)度中心
class PubSub {
	  constructor() {
        // 存儲(chǔ)格式: warTask: [], routeTask: []
        // {訂閱事件:[回調(diào)1,回調(diào)2...],訂閱事件2:[回調(diào)1,回調(diào)2..]}
        this.events = {}
   	  }
   	  // 訂閱方法 訂閱哪個(gè)類型type就把對(duì)應(yīng)的回調(diào)函數(shù)放入
      subscribe(type, cb) { 
       	 if (!this.events[type]) {
            this.events[type] = [];
        }
        this.events[type].push(cb);
     }
     // 發(fā)布方法
    publish(type, ...args) {
        if (this.events[type]) {
            this.events[type].forEach(cb => cb(...args))
        }
    }
	// 取消訂閱方法 的某一個(gè)類型的某一個(gè)回調(diào)
    unsubscribe(type, cb) {
        if (this.events[type]) {
            const cbIndex = this.events[type].findIndex(e=> e === cb)
            if (cbIndex != -1) {
                this.events[type].splice(cbIndex, 1);
            }
        }
        if (this.events[type].length === 0) {
            delete this.events[type];
        }
    }
}

//測(cè)試
let pubsub = new PubSub();
//訂閱
pubsub.subscribe('warTask', function (taskInfo){
    console.log("宗門殿發(fā)布戰(zhàn)斗任務(wù),任務(wù)信息:" + taskInfo);
})
pubsub.subscribe('routeTask', function (taskInfo) {
    console.log("宗門殿發(fā)布日常任務(wù),任務(wù)信息:" + taskInfo);
});
pubsub.subscribe('allTask', function (taskInfo) {
    console.log("宗門殿發(fā)布五星任務(wù),任務(wù)信息:" + taskInfo);
});
//發(fā)布
pubsub.publish('warTask', "獵殺時(shí)刻");
pubsub.publish('allTask', "獵殺時(shí)刻");
pubsub.publish('routeTask', "種樹澆水");
pubsub.publish('allTask', "種樹澆水");

區(qū)別

類型描述特點(diǎn)
觀察者模式觀察者和被觀察者互相知道身份,目標(biāo)直接將通知分發(fā)到觀察者身上高耦合
發(fā)布訂閱機(jī)制發(fā)布訂閱機(jī)制通過事件調(diào)度中心來協(xié)調(diào),訂閱者和發(fā)布者互相不知道身份低耦合

異步編程解決方案 Generator生成器函數(shù) async/await、Promise

筆記鏈接

筆記內(nèi)容

  • Generator生成器函數(shù)

  • Generator生成器函數(shù)使用上的補(bǔ)充 了解

  • 基于Promise對(duì)象的簡單自動(dòng)執(zhí)行器

  • iterator迭代器

  • async/await是什么? 使用場(chǎng)景是什么?

  • await/async與generator函數(shù)的區(qū)別

  • await/async內(nèi)部實(shí)現(xiàn)原理 Generator函數(shù)和自動(dòng)執(zhí)行器

  • async錯(cuò)誤捕獲方式

  • promise概述

  • promise知識(shí)點(diǎn) 了解

  • promise.then、catch、finally的原理與實(shí)現(xiàn)

  • Promise.all/Promise.race/Promise.allSettled的原理和實(shí)現(xiàn)

  • 手寫題:請(qǐng)求五秒未完成則終止

  • promise實(shí)現(xiàn)并發(fā)的異步任務(wù)調(diào)度器

擴(kuò)展運(yùn)算符的原理和應(yīng)用

淺拷貝和深拷貝

深淺拷貝只是針對(duì)引用數(shù)據(jù)類型
區(qū)分點(diǎn): 復(fù)制之后的副本進(jìn)行修改會(huì)不會(huì)影響到原來的

  • 淺拷貝:修改拷貝以后的數(shù)據(jù)會(huì)影響原數(shù)據(jù)。使得原數(shù)據(jù)不安全。(只拷貝一層)

  • 深拷貝:修改拷貝以后的數(shù)據(jù)不會(huì)影響原數(shù)據(jù),拷貝的時(shí)候生成新數(shù)據(jù)。

淺拷貝

  • 擴(kuò)展運(yùn)算符,適用于數(shù)組/對(duì)象

  • Aarry.prototype.concat(拷貝對(duì)象1,拷貝對(duì)象2...) 數(shù)組的合并方法,將多個(gè)數(shù)組或?qū)ο罂截愡M(jìn)目標(biāo)數(shù)組,返回新數(shù)組。

  • Object.assign(目標(biāo)對(duì)象1,拷貝對(duì)象1,拷貝對(duì)象2.....)對(duì)象的合并方法,將拷貝對(duì)象拷貝進(jìn)目標(biāo)對(duì)象

深拷貝

方式一: JSON.parse(JSON.stringify())

  • JSON.stringify():將JavaScript對(duì)象轉(zhuǎn)換為JSON字符串

  • JSON.parse():可以將JSON字符串轉(zhuǎn)為一個(gè)對(duì)象。

問題1: 函數(shù)屬性會(huì)丟失,不能克隆方法
問題2: 循環(huán)引用會(huì)出錯(cuò)

//循環(huán)引用:b中引用了c,c中又有b
obj = {
b:['a','f'],
c:{h:20}
}
obj.b.push(obj.c);
obj.c.j = obj.b;
b:['a','f',{h:20,j:[]}],
c:{h:20,j:['a','f',[]]}
function deepClone1(target) {
    //通過數(shù)組創(chuàng)建JSON格式的字符串
    let str = JSON.stringify(target);
    //將JSON格式的字符串轉(zhuǎn)換為JS數(shù)據(jù)
    let data = JSON.parse(str);
    return data;
}

方式二:遞歸+map
遞歸:實(shí)現(xiàn)深拷貝,不丟失屬性
map:存儲(chǔ)已經(jīng)拷貝過的對(duì)象,解決循環(huán)引用問題

//map存放已經(jīng)拷貝過的對(duì)象,key為需要拷貝的對(duì)象,value為拷貝后的對(duì)象
function deepClone(target,map=new Map()){
	//1.判斷是否是引用類型
	if(typeof target === 'object' && target !==null ){
		if(map.has(target))return map.get(target); //說明已經(jīng)拷貝過了
		let isArr = Array.isArray(target);
		let res = isArr?[]:{};
		map.set(target,res)
		if(isArr){//拷貝的是數(shù)組
			target.forEach((item,index) => {
				res[index] = deepClone(item,map);
			});	
		}else{//拷貝的是對(duì)象
			Object.keys(target).forEach(key=>{
				res[key]=deepClone(target[key],map);
			})
		} 
		return res; //返回的是一個(gè)數(shù)組或?qū)ο?
	}else{
		return target;
	}
}


//測(cè)試
console.log(deepClone([1,[1,2,[3,4]]]))

以上就是“web前端高頻知識(shí)點(diǎn)面試題有哪些”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會(huì)為大家更新不同的知識(shí),如果還想學(xué)習(xí)更多的知識(shí),請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI