js面試篇
1第煮、前端事件流
事件流描述的是從頁面中接受事件的順序,可以分為:事件捕獲階段 處于目標(biāo)階段 事件冒泡階段其中需要主要的是addeventListener這個函數(shù) 最后這個布爾值參數(shù)如果是true外永,表示在捕獲階段調(diào)用事件處理程序;如果是false拧咳,表示在冒泡階段調(diào)用事件處理程序伯顶。
1、事件捕獲階段:實際目標(biāo)div在捕獲階段不會接受事件骆膝,也就是在捕獲階段祭衩,事件從document到<html>再到<body>就停止了
2、處于目標(biāo)階段:事件在div發(fā)生并處理阅签,但是事件處理會被看成是冒泡階段的一部分掐暮。
-
3、冒泡階段:事件又傳播回文檔
阻止冒泡事件event.stopPropagation()
function stopBubble(e) {
if (e && e.stopPropagation) { // 如果提供了事件對象event 這說明不是IE瀏覽器
e.stopPropagation()
} else {
window.event.cancelBubble = true //IE方式阻止冒泡
}
}
阻止默認(rèn)行為event.preventDefault()
function stopDefault(e) {
if (e && e.preventDefault) {
e.preventDefault()
} else {
// IE瀏覽器阻止函數(shù)器默認(rèn)動作的行為
window.event.returnValue = false
}
}
事件如何先捕獲后冒泡:
在DOM標(biāo)準(zhǔn)事件模型中政钟,是先捕獲后冒泡劫乱。但是如果要實現(xiàn)先冒泡后捕獲的效果,對于同一個事件锥涕,監(jiān)聽捕獲和冒泡,分別對應(yīng)相應(yīng)的處理函數(shù)狭吼,監(jiān)聽到捕獲事件层坠,先暫緩執(zhí)行,直到冒泡事件被捕獲后再執(zhí)行捕獲事件刁笙。
哪些事件不支持冒泡事件:
鼠標(biāo)事件:mouserleave mouseenter
焦點事件:blur focus
UI事件:scroll resize
2破花、事件委托(提高性能)
簡介:事件委托指的是,不在事件的(直接dom)上設(shè)置監(jiān)聽函數(shù)疲吸,而是在其父元素上設(shè)置監(jiān)聽函數(shù)座每。通過事件冒泡,父元素可以監(jiān)聽到子元素上事件的觸發(fā)通過判斷事件發(fā)生元素DOM的類型摘悴,來做出不同的響應(yīng)峭梳。
- 舉例子: 最經(jīng)典的就是ui和li標(biāo)簽的事件監(jiān)聽,比如我們在添加事件的時候蹂喻,采用事件委托機(jī)制葱椭,不會在li標(biāo)簽上直接添加,而是在ul父元素上添加
- 好處:可以比較合適動態(tài)元素的綁定口四,新添加的子元素也會監(jiān)聽函數(shù)孵运,也可以有事件觸發(fā)機(jī)制
3、js的new操作符做了什么
new操作符創(chuàng)建了一個空對象蔓彩,這個對象原型指向構(gòu)造函數(shù)的prototype治笨,執(zhí)行構(gòu)造函數(shù)后返回這個對象驳概。如果不要父類的屬性跟方法,在函數(shù)的prototype上去new這個父類旷赖。
4顺又、this的指向
- 1、當(dāng)函數(shù)作為對象的方法被調(diào)用時杠愧,this就會指向該對象待榔。
- 2、作為普通函數(shù)流济,this指向window锐锣。
- 3、構(gòu)造器調(diào)用绳瘟,this指向返回的這個對象雕憔。
- 4、箭頭函數(shù) 箭頭函數(shù)的this綁定看的是this所在函數(shù)定義在哪個對象下糖声,就綁定哪個對象斤彼。如果有嵌套的情況,則this綁定到最近的一層對象上
4.1蘸泻、箭頭函數(shù)this的原理:
this指向的固定化琉苇,并不是因為箭頭函數(shù)內(nèi)部有綁定this的機(jī)制,實際原因是箭頭函數(shù)根本沒有自己的this悦施,導(dǎo)致內(nèi)部的this就是外層代碼塊的this并扇。正是因為它沒有this,所以也就不能用作構(gòu)造函數(shù)抡诞。
4.2穷蛹、怎么改變this的指向呢?
1.使用es6的箭頭函數(shù)昼汗;2.在函數(shù)內(nèi)部使用that = this肴熏;3.使用apply,call顷窒,bind蛙吏; 4.new實例化一個對象
4.3、bind,apply,call的區(qū)別
通過apply和call改變函數(shù)的this指向鞋吉,他們兩個函數(shù)的第一個參數(shù)都是一樣的表示要改變指向的那個對象出刷,第二個參數(shù),apply是數(shù)組坯辩,而call則是arg1,arg2...這種形式馁龟。bind一個是返回一個函數(shù),并不會立即執(zhí)行第二個是帶參數(shù)(第一個參數(shù)要指向的this漆魔,后面的的參數(shù)用來傳遞
5坷檩、深淺拷貝
基本類型 引用類型
基本類型:undefined,null,Boolean,String,Number,Symbol在內(nèi)存中占據(jù)固定大小却音,保存在棧內(nèi)存中 引用類型:Object,Array,Date,Function,RegExp等 引用類型的值是對象 保存在堆內(nèi)存中,棧內(nèi)存存儲的是對象的變量標(biāo)識符以及對象在堆內(nèi)存中的存儲地址矢炼。
基本類型的復(fù)制:其實就是創(chuàng)建了一個新的副本給將這個值賦值給新變量系瓢, 改變值舊對象不會改變 引用類型的復(fù)制:其實就是復(fù)制了指針,這個最終都將指向同一個對象句灌,改變其值新對象也會改變
注意:基本類型的比較 == 會進(jìn)行類型轉(zhuǎn)換
淺拷貝 深拷貝
僅僅就是復(fù)制了引用夷陋,彼此操作不影響,slice() concat() object.assign 在堆中重新分配內(nèi)存胰锌,不同的地址骗绕,相同的值,互不影響的 JSON.parse()將一個js對象序列化為一個json字符串JSON.stringify()將json字符串反序列化為一個js對象 es6的展開 {...}
重新在堆棧中創(chuàng)建內(nèi)存,拷貝前后對象的基本類型互不影響资昧。只拷貝一層酬土,不能對對象進(jìn)行子對象進(jìn)行拷貝 對對象中的子對象進(jìn)行遞歸拷貝,拷貝前后兩個對象互不影響
6格带、setTimeout和setInterval的機(jī)制
因為js是單線程的撤缴。瀏覽器遇到etTimeout和setInterval會先執(zhí)行完當(dāng)前的代碼塊,在此之前會把定時器推入瀏覽器的待執(zhí)行時間隊列里面叽唱,等到瀏覽器執(zhí)行完當(dāng)前代碼之后會看下事件隊列里有沒有任務(wù)屈呕,有的話才執(zhí)行定時器里的代碼
7、前端跨域問題
同源策略(協(xié)議+端口號+域名要相同)
- 1棺亭、jsonp跨域(只能解決get)
原理:動態(tài)創(chuàng)建一個script標(biāo)簽虎眨。利用script標(biāo)簽的src屬性不受同源策略限制,因為所有的src屬性和href屬性都不受同源策略的限制侦铜,可以請求第三方服務(wù)器資源內(nèi)容
步驟:1.去創(chuàng)建一個script標(biāo)簽
2.script的src屬性設(shè)置接口地址
3.接口參數(shù),必須要帶一個自定義函數(shù)名钟鸵,要不然后臺無法返回數(shù)據(jù)
4.通過定義函數(shù)名去接受返回的數(shù)據(jù)
2钉稍、document.domain 基礎(chǔ)域名相同 子域名不同
3、window.name 利用在一個瀏覽器窗口內(nèi)棺耍,載入所有的域名都是共享一個window.name
4贡未、服務(wù)器設(shè)置對CORS的支持
原理:服務(wù)器設(shè)置Access-Control-Allow-Origin HTTP響應(yīng)頭之后,瀏覽器將會允許跨域請求-
利用h5新特性window.postMessage()
iframe元素創(chuàng)建包含另外一個文檔的內(nèi)聯(lián)框架(行內(nèi)框架)(setTimeout進(jìn)行異步加載)
解釋:瀏覽器中的瀏覽器蒙袍!用于設(shè)置文本或者圖形的浮動圖文框或容器
它和跨域
1俊卤、document.domain 實現(xiàn)主域名相同,子域名不同的網(wǎng)頁通信
都設(shè)置為超域:document.domain = 'demo.com'
2害幅、window.postMessageht(data, url)消恍,h5的API,啟動跨域通信
8以现、圖片預(yù)加載和懶加載
8.1狠怨、預(yù)加載:
提前加載圖片约啊,當(dāng)用戶需要查看是可以直接從本地緩存中渲染
為什么要使用預(yù)加載:在網(wǎng)頁加載之前,對一些主要內(nèi)容進(jìn)行加載佣赖,以提供用戶更好的體驗恰矩,減少等待時間。否則憎蛤,如果一個頁面的內(nèi)容過于龐大外傅,會出現(xiàn)留白。
解決頁面留白的方案:
1.預(yù)加載
2.使用svg站位圖片俩檬,將一些結(jié)構(gòu)快速搭建起來萎胰,等待請求的數(shù)據(jù)來了之后,替換當(dāng)前的占位符
實現(xiàn)預(yù)加載的方法:
1.使用html標(biāo)簽
2.使用Image對象
3.使用XMLHTTPRequest對像豆胸,但會精細(xì)控制預(yù)加載過程
8.2奥洼、懶加載(lazyload)
客戶端優(yōu)化,減少請求數(shù)和延遲請求數(shù)晚胡,提升用戶體驗灵奖,減少無效資源的加載,防止并發(fā)加載的資源過多會阻塞js的加載估盘,影響網(wǎng)站的正常使用
原理:首先將頁面上的圖片的src屬性設(shè)置為空字符串瓷患,而圖片的真是路經(jīng)則設(shè)置帶data-original屬性中,當(dāng)頁面滾動的時候需要去監(jiān)聽scroll事件遣妥,在scroll事件的回調(diào)中擅编,判斷我們的懶加載的圖片是否進(jìn)入到可視區(qū)域,如果圖片在可視區(qū)域?qū)D片的src屬性設(shè)置為data-original的值箫踩,這樣就可以實現(xiàn)延遲加載爱态。
9、函數(shù)節(jié)流和防抖
防抖 節(jié)流
短時間內(nèi)多次觸發(fā)同一個事件境钟,只執(zhí)行最后一次锦担,或者在開始時執(zhí)行,中間不執(zhí)行慨削。比如公交車上車洞渔,要等待最后一個乘客上車 節(jié)流是連續(xù)觸發(fā)事件的過程中以一定時間間隔執(zhí)行函數(shù)。節(jié)流會稀釋你的執(zhí)行頻率缚态,比如每間隔1秒鐘磁椒,只會執(zhí)行一次函數(shù),無論這1秒鐘內(nèi)觸發(fā)了多少次事件
都為解決高頻事件而來玫芦, scroll mousewhell mousemover touchmove onresize浆熔,后面有相應(yīng)的代碼實現(xiàn)函數(shù)的節(jié)流和防抖。
10桥帆、js垃圾回收機(jī)制
1.JS具有自動垃圾收集的機(jī)制
2.JS的內(nèi)存生命周期(變量的生命)
1.分配你所需要的空間 var a = 20
2.使用分配帶的內(nèi)存(讀寫) alert(a + 10)
3.不適用的時候蘸拔,釋放內(nèi)存空間 a = null
3.JS的垃圾收集器每隔固定的時間就執(zhí)行一次釋放操作师郑,通用的是通過標(biāo)記清除的算法
4.在局部作用域中,垃圾回收器很容易做出判斷并回收调窍,全局比較難宝冕,因此應(yīng)避免全局變量
標(biāo)記清除算法:js最常見的垃圾回收方式,當(dāng)變量進(jìn)入執(zhí)行環(huán)境的時候邓萨,比如函數(shù)中聲明一個變量地梨,垃圾回收器將他標(biāo)記為'進(jìn)入環(huán)境',
當(dāng)變量離開(函數(shù)執(zhí)行完后)缔恳,就其標(biāo)記為'離開環(huán)境'宝剖。垃圾回收器會在運行的時候給存儲在內(nèi)存中的所有變量加上標(biāo)記,
然后去掉環(huán)境中的變量以及被環(huán)境中該變量所引用的變量(閉包)歉甚。在這些完成之后仍存在標(biāo)記的就是要刪除的變量了
11万细、一些檢驗方法
千萬不要使用typeof來判斷對象和數(shù)組,因為這種類型都會返回object纸泄。
- typeOf()是判斷基本類型的Boolean,Number赖钞,symbol, undefined, String。
對于引用類型:除function聘裁,都返回object null返回object雪营。 - installOf() 用來判斷A是否是B的實例,installof檢查的是原型衡便。
- toString() 是Object的原型方法献起,對于 Object 對象,直接調(diào)用 toString() 就能返回 [Object Object] 镣陕。而對于其他對象谴餐,則需要通過 call / apply 來調(diào)用才能返回正確的類型信息。
- hasOwnProperty()方法返回一個布爾值呆抑,指示對象自身屬性中是否具有指定的屬性岂嗓,該方法會忽略掉那些從原型鏈上繼承到的屬性。
- isProperty()方法測試一個對象是否存在另一個對象的原型鏈上理肺。
- valueof:所有對象都有valueof摄闸,如果存在任意原始值善镰,他就默認(rèn)將對象轉(zhuǎn)化為表示它的原始值妹萨。如果對象是復(fù)合值,而卻大部分對象無法真正表示一個原始值炫欺,因此默認(rèn)的valueof()方法簡單的返回對象本身乎完,而不是返回原始值
12、splice和slice品洛、map和forEach树姨、 filter()摩桶、reduce()的區(qū)別
1.slice(start,end):方法可以從已有數(shù)組中返回選定的元素,返回一個新數(shù)組帽揪,包含從start到end(不包含該元素)的數(shù)組方法
注意:該方法不會更新原數(shù)組硝清,而是返回一個子數(shù)組
2.splice():該方法想或者從數(shù)組中添加或刪除項目,返回被刪除的項目转晰。(該方法會改變原數(shù)組)
splice(index, howmany,item1,...itemx)
·index參數(shù):必須芦拿,整數(shù)規(guī)定添加或刪除的位置,使用負(fù)數(shù)查邢,從數(shù)組尾部規(guī)定位置
·howmany參數(shù):必須蔗崎,要刪除的數(shù)量,
·item1..itemx:可選扰藕,向數(shù)組添加新項目
3.map():會返回一個全新的數(shù)組缓苛。使用于改變數(shù)據(jù)值的時候。會分配內(nèi)存存儲空間數(shù)組并返回邓深,forEach()不會返回數(shù)據(jù)
4.forEach(): 不會返回任何有價值的東西未桥,并且不打算改變數(shù)據(jù),單純的只是想用數(shù)據(jù)做一些事情庐完,他允許callback更改原始數(shù)組的元素
5.reduce(): 方法接收一個函數(shù)作為累加器钢属,數(shù)組中的每一個值(從左到右)開始縮減,最終計算一個值门躯,不會改變原數(shù)組的值
6.filter(): 方法創(chuàng)建一個新數(shù)組淆党,新數(shù)組中的元素是通過檢查指定數(shù)組中符合條件的所有元素。它里面通過function去做處理
13讶凉、js染乌、css阻塞
js阻塞 css阻塞
所有瀏覽器在下載JS的時候,會阻止一切其他活動懂讯,比如其他資源的下載荷憋,內(nèi)容的呈現(xiàn)等等。直到JS下載褐望、解析勒庄、執(zhí)行完畢后才開始繼續(xù)并行下載其他資源并呈現(xiàn)內(nèi)容。為了提高用戶體驗瘫里,新一代瀏覽器都支持并行下載JS实蔽,但是JS下載仍然會阻塞其它資源的下載(例如.圖片,css文件等)谨读。 因為瀏覽器會維持html中css和js的順序局装,樣式表必須在嵌入的JS執(zhí)行前先加載、解析完。而嵌入的JS會阻塞后面的資源加載铐尚,所以就會出現(xiàn)上面CSS阻塞下載的情況拨脉。
14、類的創(chuàng)建和繼承
(es6)中class, extends
14.1宣增、 繼承:
原型鏈繼承: function Cat(){ } Cat.prototype = new Animal(); Cat.prototype.name = 'cat'; 無法實現(xiàn)多繼承
構(gòu)造繼承:使用父類的構(gòu)造函數(shù)來增強(qiáng)子類實例玫膀。function Cat(name){Animal.call(this);this.name = name || 'Tom';} 無法繼承父類原型鏈上的屬性跟方法 installof去檢驗
實例繼承:為父類實例添加新特性,作為子類實例的返回
拷貝繼承:拷貝父類元素上的屬性跟方法
組合繼承:構(gòu)造繼承 + 原型繼承的組合體
寄生組合繼承:通過寄生方式爹脾,在構(gòu)造繼承上加一個Super函數(shù)(沒有實例和方法) 讓他的原型鏈指向父類的原型鏈 砍掉父類的實例屬性匆骗,這樣,在調(diào)用兩次父類的構(gòu)造的時候誉简,就不會初始化兩次實例方法/屬性
14.2 給兩個構(gòu)造函數(shù)A和B碉就,如何實現(xiàn)A繼承B (Object.prototype)
function A(....){} A.prototype...
function B(....){} B.prototype...
A.prototype = Object.create(B.prototype) 再A的構(gòu)造函數(shù)里new B(props)
使用new一個函數(shù)的話,函數(shù)里的構(gòu)造函數(shù)的參數(shù)就為undefined闷串,里面的一些函數(shù)可能執(zhí)行錯誤瓮钥,因為this改變了
Object.create = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};
15、閉包和原型
15.1烹吵、閉包的理解
- 1碉熄、內(nèi)部函數(shù)可以訪問定義他們外部函數(shù)的參數(shù)和變量。(作用域鏈的向上查找肋拔,把外圍的作用域中的變量值存儲在內(nèi)存中而不是在函數(shù)調(diào)用完畢后銷毀)設(shè)計私有的方法和變量锈津,避免全局變量的污染
- 2、函數(shù)嵌套函數(shù)
- 3凉蜂、本質(zhì)是將函數(shù)內(nèi)部和外部連接起來琼梆。優(yōu)點是可以讀取函數(shù)內(nèi)部的變量,讓這些變量的值始終保存在內(nèi)存中窿吩,不會在函數(shù)被調(diào)用之后自動清除
15.2茎杂、閉包的缺陷:
1.閉包的缺點就是常駐內(nèi)存會增大內(nèi)存使用量,并且使用不當(dāng)容易造成內(nèi)存泄漏
2.如果不是因為某些特殊任務(wù)而需要閉包纫雁,在沒有必要的情況下煌往,在其它函數(shù)中創(chuàng)建函數(shù)是不明智的,因為閉包對腳本性能具有負(fù)面影響轧邪,包括處理速度和內(nèi)存消耗刽脖。
15.3、內(nèi)存的理解
內(nèi)存溢出和內(nèi)存泄漏(給的不夠用| 用了不歸還)
- 1忌愚、內(nèi)存溢出:在程序中申請內(nèi)存時曲管,沒有足夠的內(nèi)存空間供其使用,出現(xiàn)out of memory菜循;比如申請了一個integer,但給它存了long才能存下的數(shù)翘地,那就是內(nèi)存溢出
- 2、內(nèi)存泄漏:在程序申請內(nèi)存后癌幕,無法釋放已申請的內(nèi)存空間衙耕,一次內(nèi)存泄漏危害可以忽略,但內(nèi)存泄漏堆積后果很嚴(yán)重勺远,無論多少內(nèi)存橙喘,遲到會被占光
舉列子:閉包中的this,對象函數(shù)。匿名函數(shù)返回函數(shù)return function
15.4胶逢、作用域
作用域:(由當(dāng)前環(huán)境與上層環(huán)境一系列的變量對象組成L埂!初坠!保證當(dāng)先執(zhí)行環(huán)境里和簸,有權(quán)訪問的變量和函數(shù)是有序的,作用域鏈變量只能被向上訪問)
定義:由當(dāng)前環(huán)境與上層環(huán)境的一系列變量對象組成(函數(shù)嵌套函數(shù)碟刺,內(nèi)部一級級往上有序訪問變量或?qū)ο?
作用是:保證當(dāng)前執(zhí)行環(huán)境里锁保,有權(quán)訪問的變量和函數(shù)時有序的,作用域鏈的變量只能被向上訪問
變量訪問到window對象及被終止半沽,作用域鏈向下訪問是不允許的
1.改變作用域有 with try..中的catch爽柒,
2.所有為定義的直接賦值的變量自動聲明為全局作用域
作用域:一套規(guī)則,管理引擎如何在當(dāng)前作用域以及嵌套的子作用域中根據(jù)標(biāo)識符名稱
查找變量(標(biāo)識符就是變量或者函數(shù)名)(只用全局作用域和局部作用域)(作用域在它創(chuàng)建的時候就存在了)
代碼執(zhí)行分為兩個階段:
1.代碼編譯階段:有編譯器完成者填,將代碼翻譯可執(zhí)行的代碼浩村,這個階段會被確定
2.代碼執(zhí)行階段:有js引擎完成,主要執(zhí)行可執(zhí)行的大媽占哟,這個階段執(zhí)行上下文被創(chuàng)建(對象被創(chuàng)建)
執(zhí)行上下文:一個看不見得對象心墅,存在若干個屬性和變量,它被調(diào)用的時候創(chuàng)建的榨乎。函數(shù)被調(diào)用查看的this指向的object嗓化,object就是上下文(只有被調(diào)用的時候創(chuàng)建)
15.5、作用域鏈
· 當(dāng)代碼在一個環(huán)境中執(zhí)行時谬哀,會創(chuàng)建變量對象的一個作用域鏈,
舉例子:var name ="Tom"
function sayHi () {
alert('Hi,'+name)
}
sayHi() //Hi, Tom
函數(shù)sayHi()的執(zhí)行環(huán)境為全局環(huán)境刺覆,所以它的變量對象為window。當(dāng)函數(shù)執(zhí)行到name時史煎,先查找局部環(huán)境谦屑,找到則換回,否則順著作用域查找篇梭,在全局環(huán)境中氢橙,
找到name返回,這一查找變量的有序過程的依據(jù)就是作用域恬偷。
· 作用域鏈?zhǔn)潜WC執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問
15.6悍手、原型鏈
原型鏈:函數(shù)的原型鏈對象constructor默認(rèn)指向函數(shù)本身,原型對象除了有原型屬性外,為了實現(xiàn)繼承坦康,還有一個原型鏈指針proto,該指針是指向上一層的原型對象竣付,而上一層的原型對象的結(jié)構(gòu)依然類似。因此可以利用proto一直指向Object的原型對象上滞欠,而Object原型對象用Object.prototype.proto=null表示原型鏈頂端古胆。如此形成了js的原型鏈繼承。同時所有的js對象都有Object的基本防范