中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

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

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

web前端高頻知識點面試題有哪些

發布時間:2023-03-07 09:50:03 來源:億速云 閱讀:81 作者:iii 欄目:web開發

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

var、let、const

三者的區別

區別letconstvar
重復聲明不能重復聲明,會報SyntaxError錯const 定義常量,值不能修改的變量叫做常量,一定要賦初始值,因為不能修改。可以重復聲明
塊級作用域擁有擁有不擁有
會不會污染全局變量(掛載在window上)不會不會

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

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

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

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

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

3.如果常量是個數組或對象,對其內部元素修改,不算對常量的修改,不會報錯。常量指向了一個地址,地址不變就不會報錯。

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

  • 函數聲明提升
    通過function聲明的函數,在之前就可以直接調用。
    值是函數體

//變量提升先于函數提升,提升后被函數聲明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(){};//函數提升
f1 = function () {
    console.log(1);
}
f1() ;

變量提升練習題

作用域和作用域鏈

理解:一個代碼段所在的區域,是靜態的,在編寫代碼時就確定了
作用:變量綁定在這個作用域內有效,隔離變量,不同作用域下同名變量不會有沖突。
作用域分類

  • 全局作用域

  • 函數作用域

  • 塊級作用域

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

函數的作用域在聲明的時候就已經決定了,與調用位置無關
所以執行aaa()的時候先在aaa的作用域里面找,沒有找到a,再去父級作用域window里面找,找到a=10

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

執行上下文

對當前JavaScript的執行環境的抽象,每當JavaScript開始執行的時候,它都在執行上下文中運行。

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

對全局數據進行預處理

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

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

  • this --> 賦值window

  • 開始執行全局代碼

  • 函數執行上下文:在調用函數,準備執行函數體之前,創建對應的函數執行上下文對象

對局部數據進行預處理

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

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

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

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

  • this–>賦值(調用函數的對象)

  • 開始執行函數體代碼

執行上下文棧
1.在全局代碼執行前,JS引擎就會創建一個棧來存儲管理所有的執行上下文對象
2.在全局執行上下文(window)確定后,將其添加到棧中(壓棧)
3.在函數執行上下文創建后,將其添加到棧中(壓棧)
4.在當前函數執行完成后,將棧頂的對象移除(出棧)
5.當所有的代碼執行完后,棧中只剩下window

作用域執行上下文
定義了幾個函數 + 1 = 幾個作用域執行了幾個函數 + 1 = 幾個執行上下文
函數定義時就確定了,一直存在,不會再變化,是靜態的全局執行上下文環境實在全局作用域確定之后,js代碼執行之前創建的
調用函數時創建,函數調用結束被釋放,是動態的

web前端高頻知識點面試題有哪些

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實現let和const

let :使用立即執行函數創造出一個塊級作用域

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

const
1.使用立即執行函數創造出一個塊級作用域。
2.對于不可變性,可以利用Object.defineProperty 將變量掛載在對象上

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

代碼輸出題

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調用a函數,所以this指向b,所以輸出'bbb'
console.log(b.getName);//通過b調用getName,所以getName指向b,所以輸出'bbb'
console.log(c());//c是function,this指向window,window上沒有name,所以輸出undefined

數據類型

筆記鏈接

  • JS數據類型有哪些

  • 介紹一下Symbol和Bigint

  • 如何判斷一個數據類型

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

  • 各個方法的原理是什么

  • typeof(NaN) typeof(Null)

  • 手寫 instanceof 方法

  • null==undefined 和 null===undefined

  • 隱式轉換規則 === 和 == 的區別

  • map和weakmap區別

  • map和object區別

  • for in、for of 區別,分別對對象和數組使用問結果

  • 講一下數組的遍歷方法,filter與map的使用場景,some,every的區別

  • map的操作原理

  • map和forEach的區別

  • 使用迭代器實現for-of

  • 手寫數組去重

  • 手寫數組扁平化

  • map和filter的區別

  • 數組的常用方法

  • 用reduce實現map

ES6 class和 ES5類的區別

ES5 function類ES6 class
可以new
可以調用
必須new調用,不能直接執行
function存在變量提升class不存在變量提升
static靜態方法只能通過類調用,不會出現在實例上

this的指向

  • 一般函數中this的指向會在調用時向函數傳遞執行上下文對象中設置。

    • 以函數形式調用,指向window

    • 以方法形式調用,this指向調用的方法

    • 以構造函數的形式調用,this是新創建的對象

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

bind、call、apply的區別與實現

apply、call、bind 函數可以改變 this 的指向。

區別callapplybind
調用函數×
參數從第二個參數開始依次傳遞封裝成數組傳遞從第二個參數開始依次傳遞

bind函數的特殊點
多次綁定,只指向第一次綁定的obj對象。
多次綁定,一次生效。
原因:返回函數,后續bind修改的是返回函數的this

call函數的實現

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

apply函數的實現

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

bind函數的實現

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

一般函數和箭頭函數

箭頭函數的作用:確保函數內部的this和外部的this是一樣的

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

區別一般函數箭頭函數
this指向調用時確定定義時確定,沒有自己的this,沿著作用域鏈找父級的this
改變this指向call,apply,bind不能改變,靜態
arguments沒有,可以用rest參數代替
作為構造函數× 沒有prototype屬性
匿名函數可以匿名可以不匿名匿名函數
閉包

是什么
閉包就是在函數中能夠讀取其他函數內部變量

本質就是上級作用域內變量的生命周期,因為被下級作用域內引用,而沒有被釋放。
正常情況下,代碼執行完成之后,函數的執行上下文出棧被回收。但是如果當前函數執行上下文執行完成之后中的某個東西被執行上下文以外的東西占用,則當前函數執行上下文就不會出棧釋放,也就是形成了不被銷毀的上下文,閉包。

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

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

JavaScript閉包就是在另一個作用域中保存了一份它從上一級函數或者作用域得到的變量,而這些變量是不會隨上一級函數的執行完成而銷毀

常用場景:節流防抖
缺點是什么
1.函數執行完后,函數內的局部變量沒有釋放,占用內存時間會變長
2.容易造成內存泄露
怎么解決
及時釋放:讓內部函數成為垃圾對象(將閉包手動設置為null)–> 回收閉包

手寫節流和防抖函數

作用是:控制回調函數觸發的頻率,進行性能優化
參數: 控制觸發頻率的回調函數和時間wait
輸出: 到時間后,返回callback函數

節流:在函數被頻繁觸發時, 函數執行一次后,只有大于設定的執行周期后才會執行第二次。一個時間段,只觸發一次
語法:throttle(callback, wait)
常用場景:比如拖動、滾動和輸入框聯想

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

/*
思路
需要記錄上一次觸發的時間,才可以和當前時間比較,是否超過了間隔時間
第一次必然立刻觸發
*/
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實現
第一次需要延遲delay后觸發
*/
function throttle(callback,delay){
	let timer = null;
	//這里的this是window
	return function(...args){
		if(timer){//說明已經觸發了
			return;
		}
		timer = setTimeout(()=>{
			callback.apply(this,args);
			timer = null;
		},delay)
	}
}

函數防抖:指定時間間隔內只會執行一次任務。如果在等待的過程中再一次觸發了事件,計時器重新開始計時,直到達到時間后執行最后一次的回調
語法:debounce(callback, wait)
常用場景: 登錄、發短信等按鈕避免用戶點擊太快,以致于發送了多次請求,需要防抖。

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

//立即執行
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 線程機制與事件循環機制

筆記鏈接

內容

  • 進程和線程

  • 進程的通信方式

  • 瀏覽器多進程架構

  • 如何實現瀏覽器多標簽之間的通訊

  • H5 Web Workers JS多線程運行

  • 瀏覽器的事件循環機制

  • Node的事件循環機制

  • node事件循環代碼輸出題 用于理解

  • 代碼輸出題

DOM渲染

筆記

內容

  • DOM的渲染過程

  • DOM渲染的時機與渲染進程的概述
    -瀏覽器的渲染流程

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

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

    • script 標簽中的 async 和 defer 屬性

    • DOMContentLoaded和Load

  • DOM渲染優化

重繪和回流

筆記

內容

  • 什么是重繪和回流

    • 回流和重繪觸發的時機

  • 優化方案

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

    • JS優化減少重繪和回流的觸發

setTimeout 、setInterval、requestAnimationFrame

筆記

內容

  • setTimeout(cb, 0)會立刻執行嗎?

  • settimeout定時的時間準確嗎? 為什么不準確? 怎么解決?

  • setTimeout和requestAnimation的區別

  • requestAnimationFrame講一下你的理解

  • setTimeout實際延遲時間

  • 用setTimeout實現setInterval,實現一個隨時停止的版本

  • setTimeout 和 setInterval區別

  • JS實現動畫的方式

  • requestAnimationFrame與requestIdleCallback分別是什么?

  • requestAnimationFrame的執行時機?

  • requestanimationframe回調函數中進行大量計算,會阻塞頁面的渲染嗎

  • 每隔一秒輸出一個數字

觀察者模式和發布訂閱機制

觀察者是軟件設計模式中的一種,但發布訂閱只是軟件架構中的一種消息范式

觀察者模式

觀察者模式定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時,所有依賴于它的對象都得到通知并被自動更新。

被依賴的對象叫做subject,依賴的對象叫做觀察者Observer 。被依賴的對象首先需要提供一個添加觀察者方法,以供觀察者調用。所以還需要維護一個觀察者列表,自身發生變化后,依次通知觀察者。

//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');

發布訂閱機制
發布者和訂閱者不直接進行通信,通過事件調度中心進行管理。發布者將要發布的消息交由事件調度中心管理,訂閱者也是根據自己的情況,按需訂閱事件調度中心的消息。

//事件調度中心
class PubSub {
	  constructor() {
        // 存儲格式: warTask: [], routeTask: []
        // {訂閱事件:[回調1,回調2...],訂閱事件2:[回調1,回調2..]}
        this.events = {}
   	  }
   	  // 訂閱方法 訂閱哪個類型type就把對應的回調函數放入
      subscribe(type, cb) { 
       	 if (!this.events[type]) {
            this.events[type] = [];
        }
        this.events[type].push(cb);
     }
     // 發布方法
    publish(type, ...args) {
        if (this.events[type]) {
            this.events[type].forEach(cb => cb(...args))
        }
    }
	// 取消訂閱方法 的某一個類型的某一個回調
    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];
        }
    }
}

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

區別

類型描述特點
觀察者模式觀察者和被觀察者互相知道身份,目標直接將通知分發到觀察者身上高耦合
發布訂閱機制發布訂閱機制通過事件調度中心來協調,訂閱者和發布者互相不知道身份低耦合

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

筆記鏈接

筆記內容

  • Generator生成器函數

  • Generator生成器函數使用上的補充 了解

  • 基于Promise對象的簡單自動執行器

  • iterator迭代器

  • async/await是什么? 使用場景是什么?

  • await/async與generator函數的區別

  • await/async內部實現原理 Generator函數和自動執行器

  • async錯誤捕獲方式

  • promise概述

  • promise知識點 了解

  • promise.then、catch、finally的原理與實現

  • Promise.all/Promise.race/Promise.allSettled的原理和實現

  • 手寫題:請求五秒未完成則終止

  • promise實現并發的異步任務調度器

擴展運算符的原理和應用

淺拷貝和深拷貝

深淺拷貝只是針對引用數據類型
區分點: 復制之后的副本進行修改會不會影響到原來的

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

  • 深拷貝:修改拷貝以后的數據不會影響原數據,拷貝的時候生成新數據。

淺拷貝

  • 擴展運算符,適用于數組/對象

  • Aarry.prototype.concat(拷貝對象1,拷貝對象2...) 數組的合并方法,將多個數組或對象拷貝進目標數組,返回新數組。

  • Object.assign(目標對象1,拷貝對象1,拷貝對象2.....)對象的合并方法,將拷貝對象拷貝進目標對象

深拷貝

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

  • JSON.stringify():將JavaScript對象轉換為JSON字符串

  • JSON.parse():可以將JSON字符串轉為一個對象。

問題1: 函數屬性會丟失,不能克隆方法
問題2: 循環引用會出錯

//循環引用: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) {
    //通過數組創建JSON格式的字符串
    let str = JSON.stringify(target);
    //將JSON格式的字符串轉換為JS數據
    let data = JSON.parse(str);
    return data;
}

方式二:遞歸+map
遞歸:實現深拷貝,不丟失屬性
map:存儲已經拷貝過的對象,解決循環引用問題

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


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

以上就是“web前端高頻知識點面試題有哪些”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

会昌县| 海南省| 衡水市| 图木舒克市| 云安县| 京山县| 肇源县| 阜康市| 仁怀市| 宝山区| 绵竹市| 遂平县| 无极县| 长垣县| 鲜城| 东山县| 雅江县| 高唐县| 达孜县| 武邑县| 太仓市| 德兴市| 汶上县| 株洲市| 界首市| 京山县| 平原县| 泰宁县| 衡水市| 台中市| 措美县| 遂平县| 庄河市| 屯门区| 新化县| 绥阳县| 尚志市| 九龙县| 高邮市| 丁青县| 延寿县|