日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

前端面试总结--JS

發(fā)布時(shí)間:2023/12/8 HTML 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 前端面试总结--JS 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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

String、Number、Boolean、null、undefined

類型判斷

判斷基本數(shù)據(jù)類型用typeof: MDN

  • typeof 'aaa' // string
  • typeof 123 // number
  • typeof true // boolean
  • typeof null // object 因?yàn)閚ull和object的類型標(biāo)簽都是0,null是一個(gè)空對象指針
  • typeof undefined // undefined
  • typeof 函數(shù) // function
  • typeof 其他對象 // object

判斷引用類型用instanceof: MDN

  • instanceof 運(yùn)算符用來檢測 constructor.prototype 是否存在于參數(shù) object 的原型鏈上。
  • 用instanceof來判斷基本數(shù)據(jù)類型會(huì)報(bào)錯(cuò)

如何判斷一個(gè)數(shù)據(jù)是NaN

NaN==NaN; // false isNaN(NaN); // true Number.isNaN(NaN); // true Object.is(NaN,NaN); // true

null與undefined區(qū)別

null 表示值被定義但是個(gè)空值,null是一個(gè)空對象指針;
undefined 表示變量聲明但未賦值;
參考:理解 | 堆內(nèi)存棧內(nèi)存釋放、null和{}、undefined的區(qū)別

null == undefined // true null === undefined // falsetypeof null // object typeof undefined // undefinedNumber(null) // 0 Number(undefined) // NaN

作用域鏈

定義:訪問一個(gè)變量時(shí),會(huì)先在當(dāng)前作用域查找該變量,若找到就直接使用,若未找到就繼續(xù)向上一層查找,直到全局作用域。這種鏈?zhǔn)讲樵冴P(guān)系就是作用域鏈。
其實(shí)作用域鏈在函數(shù)定義時(shí)已經(jīng)確定了,作用域鏈?zhǔn)呛秃瘮?shù)定義時(shí)的位置相關(guān)的。在函數(shù)創(chuàng)建的時(shí)候創(chuàng)建一個(gè)包含外部對象(包括全局對象和所有包含自己的對象)的作用域鏈,儲(chǔ)存在內(nèi)部[[scope]]屬性中。函數(shù)執(zhí)行的時(shí)候會(huì)創(chuàng)建一個(gè)執(zhí)行環(huán)境,通過復(fù)制[[scope]]屬性中的對象,構(gòu)建執(zhí)行環(huán)境的作用域鏈,并把自己的活動(dòng)對象推向當(dāng)前作用域鏈的前端以此形成完整的作用域鏈。[[scope]]屬性中保存的是對可訪問變量對象的引用,而不是值的復(fù)制。
參考:函數(shù)的作用域鏈在定義時(shí)已經(jīng)確定!!

閉包

定義:閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。
優(yōu)點(diǎn):局部變量可被重用且不會(huì)被污染(變量私有化)。
缺點(diǎn):由于變量不會(huì)被回收,所以濫用閉包會(huì)導(dǎo)致內(nèi)存溢出,所以要及時(shí)釋放不再需要的閉包。
代碼

function count() {var num = 0;return function(){num++;} } count();

閉包是在定義時(shí)確定的


參考:JS閉包的理解

事件處理機(jī)制

DOM事件流存在三個(gè)階段:事件捕獲階段處于目標(biāo)階段事件冒泡階段
在捕獲階段觸發(fā)事件:addEventListener(event, listener, true)
在冒泡階段出發(fā)事件:addEventListener(event, listener, false), attachEvent(event,listener)

事件委托

<ul><li></li><li></li><li></li> </ul>window.onload = function(){ var UL = document.getElementById('ul');//委托ul上的點(diǎn)擊事件,將當(dāng)前點(diǎn)擊的li節(jié)點(diǎn)變?yōu)榧t色UL.onclick = function(ev){ var e = ev || window.event;var target = e.target || window.event.srcElement; //判斷target是否符合要求的元素節(jié)點(diǎn) if(target.tagName.toLowerCase() == 'li'){//將當(dāng)前點(diǎn)擊這個(gè)li節(jié)點(diǎn)變成紅色 target.style.backgroundColor = 'red';} }}

如果我們需要在每一個(gè)li上綁定一個(gè)事件,就可以利用事件冒泡原理,將這些事件綁定到ul上,讓ul來代為處理。
優(yōu)點(diǎn):

  • 提高性能。每個(gè)函數(shù)都會(huì)占用內(nèi)存,使用一個(gè)事件可減少內(nèi)存占用。
  • 動(dòng)態(tài)監(jiān)聽。新增的節(jié)點(diǎn)無需再重新綁定事件也擁有和其他節(jié)點(diǎn)一樣的事件。

阻止事件冒泡

W3C的方法: event.stopPropagation()
IE的方法: event.cancelBubble =true

function stopBubble(e) {if (e && e.stopPropagation) {e.stopPropagation();} else {window.event.cancelBubble = true;} }

取消默認(rèn)事件

W3C的方法: event.preventDefault()
IE的方法: event.returnValue =false

function stopDefault(e) {if (e && e.preventDefault) {e.preventDefault();} else {window.event.returnValue = false;} }

垃圾回收機(jī)制

標(biāo)記清除:垃圾收集器在運(yùn)行的時(shí)候會(huì)給存儲(chǔ)在內(nèi)存中的所有變量都加上標(biāo)記(當(dāng)然,可以使用任何標(biāo)記方式)。然后,它會(huì)去掉環(huán)境中的變量以及被環(huán)境中的變量引用的變量的標(biāo)記。而在此之后再被加上標(biāo)記的變量將被視為準(zhǔn)備刪除的變量,原因是環(huán)境中的變量已經(jīng)無法訪問到這些變量了。最后,垃圾收集器完成內(nèi)存清除工作,銷毀那些帶標(biāo)記的值并回收它們所占用的內(nèi)存空間。
引用計(jì)數(shù):當(dāng)聲明了一個(gè)變量并將一個(gè)引用類型值賦值該變量時(shí),則這個(gè)值的引用次數(shù)就是1.如果同一個(gè)值又被賦給另外一個(gè)變量,則該值得引用次數(shù)加1。相反,如果包含對這個(gè)值引用的變量又取 得了另外一個(gè)值,則這個(gè)值的引用次數(shù)減 1。當(dāng)這個(gè)值的引用次數(shù)變成 0時(shí),則說明沒有辦法再訪問這個(gè)值了,因而就可以將其占用的內(nèi)存空間回收回來。這樣,當(dāng)垃圾收集器下次再運(yùn)行時(shí),它就會(huì)釋放那 些引用次數(shù)為零的值所占用的內(nèi)存。
參考:js垃圾回收機(jī)制和引起內(nèi)存泄漏的操作;JS垃圾回收機(jī)制;談?wù)凧S 垃圾回收機(jī)制

this的指向

方法調(diào)用模式:this指向?qū)ο蟆?br /> 函數(shù)調(diào)用模式:this指向window。
構(gòu)造器調(diào)用模式:this指向?qū)嵗?br /> call和apply調(diào)用:this指向傳入的第一個(gè)參數(shù)。
箭頭函數(shù):this指向定義時(shí)所在的對象,call和apply失效;不可以當(dāng)做構(gòu)造函數(shù);不可以使用arguments對象;不可以使用yield命令。
參考:call、apply和bind方法的用法以及區(qū)別;函數(shù)的四種調(diào)用模式及this指向;JS this指向總結(jié)

call、apply和bind的用法以及區(qū)別

它們作用都是改變函數(shù)運(yùn)行時(shí)this的指向。

function func (a,b,c) {}// call的第一個(gè)參數(shù)是要綁定給this的值,從第二個(gè)參數(shù)開始是接收的參數(shù)列表。 // 當(dāng)?shù)谝粋€(gè)參數(shù)為null、undefined的時(shí)候,this默認(rèn)指向window。 func.call(obj, 1, 2, 3)// apply接受兩個(gè)參數(shù),第一個(gè)參數(shù)是要綁定給this的值,第二個(gè)參數(shù)是一個(gè)參數(shù)數(shù)組。 // 當(dāng)?shù)谝粋€(gè)參數(shù)為null、undefined的時(shí)候,this默認(rèn)指向window。 func.apply(obj, [1,2,3])// bind和call很相似,第一個(gè)參數(shù)是this的指向,從第二個(gè)參數(shù)開始是接收的參數(shù)列表。 // 區(qū)別在于bind的返回值是一個(gè)改變了this指向的函數(shù),不會(huì)立即執(zhí)行,原來的函數(shù)this的指向是不變的。 func.bind(obj, 1, 2, 3)

參考:call、apply和bind方法的用法以及區(qū)別;讓你弄懂 call、apply、bind的應(yīng)用和區(qū)別;「干貨」細(xì)說 call、apply 以及 bind 的區(qū)別和用法

原型和原型鏈

function SuperType(){this.property = true; } SuperType.prototype.getSuperValue = function(){return this.property; } var superInstance = new SuperType();

function SubType(){this.subProperty = false; } SubType.prototype.getSubValue = function(){return this.subProperty; } var subInstance = new SubType();

SubType.prototype = new SuperType(); SubType.prototype.getSubValue1 = function(){return this.subProperty; } var instance = new SubType(); alert(instance.getSuperValue()); //true //查找順序:instance→SubType.prototype→SuperType.prototype

注意:subInstance.constructor = SuperType,因?yàn)镾ubType.prototype指向了另一個(gè)對象,導(dǎo)致constructor 被重寫了;同理,subInstance.getSubValue()也已經(jīng)訪問不到了。

如何實(shí)現(xiàn)繼承

1-經(jīng)典繼承(借用構(gòu)造函數(shù))
優(yōu)點(diǎn):可以在子類構(gòu)造函數(shù)中向父類構(gòu)造函數(shù)傳參;避免了引用類型的屬性被所有實(shí)例共享。
缺點(diǎn):方法都在構(gòu)造函數(shù)中定義,每次創(chuàng)建實(shí)例都會(huì)創(chuàng)建一遍方法,無法復(fù)用。

function SuperType(){this.colors = ['red','blue','green']; } function SubType(){SuperType.call(this);//繼承了SuperType } var instance1 = new SubType(); instance1.colors.push('black'); console.log(instance1.colors);//["red", "blue", "green", "black"] var instance2 = new SuperType(); console.log(instance2.colors);//["red", "blue", "green"]

2-原型鏈繼承(借用原型鏈)
優(yōu)點(diǎn):方法可以復(fù)用。
缺點(diǎn):引用類型的屬性被所有實(shí)例共享;創(chuàng)建子類的實(shí)例時(shí),不能向父類傳參。

function SuperType(){ } SuperType.prototype.name= "Nicholas"; SuperType.prototype.sayName = function(){console.log(this.name); } function SubType(){ } SubType.prototype = new SuperType(); SubType.prototype.age = 29; SubType.prototype.sayAge = function(){console.log(this.age); } var instance1 = new SubType(); instance1.sayName();//"Nicholas" instance1.sayAge();//29

3-偽經(jīng)典繼承(組合繼承)
優(yōu)點(diǎn):融合原型鏈繼承和構(gòu)造函數(shù)繼承的優(yōu)點(diǎn),是 JavaScript 中最常用的繼承模式。

function SuperType(name){this.name = name;this.colors = ['red','blue','green']; } SuperType.prototype.sayName = function(){console.log(this.name); } function SubType(name,age){//繼承屬性SuperType.call(this,name);this.age = age; } //繼承方法 SubType.prototype = new SuperType(); SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function(){console.log(this.age); }var instance1 = new SubType('Nicholas',29); instance1.colors.push('black'); console.log(instance1.colors);//["red", "blue", "green", "black"] instance1.sayName();//"Nicholas" instance1.sayAge();//29 var instance2 = new SubType('Greg',27); console.log(instance2.colors);//["red", "blue", "green"] instance2.sayName();//"Greg" instance2.sayAge();//27

參考:js各種繼承方式和優(yōu)缺點(diǎn)的介紹

新建對象的方法

1-直接新建

let person = {sex: 'femail',age: '19',eat: function(){console.log('eating');} }

2-工廠模式

function createAPerson(){let person = new Object();person.sex = 'femail';person.age = '19';person.eat = function(){console.log('eating');}return person; } let person = createAPerson();

3-構(gòu)造函數(shù)模式

function Person(){this.sex = 'femail';this.age = '19';this.eat = function(){console.log('eating');} } let person = new Person();

4-原型模式

function Person(){ } Person.prototype.sex = 'femail'; Person.prototype.age = '19'; Person.prototype.eat = function(){console.log('eating'); } let person = new Person();

5-混合模式(組合使用構(gòu)造函數(shù)模式和原型模式)

function Person(){this.sex = 'femail';this.age = '19'; } Person.prototype.eat = function(){console.log('eating'); } let person = new Person();

參考:js中對象與對象創(chuàng)建方法的各種方法

EventLoop

宏任務(wù)
宏任務(wù)的例子有很多,包括創(chuàng)建主文檔對象、解析HTML、執(zhí)行主線JavaScript代碼,更改當(dāng)前的URL、以及各種事件、setTimeout、setInterval等。
微任務(wù)
微任務(wù)是更小的任務(wù),主要包括Promise的回調(diào)函數(shù)、DOM發(fā)生變化。微任務(wù)需要盡可能快的、通過異步的方式執(zhí)行。
事件循環(huán)基于兩個(gè)基本原則
一次處理一個(gè)任務(wù)。
一個(gè)任務(wù)開始后直到運(yùn)行完成,不會(huì)被其他任務(wù)中斷。
參考:Promise自我修養(yǎng)之事件循環(huán)

怎么區(qū)分宏任務(wù)和微任務(wù)

宏任務(wù)是由宿主發(fā)起的,而微任務(wù)由JavaScript自身發(fā)起
參考鏈接:宏任務(wù)和微任務(wù)到底是什么?

MutationObserver

描述:監(jiān)視一個(gè)節(jié)點(diǎn)及其全部子節(jié)點(diǎn)樹的添加、移除元素,以及任何屬性變化的事件
應(yīng)用:群組組件監(jiān)聽disabled屬性

var targetNode = document.querySelector("#someElement"); var observerOptions = {childList: true, // 觀察目標(biāo)子節(jié)點(diǎn)的變化,是否有添加或者刪除attributes: true, // 觀察屬性變動(dòng)subtree: true // 觀察后代節(jié)點(diǎn),默認(rèn)為 false } var observer = new MutationObserver(callback); observer.observe(targetNode, observerOptions);//回調(diào)函數(shù) function callback(mutationList, observer) {mutationList.forEach((mutation) => {switch(mutation.type) {case 'childList':/* 從樹上添加或移除一個(gè)或更多的子節(jié)點(diǎn);參見 mutation.addedNodes 與mutation.removedNodes */break;case 'attributes':/* mutation.target 中某節(jié)點(diǎn)的一個(gè)屬性值被更改;該屬性名稱在 mutation.attributeName 中,該屬性之前的值為 mutation.oldValue */break;}}); }

變量和函數(shù)的優(yōu)先級

函數(shù)提升優(yōu)先級高于變量提升,且不會(huì)被同名變量聲明覆蓋,但是會(huì)被變量賦值后覆蓋。而且存在同名函數(shù)與同名變量時(shí),優(yōu)先執(zhí)行函數(shù)。
參考:JS中變量提升與函數(shù)提升及其優(yōu)先級

堆內(nèi)存和棧內(nèi)存

參考:JavaScript棧內(nèi)存和堆內(nèi)存

深拷貝和淺拷貝

深拷貝和淺拷貝是針對引用數(shù)據(jù)類型的,比如數(shù)組和對象。基本數(shù)據(jù)類型不存在深淺拷貝之分
淺拷貝:只復(fù)制引用,原對象屬性值改變,新的屬性值也會(huì)改變。(只復(fù)值第一層
深拷貝:創(chuàng)建一個(gè)新的內(nèi)存,復(fù)制真正的值,原對象屬性值改變,新的屬性值不會(huì)受影響。(復(fù)制每一層

淺拷貝數(shù)組:

// 方法1 let arr1 = [1,2,3,4,5]; let arr2 = [...arr1];// 方法2 let arr1 = [1,2,3,4,5]; let arr2 = arr1.slice(0)// 方法3 let arr1 = [1,2,3,4,5]; let arr2 = arr1.concat()

淺拷貝對象:

// 方法1 var o2 = Object.assign({}, o1)// 方法2 var o2 = {...o1}

深拷貝數(shù)組和對象:

// 方法1,需要求目標(biāo)對象(非 undefined,function) const obj2 = JSON.parse(JSON.stringify(obj1));// 方法2 function deepClone(item){const target = item.constructor === Array ? [] : {}; // 判斷復(fù)制的目標(biāo)是數(shù)組還是對象for(let keys in item){ // 遍歷目標(biāo)if(item.hasOwnProperty(keys)){if(item[keys] && typeof item[keys] === 'object'){ // 如果值是對象,就遞歸一下target[keys] = item[keys].constructor === Array ? [] : {};target[keys] = deepClone(item[keys]);}else{ // 如果不是,就直接賦值target[keys] = item[keys];}}}return target; }

淺拷貝內(nèi)存分析

深拷貝內(nèi)存分析

參考:內(nèi)存分析-深淺拷貝

函數(shù)柯里化(Currying)

定義:柯里化是指通過函數(shù)調(diào)用繼續(xù)返回函數(shù)的方式,實(shí)現(xiàn)多次接收參數(shù)最后統(tǒng)一處理的函數(shù)編碼形式
優(yōu)點(diǎn):函數(shù)復(fù)用、延遲執(zhí)行、提前確認(rèn)
參考:詳解JS函數(shù)柯里化;「前端面試題系列6」理解函數(shù)的柯里化

// 一個(gè)普通函數(shù) function sum(a, b, c) {console.log(a + b + c); }// 柯里化后 const fn = curry(sum)// 可能的調(diào)用方式 fn(1, 2, 3); // 6 fn(1, 2)(3); // 6 fn(1)(2, 3); // 6 fn(1)(2)(3); // 6// 優(yōu)點(diǎn)1:可以復(fù)用 // 優(yōu)點(diǎn)2:可延遲執(zhí)行 const tempF = fn(1, 2) const res1 = tempF(3) // 6 const res2 = tempF(4) // 7// 柯里化實(shí)現(xiàn)方法 function curry (fn, currArgs) {return function() {// 將 arguments 數(shù)組化let args = [].slice.call(arguments);// 首次調(diào)用時(shí),若未提供最后一個(gè)參數(shù)currArgs,則不用進(jìn)行args的拼接if (currArgs !== undefined) {args = args.concat(currArgs);}// 遞歸調(diào)用if (args.length < fn.length) {return curry(fn, args);}// 遞歸出口return fn.apply(null, args);} }// 優(yōu)點(diǎn)3:提前確認(rèn):可以在不同條件下返回不同的函數(shù),省去重復(fù)的判斷過程 // before var on = function(element, event, handler) {if (document.addEventListener) {if (element && event && handler) {element.addEventListener(event, handler, false);}} else {if (element && event && handler) {element.attachEvent('on' + event, handler);}} } // after var on = (function() {if (document.addEventListener) {return function(element, event, handler) {if (element && event && handler) {element.addEventListener(event, handler, false);}};} else {return function(element, event, handler) {if (element && event && handler) {element.attachEvent('on' + event, handler);}};} })();

數(shù)組的常用方法

arr.push() // 從后面添加元素,返回值為添加完后的數(shù)組的長度 arr.pop() // 從后面刪除元素,只能是一個(gè),返回值是刪除的元素 arr.shift() // 從前面刪除元素,只能刪除一個(gè) 返回值是刪除的元素 arr.unshift() // 從前面添加元素, 返回值是添加完后的數(shù)組的長度 arr.splice(i,n) // 刪除從i(索引值)開始之后的n個(gè)元素。返回值是刪除的元素 arr.concat() // 連接兩個(gè)數(shù)組 返回值為連接后的新數(shù)組 str.split() // 將字符串轉(zhuǎn)化為數(shù)組 arr.sort() // 將數(shù)組進(jìn)行排序,返回值是排好的數(shù)組,默認(rèn)是按照最左邊的數(shù)字進(jìn)行排序,不是按照數(shù)字大小排序的 arr.reverse() // 將數(shù)組反轉(zhuǎn),返回值是反轉(zhuǎn)后的數(shù)組 arr.slice(start,end) // 切去索引值start到索引值end的數(shù)組,不包含end索引的值,返回值是切出來的數(shù)組 arr.forEach(callback) // 遍歷數(shù)組,無return 即使有return,也不會(huì)返回任何值,并且會(huì)影響原來的數(shù)組 arr.map(callback) // 映射數(shù)組(遍歷數(shù)組),有return 返回一個(gè)新數(shù)組 arr.filter(callback) // 過濾數(shù)組,返回一個(gè)滿足要求的數(shù)組 arr.reduce(callback) // 對數(shù)組中的每個(gè)元素執(zhí)行一個(gè)由您提供的reducer函數(shù)(升序執(zhí)行),將其結(jié)果匯總為單個(gè)返回

普通函數(shù)和構(gòu)造函數(shù)的區(qū)別

  • 構(gòu)造函數(shù)也是一個(gè)普通函數(shù),創(chuàng)建方式和普通函數(shù)一樣,但是構(gòu)造函數(shù)習(xí)慣上首字母大寫;
  • 調(diào)用方式不一樣,普通函數(shù)直接調(diào)用,構(gòu)造函數(shù)要用關(guān)鍵字new來調(diào)用;
  • 調(diào)用時(shí),構(gòu)造函數(shù)內(nèi)部會(huì)創(chuàng)建一個(gè)新對象,就是實(shí)例,普通函數(shù)不會(huì)創(chuàng)建新對象;
  • 構(gòu)造函數(shù)內(nèi)部的this指向?qū)嵗?#xff0c;普通函數(shù)內(nèi)部的this指向調(diào)用函數(shù)的對象(如果沒有對象調(diào)用,默認(rèn)為window);
  • 構(gòu)造函數(shù)默認(rèn)的返回值是創(chuàng)建的對象(也就是實(shí)例),普通函數(shù)的返回值由return語句決定;
  • 構(gòu)造函數(shù)的函數(shù)名與類名相同;

防抖和節(jié)流

防抖:當(dāng)持續(xù)觸發(fā)事件時(shí),一定時(shí)間段內(nèi)沒有再觸發(fā)事件,事件處理函數(shù)才會(huì)執(zhí)行一次,如果設(shè)定的時(shí)間到來之前,又一次觸發(fā)了事件,就重新開始延時(shí)。
節(jié)流:當(dāng)持續(xù)觸發(fā)事件時(shí),保證一定時(shí)間段內(nèi)只調(diào)用一次事件處理函數(shù)。
參考:js防抖和節(jié)流
代碼:

// 防抖 function debounce(fn, wait) { var timeout = null; return function() { if(timeout !== null) clearTimeout(timeout); timeout = setTimeout(fn, wait); } } // 處理函數(shù) function handle() { console.log(Math.random()); } // 滾動(dòng)事件 window.addEventListener('scroll', debounce(handle, 1000)); // 節(jié)流 var throttle = function(func, delay) { var prev = Date.now(); return function() { var context = this; var args = arguments; var now = Date.now(); if (now - prev >= delay) { func.apply(context, args); prev = Date.now(); } } } // 處理函數(shù) function handle() { console.log(Math.random()); } // 滾動(dòng)事件 window.addEventListener('scroll', throttle(handle, 1000));

new 操作符做了什么

// 創(chuàng)建了一個(gè)空對象obj var obj = {}; // 將這個(gè)空對象的__proto__成員指向了Base函數(shù)對象prototype成員對象 obj.__proto__ = Base.prototype; // 將Base函數(shù)對象的this指針替換成obj,然后調(diào)用Base函數(shù) Base.call(obj);

參考:js中的new()到底做了些什么??

websocket

websocket的特點(diǎn):

  • 服務(wù)器可以主動(dòng)向客戶端推送信息,客戶端也可以主動(dòng)向服務(wù)器發(fā)送信息,是真正的雙向平等對話
  • 建立在 TCP 協(xié)議之上,服務(wù)器端的實(shí)現(xiàn)比較容易
  • 與 HTTP 協(xié)議有著良好的兼容性。默認(rèn)端口也是80和443,并且握手階段采用 HTTP 協(xié)議,因此握手時(shí)不容易屏蔽,能通過各種 HTTP 代理服務(wù)器
  • 數(shù)據(jù)格式比較輕量,性能開銷小,通信高效
  • 可以發(fā)送文本,也可以發(fā)送二進(jìn)制數(shù)據(jù)
  • 有同源限制,客戶端可以與任意服務(wù)器通信
  • 協(xié)議標(biāo)識(shí)符是ws(如果加密,則為wss),服務(wù)器網(wǎng)址就是 URL(ws://example.com:80/some/path)

WebSocket 是什么原理?為什么可以實(shí)現(xiàn)持久連接?

export default {name : 'websocket',data() {return {websock: null,}},created() {this.initWebSocket();},destroyed() {this.websock.close() //離開路由之后斷開websocket連接},methods: {initWebSocket(){ //初始化weosocketconst wsuri = "ws://127.0.0.1:8080";this.websock = new WebSocket(wsuri);this.websock.onmessage = this.websocketonmessage;this.websock.onopen = this.websocketonopen;this.websock.onerror = this.websocketonerror;this.websock.onclose = this.websocketclose;},websocketonopen(){ //連接建立之后執(zhí)行send方法發(fā)送數(shù)據(jù)let actions = {"test":"12345"};this.websocketsend(JSON.stringify(actions));},websocketonerror(){//連接建立失敗重連this.initWebSocket();},websocketonmessage(e){ //數(shù)據(jù)接收const redata = JSON.parse(e.data);},websocketsend(Data){//數(shù)據(jù)發(fā)送this.websock.send(Data);},websocketclose(e){ //關(guān)閉console.log('斷開連接',e);},}, }

異步請求xhr、ajax、axios與fetch的區(qū)別比較

xhr:現(xiàn)代瀏覽器,最開始與服務(wù)器交換數(shù)據(jù),都是通過XMLHttpRequest對象。它可以使用JSON、XML、HTML和text文本等格式發(fā)送和接收數(shù)據(jù)。

  • 優(yōu)點(diǎn):
    不重新加載頁面的情況下更新網(wǎng)頁
    在頁面已加載后從服務(wù)器請求/接收數(shù)據(jù)
    在后臺(tái)向服務(wù)器發(fā)送數(shù)據(jù)
  • 缺點(diǎn):
    使用起來也比較繁瑣,需要設(shè)置很多值
    早期的IE瀏覽器有自己的實(shí)現(xiàn),這樣需要寫兼容代碼
  • 代碼:
var request = new XMLHttpRequest(); request.open("GET", "get.php", true); request.send(); //該屬性每次變化時(shí)會(huì)觸發(fā) request.onreadystatechange = function(){// readyState: 響應(yīng)是否成功// 0:請求為初始化,open還沒有調(diào)用// 1:服務(wù)器連接已建立,open已經(jīng)調(diào)用了// 2:請求已接收,接收到頭信息了// 3:請求處理中,接收到響應(yīng)主題了// 4:請求已完成,且響應(yīng)已就緒,也就是響應(yīng)完成了//若響應(yīng)完成且請求成功if(request.readyState === 4 && request.status === 200){//do something, e.g. request.responseText} }

jQuery ajax:jQuery對XMLHttpRequest對象的封裝。

  • 優(yōu)點(diǎn):
    對原生XHR的封裝,做了兼容處理,簡化了使用。
    增加了對JSONP的支持,可以簡單處理部分跨域。
  • 缺點(diǎn):
    如果有多個(gè)請求,并且有依賴關(guān)系的話,容易形成回調(diào)地獄。
    本身是針對MVC的編程,不符合現(xiàn)在前端MVVM的浪潮。
    ajax是jQuery中的一個(gè)方法。如果只是要使用ajax卻要引入整個(gè)jQuery非常的不合理。
  • 代碼:
$.ajax({type: 'POST',url: url, data: data,dataType: dataType,success: function () {},error: function () {} })

axios:Axios是一個(gè)基于promise的HTTP庫,可以用在瀏覽器和 node.js 中。它本質(zhì)也是對原生XMLHttpRequest的封裝,只不過它是Promise的實(shí)現(xiàn)版本,符合最新的ES規(guī)范。

  • 優(yōu)點(diǎn):
    從瀏覽器中創(chuàng)建XMLHttpRequests
    從 node.js 創(chuàng)建 http 請求
    支持 Promise API
    攔截請求和響應(yīng)
    轉(zhuǎn)換請求數(shù)據(jù)和響應(yīng)數(shù)據(jù)
    取消請求
    自動(dòng)轉(zhuǎn)換 JSON 數(shù)據(jù)
    客戶端支持防御 XSRF
  • 缺點(diǎn):
    只持現(xiàn)代代瀏覽器
  • 代碼:
axios({method: 'post',url: '/user/12345',data: {firstName: 'liu',lastName: 'weiqin'}}).then(res => console.log(res)).catch(err => console.log(err))

fetch:fetch是低層次的API,代替XHR,可以輕松處理各種格式,非文本化格式。可以很容易的被其他技術(shù)使用,例如Service Workers。但是想要很好的使用fetch,需要做一些封裝處理。

  • 優(yōu)點(diǎn):
    mode: 'no-cors’就可以跨域了
  • 缺點(diǎn):
    fetch只對網(wǎng)絡(luò)請求報(bào)錯(cuò),對400,500都當(dāng)做成功的請求,需要封裝去處理
    fetch默認(rèn)不會(huì)帶cookie,需要添加配置項(xiàng)
    fetch不支持abort,不支持超時(shí)控制,使用setTimeout及Promise.reject的實(shí)現(xiàn)超時(shí)控制并不能阻止請求過程繼續(xù)在后臺(tái)運(yùn)行,造成了流量的浪費(fèi)
    fetch沒有辦法原生監(jiān)測請求的進(jìn)度,而XHR可以
  • 代碼:
fetch('/users.json', {method: 'post', mode: 'no-cors',data: {} }).then(function() { /* handle response */ });

參考:異步請求xhr、ajax、axios與fetch的區(qū)別比較

對異步的理解

js是單線程的,一次只能做一件事情,遇到需要等待結(jié)果的任務(wù),如果一直等候,就會(huì)阻塞進(jìn)程,異步就是可以在某個(gè)任務(wù)等待結(jié)果的時(shí)候先執(zhí)行其他任務(wù),等結(jié)果返回后再執(zhí)行這個(gè)任務(wù)

總結(jié)

以上是生活随笔為你收集整理的前端面试总结--JS的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。