2020回顧-個(gè)人web分享JavaScript面試題附加回答
把你的前端拿捏得死死的,每天學(xué)習(xí)得爽爽的,達(dá)達(dá)前端程序員 感謝不負(fù)每一份熱愛(ài)前端的程序員,不論前端技能有多奇葩,歡迎關(guān)注
前言
希望可以通過(guò)這篇文章,能夠給你得到幫助。
1. JavaScript垃圾回收機(jī)制的了解
對(duì)于在JavaScript中的字符串,對(duì)象,數(shù)組是沒(méi)有固定大小的,只有當(dāng)對(duì)他們進(jìn)行動(dòng)態(tài)分配存儲(chǔ)時(shí),解釋器就會(huì)分配內(nèi)存來(lái)存儲(chǔ)這些數(shù)據(jù),當(dāng)JavaScript的解釋器消耗完系統(tǒng)中所有可用的內(nèi)存時(shí),就會(huì)造成系統(tǒng)崩潰。
內(nèi)存泄漏,在某些情況下,不再使用到的變量所占用內(nèi)存沒(méi)有及時(shí)釋放,導(dǎo)致程序運(yùn)行中,內(nèi)存越占越大,極端情況下可以導(dǎo)致系統(tǒng)崩潰,服務(wù)器宕機(jī)。
so,JavaScript有自己的一套垃圾回收機(jī)制,JavaScript的解釋器可以檢測(cè)到什么時(shí)候程序不再使用這個(gè)對(duì)象了(數(shù)據(jù)),就會(huì)把它所占用的內(nèi)存釋放掉。
針對(duì)JavaScript的來(lái)及回收機(jī)制有以下兩種方法(常用):標(biāo)記清除,引用計(jì)數(shù)。
標(biāo)記清除
當(dāng)變量進(jìn)入到執(zhí)行環(huán)境時(shí),垃圾回收器就會(huì)將其標(biāo)記為“進(jìn)入環(huán)境”,當(dāng)變量離開(kāi)環(huán)境時(shí),就會(huì)將其標(biāo)記為“離開(kāi)環(huán)境”。
垃圾回收器在運(yùn)行時(shí)會(huì)給存儲(chǔ)在內(nèi)存中的所有變量都加上標(biāo)記,接著去掉環(huán)境環(huán)境中的變量,和被環(huán)境中的變量所引用的變量的標(biāo)記,在此之后再被加上標(biāo)記的變量將被視為準(zhǔn)備刪除的變量,就是要?jiǎng)h除的變量,垃圾收集器完成內(nèi)存清除工作,銷毀這些帶有的標(biāo)記的值,回收它們所占用的內(nèi)存空間。
引用計(jì)數(shù)
說(shuō)到引用計(jì)數(shù),部分人是不知道是啥的,引用計(jì)數(shù)作為垃圾回收策略的一種,含義是跟蹤記錄每個(gè)值被引用的次數(shù)。
當(dāng)聲明了一個(gè)變量并將一個(gè)引用類型賦值給該變量時(shí),則這個(gè)值的引用次數(shù)就是為1。
相反的,如果該變量的值變成了另外一個(gè),則這個(gè)值的引用次數(shù)減一。(當(dāng)這個(gè)值的引用次數(shù)變?yōu)?的時(shí)候,說(shuō)明沒(méi)有變量在使用,則這個(gè)值沒(méi)法被訪問(wèn)。)---因而就可以將它占用的空間回收起來(lái),這樣垃圾回收器就會(huì)在運(yùn)行的時(shí)候清理引用次數(shù)為0的值占用的空間。
但是引用計(jì)數(shù)存在如果相互引用大量的存在會(huì)導(dǎo)致大量的內(nèi)存泄漏;同時(shí)如果出現(xiàn)循環(huán)引用問(wèn)題也會(huì)導(dǎo)致內(nèi)存泄漏的問(wèn)題。
所以,要減少JavaScript中的垃圾回收,在初始化的時(shí)候新建對(duì)象,然后在后續(xù)過(guò)程中盡量多的重用這些創(chuàng)建好的對(duì)象。我們可以:1. 數(shù)組array優(yōu)化;2. 對(duì)象盡量?jī)?yōu)化;3. 循環(huán)優(yōu)化。
如下內(nèi)存分配方式:
{}?創(chuàng)建一個(gè)新對(duì)象
[]?創(chuàng)建一個(gè)新數(shù)組
funtion(){...}?創(chuàng)建一個(gè)新的方法
new?Foo()?new?關(guān)鍵字,一次內(nèi)存的分配
重復(fù)利用:對(duì)對(duì)象object的優(yōu)化,遍歷此對(duì)象的所有屬性,逐個(gè)刪除屬性,最終將對(duì)象清空為一個(gè)空對(duì)象。
2. 說(shuō)說(shuō)有幾種類型的DOM節(jié)點(diǎn)
嗯,好的,DOM節(jié)點(diǎn)類型有:Document節(jié)點(diǎn),整個(gè)文檔是一個(gè)文檔節(jié)點(diǎn);Element節(jié)點(diǎn),每個(gè)HTML標(biāo)簽是一個(gè)元素節(jié)點(diǎn);Attribute節(jié)點(diǎn),每一個(gè)HTML屬性是一個(gè)屬性節(jié)點(diǎn);Text節(jié)點(diǎn),包含在HTML元素中的文本是文本節(jié)點(diǎn)。
3.在script標(biāo)簽中defer和async屬性的區(qū)別
一般情況下,腳本的下載和執(zhí)行將會(huì)按照文檔的先后順序同步執(zhí)行,當(dāng) 腳本下載和執(zhí)行 的時(shí)候,文檔解析會(huì)被阻塞,在 腳本下載和執(zhí)行 完成之后文檔才會(huì)往下繼續(xù)進(jìn)行解析。
如果script標(biāo)簽中沒(méi)有defer或async屬性,瀏覽器在渲染過(guò)程中遇到script標(biāo)簽時(shí),會(huì)停止渲染來(lái)下載執(zhí)行js代碼,等待js執(zhí)行完畢后,瀏覽器再?gòu)闹袛嗟牡胤交謴?fù)渲染。
你會(huì)知道這樣瀏覽器會(huì)造成阻塞,如果你想要你的項(xiàng)目首屏渲染很快的話,就盡量不要在首屏加載js文件,所以學(xué)習(xí)的時(shí)候會(huì)建議將script標(biāo)簽放在body標(biāo)簽底部。
說(shuō)到defer(延遲執(zhí)行)和async(異步加載)屬性的區(qū)別,下面展示使用script標(biāo)簽有以下三種情況:
?//?瀏覽器會(huì)立即加載并執(zhí)行相應(yīng)的腳本
?//?后續(xù)文檔的加載和渲染與js腳本的加載和執(zhí)行是并行進(jìn)行的
?//?加載后續(xù)文檔的過(guò)程和js腳本的加載是并行進(jìn)行的,js腳本的執(zhí)行需要等到文檔所有元素解析完成之后,DOMContentLoaded事件觸發(fā)執(zhí)行之前
當(dāng)加載的js腳本有多個(gè)的時(shí)候,async是無(wú)順序的加載,而defer是有順序的加載,defer屬性表示延遲執(zhí)行引入的JavaScript,這段JavaScript加載時(shí)HTML并未停止解析,so,defer是不會(huì)阻塞html解析的,它是等Dom加載完后再去執(zhí)行JavaScript代碼的。(當(dāng)html解析過(guò)程中,遇到defer屬性,就會(huì)異步加載該js文件,不會(huì)中斷HTML文檔的解析,當(dāng)整個(gè)HTML解析完成后,回頭再來(lái)解析該js文件)
當(dāng)有defer屬性時(shí),腳本的加載過(guò)程 和 文檔加載 是 異步發(fā)生的,等到 文檔解析 完腳本才開(kāi)始執(zhí)行。 當(dāng)有async屬性時(shí),腳本的加載過(guò)程 和 文檔加載 也是異步發(fā)生的,這里注意的是 腳本下載完成后,會(huì)停止HTML解析,先執(zhí)行腳本,腳本解析完 后繼續(xù)HTML解析。 同時(shí)有async和defer屬性時(shí),執(zhí)行效果與async一致。
defer屬性-是否延遲執(zhí)行腳本,直到頁(yè)面加載為止;async屬性-腳本一旦可用,就異步執(zhí)行。defer屬性并行加載JavaScript文件,會(huì)按照頁(yè)面上的script標(biāo)簽順序執(zhí)行,而async并行加載,下載完成就立即執(zhí)行,不會(huì)按照頁(yè)面上的順序執(zhí)行。
4. 說(shuō)說(shuō)你對(duì)閉包的了解
面試前端,當(dāng)面試官問(wèn)你,談?wù)勀銓?duì)閉包的理解的時(shí)候,該怎么回答呢?
簡(jiǎn)單說(shuō)就是 定義在一個(gè)函數(shù)內(nèi)部的函數(shù),內(nèi)部函數(shù)持有 外部函數(shù) 內(nèi)的變量 或 參數(shù)的引用。內(nèi)部函數(shù)依賴外部函數(shù), 外部函數(shù)參數(shù)和變量 不會(huì)被垃圾回收機(jī)制回收,這些變量會(huì)始終存在于內(nèi)存中。
好處可以讀取函數(shù)內(nèi)部的變量,可以避免全局變量的污染,壞處會(huì)增加內(nèi)存的使用量,容易導(dǎo)致內(nèi)存泄漏,解決方法就是退出函數(shù)前,將不適用的局部變量全部刪除。在JavaScript中,函數(shù)即是閉包,只有函數(shù)才會(huì)產(chǎn)生作用域。
閉包特性,函數(shù)嵌套函數(shù),在函數(shù)內(nèi)部可以引用外部的參數(shù)和變量,參數(shù)和變量不會(huì)被垃圾回收機(jī)制回收。
由于在js中,變量的作用域?qū)儆诤瘮?shù)作用域,在函數(shù)執(zhí)行后,作用域就會(huì)被清理,內(nèi)存也會(huì)被回收,但是由于閉包是建立在一個(gè)函數(shù)內(nèi)部的 子函數(shù),由于子函數(shù)可以訪問(wèn)上級(jí)作用域的原因,即使上級(jí)函數(shù)執(zhí)行完,作用域也不會(huì)隨之銷毀。
在本質(zhì)上,閉包就是將函數(shù)內(nèi)部和函數(shù)外部連接起來(lái)的一座橋梁。
代碼閉包表現(xiàn)形式:
//?作為函數(shù)參數(shù)傳遞
var?a?=?1;
function?foo()?{
?var?a?=?2;
?function?dada()?{
??console.log(a);
?}
?da(dada);
}
function?da(fn)?{
?//?閉包
?fn();
}
foo();?//?輸出2
5. 解釋一下unshift()的方法
unshift()方法可以想數(shù)組開(kāi)頭添加一個(gè)或多個(gè)元素,并返回新的長(zhǎng)度。
arrayObject.unshift(newelement1,newelement2,....,newelementX)
newelement1 必需。向數(shù)組添加的第一個(gè)元素。
newelement2 可選。向數(shù)組添加的第二個(gè)元素。
newelementX 可選??商砑尤舾蓚€(gè)元素。
返回值- arrayObject 的新長(zhǎng)度。
unshift() 方法將把它的參數(shù)插入 arrayObject 的頭部,并將已經(jīng)存在的元素順次地移到較高的下標(biāo)處,以便留出空間。該方法的第一個(gè)參數(shù)將成為數(shù)組的新元素 0,如果還有第二個(gè)參數(shù),它將成為新的元素 1,以此類推。
請(qǐng)注意,unshift() 方法不創(chuàng)建新的創(chuàng)建,而是直接修改原有的數(shù)組。該方法會(huì)改變數(shù)組的長(zhǎng)度。
6. 說(shuō)說(shuō)encodeURI()和decodeURI()的作用是什么
1.encodeURl( )用于將URL轉(zhuǎn)換為十六進(jìn)制編碼。2.decodeURI( )用于將編碼的URL轉(zhuǎn)換回正常URL。
7. 為什么不建議在JavaScript中使用innerHTML
innerHTML內(nèi)容每次刷新,因此很慢。在innerHTML中沒(méi)有驗(yàn)證的余地,因此,更容易在文檔中插入錯(cuò)誤代碼,從而使網(wǎng)頁(yè)不穩(wěn)定。
8. 在DOM操作中怎樣創(chuàng)建,添加,移除,替換,插入,查找節(jié)點(diǎn)
DOM節(jié)點(diǎn)操作方法:
訪問(wèn)、獲取節(jié)點(diǎn)
document.getElementById(id);
//?返回對(duì)擁有指定id的第一個(gè)對(duì)象進(jìn)行訪問(wèn)
document.getElementsByName(name);
//?返回帶有指定名稱的節(jié)點(diǎn)集合
document.getElementsByTagName(tagName);
//?返回帶有指定標(biāo)簽名的對(duì)象集合
document.getElementsByClassName(className);
//?返回帶有指定class名稱的對(duì)象集合
創(chuàng)建節(jié)點(diǎn)/屬性
createDocumentFragment()?//創(chuàng)建一個(gè)DOM片段
document.createElement(eName);?//?創(chuàng)建一個(gè)節(jié)點(diǎn)
document.createAttribute(attrName);?//?對(duì)某個(gè)節(jié)點(diǎn)創(chuàng)建屬性
document.createTextNode(text);?//?創(chuàng)建文本節(jié)點(diǎn)
添加節(jié)點(diǎn)
document.insertBefore(newNode,?referenceNode);?//?在某個(gè)節(jié)點(diǎn)前插入節(jié)點(diǎn)
parentNode.appendChild(newNode);?//?給某個(gè)節(jié)點(diǎn)添加子節(jié)點(diǎn)
復(fù)制節(jié)點(diǎn)
cloneNode(true?|?false);?//?復(fù)制某個(gè)節(jié)點(diǎn)
刪除節(jié)點(diǎn)
parentNode.removeChild(node);?//?刪除某個(gè)節(jié)點(diǎn)的子節(jié)點(diǎn)node是要?jiǎng)h除的節(jié)點(diǎn)
屬性操作
getAttribute(name)?//?通過(guò)屬性名稱獲取某個(gè)節(jié)點(diǎn)屬性的值
setAttribute(name,value);?//?通過(guò)某個(gè)節(jié)點(diǎn)屬性的值
removeAttribute(name);?//?刪除某個(gè)屬性
獲取相鄰的節(jié)點(diǎn)
curtNode.previousSibling;?//?獲取已知節(jié)點(diǎn)的相鄰的上一個(gè)節(jié)點(diǎn)
curtNode.nextSibling;?//?獲取已知節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)
9. 如何實(shí)現(xiàn)瀏覽器內(nèi)多個(gè)標(biāo)簽頁(yè)之間的通信
使用localStorage,使用localStorage.setItem(key,value);添加內(nèi)容
使用storage事件監(jiān)聽(tīng)添加、修改、刪除的動(dòng)作
window.addEventListener("storage",function(event){
?$("#name").val(event.key+"="+event.newValue);
});
$(function(){
???$("#btn").click(function(){
???????var?name?=?$("#name").val();
???????localStorage.setItem("name",?name);
???});
});
10. null和undefined的區(qū)別是什么
console.log(null==undefined)//true
console.log(null===undefined)//false
null:Null類型,代表“空值”,代表一個(gè)空對(duì)象指針
undefined:Undefined類型,當(dāng)一個(gè)聲明了一個(gè)變量未初始化時(shí),得到的是undefined
undefined表示“缺少值”,此處應(yīng)該有一個(gè)值,但是還沒(méi)有定義。

null表示“沒(méi)有對(duì)象”,該處不應(yīng)該有值。

11. new操作符的作用是什么
new操作符首先,創(chuàng)建了一個(gè)空對(duì)象:
var?obj?=?new?Object();
設(shè)置原型鏈:
obj._proto_?=?Object.prototype

示例代碼了解new的作用:
function?da(name)?{
?this.name?=?name;
}
da.prototype.sayName?=?function()?{
?console.log(this.name);
}
const?jeskson?=?new?da('dada');
console.log(jeskson.name);?//?dada
jeskson.sayName();?//?dada
由例子得出:
new 通過(guò)構(gòu)造函數(shù) da 創(chuàng)建出來(lái)的實(shí)例可以訪問(wèn)到構(gòu)造函數(shù)中的屬性
new 通過(guò)構(gòu)造函數(shù) da 創(chuàng)建出來(lái)的實(shí)例可以訪問(wèn)到構(gòu)造函數(shù)原型鏈中的屬性,(通過(guò)new操作符,實(shí)例與構(gòu)造函數(shù)通過(guò)原型鏈連接了起來(lái))
如果給構(gòu)造函數(shù)一個(gè)return返回值,(沒(méi)有顯式的return任何值,默認(rèn)返回undefined)
function?da(name)?{
?this.name?=?name;
?return?1;
}
const?jeskson?=?new?da('dada');
console.log(jeskson.name);?//?dada
這個(gè)返回值沒(méi)有任何的用處,構(gòu)造函數(shù)如果返回原始值,這個(gè)返回值沒(méi)有意義。
function?da(name)?{
?this.name?=?name;
?console.log(this);?//?da?{name:?'dada'}
?return?{age:1}
}
const?jeskson?=?new?da('dada');
console.log(jeskson);?//?{age:1}
console.log(jeskson.name);?//?undefined
構(gòu)造函數(shù)如果返回值為對(duì)象,那么這個(gè)返回值就會(huì)被正常使用。
new 操作符會(huì)返回一個(gè)對(duì)象 這個(gè)對(duì)象,也就是構(gòu)造函數(shù)中的this,可以訪問(wèn)到掛載在this上的任意屬性 這個(gè)對(duì)象可以訪問(wèn)到構(gòu)造函數(shù)原型上的屬性 返回原始值會(huì)忽略,返回對(duì)象會(huì)正常處理
12. JavaScript延遲加載的方式有哪些
js的延遲加載有助于提高頁(yè)面的加載速度
延遲有:defer屬性,async屬性,動(dòng)態(tài)創(chuàng)建DOM方式,使用JQuery的getScript方法,使用setTimeout延遲方法,讓JS最后加載。
使用setTimeout延遲方法
13. call()和apply()的區(qū)別和作用是什么
call(), applay() 都屬于Function.prototype的一個(gè)方法,它是JavaScript引擎內(nèi)實(shí)現(xiàn)的,屬于Function.prototype,所以每個(gè)Function對(duì)象實(shí)例,每個(gè)方法都有call,apply屬性。
call()和apply() ,它們的作用都是相同的,不同的在于,它們的參數(shù)不同。
call(this,?arg1,?arg2,?arg3);
apply(this,?arguments);
function?add(a,b){
?console.log(a+b);
}
function?sub(a,b){
?console.log(a-b);
}
add.call(sub,?2,?1);
add.apply(sub,?[2,1]);
對(duì)于A.applay(B)或A.call(B),簡(jiǎn)單地說(shuō),B先執(zhí)行,執(zhí)行后根據(jù)結(jié)果去執(zhí)行A,用A去執(zhí)行B的內(nèi)容代碼,再執(zhí)行自己的代碼。
var?f1?=?function(a,b)?{
?console.log(a+b);
}
var?f2?=?function(a,b,c)?{
?console.log(a,b,c);
}
f2.apply(f1,[1,2])?//?1?2?undefined
解析一下就是,先執(zhí)行f1,f1執(zhí)行后,這里注意f1是f1,不是f1()執(zhí)行方法,所以里面的console.log等內(nèi)容代碼并沒(méi)有執(zhí)行,相等于,初始化了代碼f1,由于沒(méi)有返回值,結(jié)果是undefined,f2執(zhí)行的時(shí)候this指向window。參數(shù)中為[1,2],解析后參數(shù)為1,2,undefined;執(zhí)行f2方法后,打印出結(jié)果值為:1 2 undefined
A.call(B, 1,2,3) 后面的參數(shù)都是獨(dú)立的參數(shù)對(duì)象,會(huì)被自動(dòng)解析為A的參數(shù):
var?f1?=?function(a,b)?{
?console.log(a+b);
}
var?f2?=?function(a,b,c)?{
?console.log(a,b,c);
}
f2.call(f1,[1,2]);?//?[1,2]?undefined?undefined
f2.call(f1,?1,?2);?//?1?2?undefined
解析一下就是,參數(shù)中的[1,2],因?yàn)閭魅肓艘粋€(gè)數(shù)組,相當(dāng)于只傳入了第一個(gè)參數(shù),b和c參數(shù)沒(méi)有傳。
使用apply()和call():
?//apply用法
?var?arr?=?new?Array(1,2,3)
?var?arr1?=?new?Array(11,21,31)
?Array.prototype.push.apply(arr,arr1)
?console.log(arr)//[1,?2,?3,?11,?21,?31]
?
?//call用法
?var?arr?=?new?Array(1,2,3)
?var?arr1?=?new?Array(11,21,31)
?Array.prototype.push.call(arr,arr1[0],arr1[1],arr1[2])
?console.log(arr)//[1,?2,?3,?11,?21,?31]
數(shù)組利用Math求最大和最小值
?//apply的用法
?var?_maxNum?=?Math.max.apply(null,[1,3,2,4,5])
?console.log(_maxNum)//5
?var?_minNum?=?Math.min.apply(null,[1,3,2,4,5])
?console.log(_minNum)//1
?
?//call的用法
?var?_maxNum?=?Math.max.call(null,1,3,2,4,5)
?console.log(_maxNum)//5
?var?_minNum?=?Math.min.call(null,1,3,2,4,5)
?console.log(_minNum)//1
one總結(jié):Function.prototype.apply和Function.prototype.call的作用是一樣的,區(qū)別在于傳入?yún)?shù)的不同;第一個(gè)參數(shù)都是指定函數(shù)體內(nèi)this的指向;第二個(gè)參數(shù)就不同了,apply是傳入帶下標(biāo)的集合,數(shù)組或者類數(shù)組,apply把它傳給函數(shù)作為參數(shù),call從第二個(gè)開(kāi)始傳入的參數(shù)是不固定的,都會(huì)傳給函數(shù)作為參數(shù)。call比applay的性能要好,平常多用call。
two總結(jié):尤其是es6引入了Spread operator延展操作符后,即使參數(shù)是數(shù)組,可以使用call了。
let?params?=?[1,2,3,4,5];
dada.call(obj,?...?params);
傳入的第一個(gè)參數(shù)為 null, 函數(shù)體內(nèi)的 this 會(huì)指向默認(rèn)的宿主對(duì)象, 在瀏覽器中則是 window
var?func?=?function(?a,?b,?c?){?
????console.log(this?===?window);?//?輸出:true
};
func.apply(?null,?[?1,?2,?3?]?);
//?在嚴(yán)格模式下,函數(shù)體內(nèi)的?this?還是為?null
var?func?=?function(?a,?b,?c?){?
????"use?strict";
????console.log(this?===?null);?//?輸出:true
};
func.apply(?null,?[?1,?2,?3?]?);
改變this指向
var?obj1={?
????name:?'dada'
};
var?obj2={?
????name:?'da'
};
window.name?=?'window';
var?getName?=?function(){?
????console.log?(?this.name?);
};
getName();?//?輸出:?window
getName.call(?obj1?);//?輸出:?dada
getName.call(obj2?);?//?輸出:?da
document.getElementById(?'div1'?).onclick?=?function(){
????console.log(?this.id?);//?輸出:?div1
????var?func?=?function(){?
????????console.log?(?this.id?);//?輸出:?undefined
????}?
????func();
};?
//修正后
document.getElementById(?'div1'?).onclick?=?function(){
????var?func?=?function(){?
????????console.log?(?this.id?);//?輸出:?div1
????}?
????func.call(this);
};?
14. 哪些操作會(huì)造成內(nèi)存泄漏

15. 說(shuō)說(shuō)JavaScript對(duì)象的幾種創(chuàng)建方式
工廠模式,創(chuàng)建方式
function?createPerson(name,age,job){
????var?o?=?new?Object();
????o.name=name;
????o.age=age;
????o.job=job;
????o.sayName?=?function(){
????????alert(this.name);
????}
}
var?person1?=?createPerson("da",1,"it");
var?person2?=?createPerson("dada",2,"it");
構(gòu)造函數(shù)模式
function?Person(name,age,ob){
????this.name=name;
????this.age=age;
????this.job=job;
????this.sayName?=?function(){
????????alert(this.name);
????}
var?person1?=?new?Person("dada",1,"web");
var?person2?=?new?Person("dada",2,"web");
}
使用原型模式:
function?Person(){
}
Person.prototype.name?=?"da";
Person.prototype.age?=?1;
Person.prototype.job?=?"web";
Person.prototype.sayName?=?function(){
????alert(this.name);
}
?
var?person1?=?new?Person();
person1.sayName();????//"dada"
?
var?person2?=?new?Person();
person2.sayName();????//"dada"
?
alert(person1.sayName?==?person2.sayName);???//true
組合使用構(gòu)造函數(shù)模式和原型模式
function?Person(name,age){
????this.name?=?name;
????this.age?=?age;
????this.friends?=?["da","dada"];
}
Person.prototype?=?{
????constructor:Person,
????sayName:function(){
????????alert(this.name);
????}
}
var?person1?=?new?Person("da1",1);
var?person2?=?new?Person("da2",2);
person1.friends.push("dadada");
console.log(person1.friends);????//["da","dada","dadada"]
console.log(person2.friends);????//["da","dada"]
console.log(person1.friends?===?person2.friends);????//false
console.log(person1.sayName?===?person2.sayName);???//true
動(dòng)態(tài)原型模式
function?Person(name,age,job){
????this.name=name;
????this.age=age;
????this.job=job;
????if(typeof?this.sayName!="function"){
????????Person.prototype.sayName=function(){
????????????alert(this.name);
????????};
????}
}
JavaScript對(duì)象的創(chuàng)建方式,1,Object構(gòu)造函數(shù)式,2,對(duì)象字面量式,3,工廠模式,4,安全工廠模式,5,構(gòu)造函數(shù)模式,6,原型模式,7,混合構(gòu)造函數(shù)和原型模式,8,動(dòng)態(tài)原型模式,9,寄生構(gòu)造函數(shù)模式,10,穩(wěn)妥構(gòu)造函數(shù)模式。
16. 如何實(shí)現(xiàn)異步編程
學(xué)習(xí)使用異步很重要,在瀏覽器端,耗時(shí)很長(zhǎng)的操作都應(yīng)該異步執(zhí)行,避免瀏覽器失去響應(yīng),最好的例子是ajax操作。

簡(jiǎn)單的promise對(duì)象的構(gòu)造函數(shù)的結(jié)構(gòu):
var?Promise?=?function()?{
?this.callbacks?=?[];?//?用于管理回調(diào)函數(shù)
}
Promise.prototype?=?{
?construct:?Promise,
?resolve:?function(result)?{?//?請(qǐng)求成功時(shí)執(zhí)行的方法
?},
?reject:?function(result)?{?//?請(qǐng)求失敗時(shí)執(zhí)行的方法
?},
?complete:?function(type,?result)?{?//?執(zhí)行回調(diào)
?},
?then:?function(successHandler,?failedHandler)?{?//?綁定回調(diào)函數(shù)
?}
}
對(duì)于回調(diào)函數(shù),好處是簡(jiǎn)單,容易理解,但是缺點(diǎn)在于代碼的閱讀和維護(hù),各個(gè)部分之間高度耦合,流程也會(huì)很亂,每個(gè)任務(wù)只能指定一個(gè)回調(diào)函數(shù),稱之為:回調(diào)地獄。
//?同步操作變成異步操作
f1();
f2();
function?f1(callback)?{
?setTimeout(function()?{
??callback();
?},1000);
}
f1(f2);
事件監(jiān)聽(tīng)(采用事件驅(qū)動(dòng)模式,任務(wù)的執(zhí)行不取決于代碼的順序,而取決于某個(gè)事件是否發(fā)生)示例如下:
$('#clickBtn').on('click',function(e){console.log('xxx');}
f1.on('dada',?f2);
function?f1()?{
?setTimeout(function()?{
??f1.trigger('dada');
?},1000);
}
//?f1.trigger('dada')表示執(zhí)行完成后,立即觸發(fā)dada事件,然后開(kāi)始執(zhí)行f2
對(duì)于事件監(jiān)聽(tīng),可綁定多個(gè)事件,而且每個(gè)事件可以指定多個(gè)回調(diào)函數(shù),可以“去耦合”,有利于實(shí)現(xiàn)模塊化,缺點(diǎn)就是整個(gè)程序都要編程事件驅(qū)動(dòng)型,運(yùn)行流程會(huì)變得很不清晰。
對(duì)于采用發(fā)布,訂閱方式,和“事件監(jiān)聽(tīng)”類似。(發(fā)布/訂閱)
對(duì)于使用Promise對(duì)象實(shí)現(xiàn),每一個(gè)異步任務(wù)返回一個(gè)Promise對(duì)象,該對(duì)象有一個(gè)then方法,允許指定回調(diào)函數(shù)。
17. 說(shuō)說(shuō)JavaScript的同源策略
同源策略的目的是為了防止某個(gè)文檔或腳本從多個(gè)不同源裝載,同源策略是指,協(xié)議,域名,端口相同。同源策略是一種安全協(xié)議,指一段腳本只能讀取來(lái)自同一來(lái)源的窗口和文檔的屬性。
18. 說(shuō)一下為啥要有同源限制
有同源限制可以放置黑客盜取信息。
19. 在JavaScript中,為啥說(shuō)函數(shù)是第一類對(duì)象
函數(shù)是第一類對(duì)象:
這些函數(shù)可以作為參數(shù)傳遞給其他函數(shù),作為其他函數(shù)的值返回,分配給變量,也可以存儲(chǔ)在數(shù)據(jù)結(jié)構(gòu)中。
如果公民分等級(jí),一等公民什么都可以做,次等公民這不能做那不能做。JavaScript的函數(shù)也是對(duì)象,可以有屬性,可以賦值給一個(gè)變量,可以放在數(shù)組里作為元素,可以作為其他對(duì)象的屬性,什么都可以做,別的對(duì)象能做的它能做,別的對(duì)象不能做的它也能做。這不就是一等公民的地位嘛。
20. 函數(shù)聲明與函數(shù)表達(dá)式的區(qū)別
函數(shù)聲明:
foo();?//?在函數(shù)聲明之后調(diào)用 foo,可以正常調(diào)用。因?yàn)?foo 被提前到最前面定義了。
function?foo()?{
???return?true;
}
調(diào)用:
函數(shù)名(參數(shù))
函數(shù)名.call(函數(shù)名,參數(shù))
函數(shù)名.apply(函數(shù)名,[參數(shù)])
new?函數(shù)名(參數(shù))
定時(shí)器
把函數(shù)聲明變成函數(shù)表達(dá)式再調(diào)用
ES6里的模版字符串
函數(shù)表達(dá)式:
foo();?//?在函數(shù)表達(dá)式之前調(diào)用函數(shù),報(bào)錯(cuò)。因?yàn)檫@時(shí)候還沒(méi)有 foo 這個(gè)變量。
var?foo?=?function()?{
???return?foo;
};
調(diào)用
函數(shù)名(參數(shù))
函數(shù)名.call(函數(shù)名,參數(shù))
函數(shù)名.apply(函數(shù)名,[參數(shù)])
new?函數(shù)名(參數(shù))
直接在后面加上一對(duì)小括號(hào)
定時(shí)器
ES6里的模版字符串
以被賦值的形式出現(xiàn)(根據(jù)具體形式調(diào)用)
在向執(zhí)行環(huán)境中加載數(shù)據(jù)時(shí),解析器對(duì)函數(shù)聲明和函數(shù)表達(dá)式不一樣的,解析器首先讀取讀取函數(shù)聲明,并使它在執(zhí)行任何代碼之前可用,對(duì)于函數(shù)表達(dá)式,就需要等到解析器執(zhí)行到它所在的代碼行。
JavaScript解釋器中存在一種變量聲明被提升的機(jī)制,也就是說(shuō)函數(shù)聲明會(huì)被提升到作用域的最前面,即使寫代碼的時(shí)候是寫在最后面,也還是會(huì)被提升至最前面。
var?getName?//?變量被提升,此時(shí)為undefined
getName()?//?dada?函數(shù)被提升
var?getName?=?function()?{
?console.log('da')
}
//?函數(shù)表達(dá)式此時(shí)才開(kāi)始覆蓋函數(shù)聲明的定義
getName()?//?da
function?getName()?{
?console.log('dada')
}
getName()?//?da
在JavaScript中定義一個(gè)函數(shù)有四種方式
1.?函數(shù)聲明
2.?函數(shù)表達(dá)式
3.?ES6里箭頭函數(shù)
4.?new?Function()
ES5 規(guī)定,函數(shù)只能在頂級(jí)作用域和函數(shù)作用域中聲明,否則是不合法的。 ES6 引入了塊級(jí)作用域的概念,這種定義方法就被允許了。
21. 如何刪除一個(gè)cookie
代碼如下:
document.cookie?=?'user=jeskson;expires='+new?Date(0);
22. 寫一下一個(gè)方法,求字符串的長(zhǎng)度
一個(gè)英文字符 占用一個(gè)字節(jié),一個(gè)中文 字符占用兩個(gè)字節(jié)
function?byte(str)?{
?var?bytes?=?str.length;
?for(var?i=0;?i??if(str.charCodeAt(i)>255)?{
???bytes++;
??}
?}
?return?bytes
}
console.log(byte('dada'));
23. attribute和property的區(qū)別是什么
attribute是dom元素在文檔中作為HTML標(biāo)簽擁有的屬性,property就是dom元素在JavaScript中作為對(duì)象擁有的屬性。
attribute特性,property屬性。
24. 延遲腳本在JavaScript中有什么作用
默認(rèn)情況下,在頁(yè)面加載期間,HTML 代碼的解析將暫停,知道腳本停止執(zhí)行。如果服務(wù)器速度較慢或者腳本特別沉重,會(huì)導(dǎo)致網(wǎng)頁(yè)延遲,在使用Deferred時(shí),腳本會(huì)延遲執(zhí)行直到HTML解析器運(yùn)行。這減少了網(wǎng)頁(yè)加載時(shí)間,并且它們的顯示速度更快。
25. 說(shuō)說(shuō)什么是閉包,閉包的優(yōu)缺點(diǎn)是什么
function?outer()?{
?var?a?=?'變量1'
?var?inner?=?function()?{
??console.info(a);
}
return?inner;?//?inner就是一個(gè)閉包函數(shù),因?yàn)樗茉L問(wèn)到outer函數(shù)的作用域
}
在JavaScript中的一大特點(diǎn)就是閉包,很多高級(jí)應(yīng)用都要依靠閉包來(lái)實(shí)現(xiàn)。由于閉包會(huì)使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大的,所以不要亂濫用閉包,否則會(huì)導(dǎo)致頁(yè)面的性能問(wèn)題,在IE中可能會(huì)導(dǎo)致內(nèi)存泄漏,所以可以在退回函數(shù)前,將不使用的局部變量全部刪除。
26. 判斷一個(gè)對(duì)象是否屬于某個(gè)類
instanceof關(guān)鍵字,判斷一個(gè)對(duì)象是否是類的實(shí)例化對(duì)象 constructor屬性,判斷一個(gè)對(duì)象是否是類的構(gòu)造函數(shù)
27. 你知道有個(gè)函數(shù),執(zhí)行直接對(duì)象查找時(shí),它始終不會(huì)查找原型,這是什么函數(shù)
hasOwnProperty
28. document.write和innerHTML的區(qū)別
document.write會(huì)重繪整個(gè)頁(yè)面 innerHTML可以重繪頁(yè)面的一部分
效果動(dòng)態(tài)圖:
29. 在JavaScript中讀取文件的方法是什么
讀取服務(wù)器中的文件內(nèi)容
function?readAjaxFile(url)?{
?//?創(chuàng)建xhr
?var?xhr?=?new?XMLHttpRequest();
?//?監(jiān)聽(tīng)狀態(tài)
?xhr.onreadystatechange?=?function()?{
??//?監(jiān)聽(tīng)狀態(tài)值
??if(xhr.readyState?===?1?&&?xhr.status?===?200)?{
???console.log(xhr.responseTest)
??}
?}
?//?打開(kāi)請(qǐng)求
?xhr.open('GET',?url,?true)
?//?發(fā)送數(shù)據(jù)
?xhr.send(null)
}
讀取本地計(jì)算機(jī)中的內(nèi)容
function?readInputFile(id)?{
?var?file?=?document.getElementById(id).files[0];
?//?實(shí)例化
?var?reader?=?new?FileReader();
?//?讀取文件
?reader.readAsText(file)
?//?監(jiān)聽(tīng)返回
?reader.onload?=?function(data)?{
??console.log(data,?this.result);
?}
}
30. 如何分配對(duì)象屬性
document.form.action?=?'submit';
31. 常用的JavaScript語(yǔ)句基本規(guī)范
不要在同一行聲明多個(gè)變量 使用對(duì)象字面量替代new Array這種形式 不要使用全局函數(shù) switch語(yǔ)句必須帶有default分支 函數(shù)不應(yīng)該有時(shí)有返回值,有時(shí)沒(méi)有返回值 for循環(huán)必須使用大括號(hào)括起來(lái) if語(yǔ)句必須使用大括號(hào)括起來(lái) 寫注釋 命名規(guī)則,構(gòu)造器函數(shù)首字母大寫
32. eval的功能是什么
eval的功能是把對(duì)應(yīng)的字符串解析成JavaScript代碼并運(yùn)行。但是應(yīng)該避免使用eval,使用它可能會(huì)造成程序不安全,影響性能因要一次解析成JavaScript語(yǔ)句,一次執(zhí)行。
33. 如下執(zhí)行結(jié)果:
["1","2","3"].map(parseInt)
[1,NaN,NaN]因parseInt需要兩個(gè)參數(shù)val,radix,其中radix表示解析時(shí)用的基數(shù),map傳遞了3個(gè)參數(shù)item, index, array,對(duì)應(yīng)的radix不合法導(dǎo)致解析失敗。
34. 說(shuō)說(shuō)this對(duì)象的理解
this指的是調(diào)用函數(shù)的那個(gè)對(duì)象,一般情況下,this是全局對(duì)象Global,可以作為方法調(diào)用。this隨著函數(shù)的使用場(chǎng)合的不同,this的值會(huì)發(fā)生變化。
this是誰(shuí)調(diào)用就指向誰(shuí),在全局環(huán)境里,指向的是window對(duì)象。
var?name?=?'jeskson';
function?person()?{
?return?this.name;
}
console.log(this.name);?//?jeskson
console.log(window.name);?//?jeskson
console.log(person());?//?jeskson
局部環(huán)境:
var?name?=?"jeskson";
function?person()?{
?console.log(this.name);
}
person();?//?jeskson
var?obj?=?{
?name:?"dada",
?person:?function()?{
??console.log(this.name);
?}
}
obj.person();?//?dada
構(gòu)造函數(shù)內(nèi)使用this
function?Person(name)?{
?this.name?=?name;
?return?name;
}
console.log(new?Person('jeskson').name);?//?jeskson
使用apply和call函數(shù)改變this的指向
function?person()?{
?return?this.name;
}
var?obj?=?{
?name:?'jeskson'
}
console.log(person.call(obj));?//?jeskson
console.log(person.apply(obj));?//?jeskson
對(duì)象函數(shù)調(diào)用,哪個(gè)對(duì)象調(diào)用就指向哪個(gè)對(duì)象
type="button"?id="btnDa"?value="dada">
使用new實(shí)例化對(duì)象,在構(gòu)造函數(shù)中的this指向?qū)嵗瘜?duì)象
var?show?=?function()?{
?this.myName="jeskson";?///?this指向的是obj對(duì)象
}
var?obj?=?new?show();
35. 在JavaScript中什么是類(偽)數(shù)組,如何將類(偽)數(shù)組轉(zhuǎn)換為標(biāo)準(zhǔn)數(shù)組
典型的類(偽)數(shù)組是函數(shù)的argument參數(shù),在調(diào)用 getElementsByTagName和document.childNodes方法時(shí),它們返回的NodeList對(duì)象都屬于偽數(shù)組。可以使用 Array.prototype.slice.call(fakeArray)將數(shù)組轉(zhuǎn)化為真正的Array對(duì)象。
什么是偽數(shù)組,是能通過(guò)Array.prototype.slice轉(zhuǎn)換為真正的數(shù)組的帶有length屬性的對(duì)象。
//?標(biāo)準(zhǔn)的有偽數(shù)組對(duì)象
var?da?=?{?0:?'a',?1:?'b',?length:?2};
var?dada?=?Array.prototype.slice.call(da);
console.log(da[0]);?//?a
var?dadada?=?[].slice.call(dada);
console.log(da[0]);?//?a
偽數(shù)組:就是無(wú)法使用數(shù)組的方法和api,但任然可以使用便利數(shù)組的方式遍歷他們。
一個(gè)偽數(shù)組Array.prototype.slice.call()進(jìn)行轉(zhuǎn)換為一個(gè)真正的數(shù)組
36. JavaScript中的callee和caller的作用是什么
caller返回一個(gè)關(guān)于函數(shù)的引用,該函數(shù)調(diào)用了當(dāng)前函數(shù) callee返回正在執(zhí)行的函數(shù),也就是指定的function對(duì)象的正文
caller是JavaScript函數(shù)類型的一個(gè)屬性,它引用調(diào)用當(dāng)前函數(shù)的函數(shù); callee則不是函數(shù)對(duì)象的屬性,它是函數(shù)上下文中arguments對(duì)象的屬性。
37. 統(tǒng)計(jì)字符串中字母的個(gè)數(shù)或統(tǒng)計(jì)最多的字母:
aaaabbbccccddhgddada
function?dealStr(str)?{
?var?obj?=?{};
?for(var?i?=?0;?i??var?v?=?str.charAt(i);
??if(obj[v]?&&?obj[v].value?===?v)?{
???++obj[v].count
??}else{
???obj[v]?=?{
????count:?1,
????value:?v
???}
??}
?}
?return?obj;
}
var?obj?=?dealStr(str);
for(key?in?obj)?{
?console.log(obj[key].value+'='+obj[key].count);
}
38. 寫一個(gè)函數(shù),清除字符串前后的空格
function?trim(str)?{
????if?(str?&&?typeof?str?===?"string")?{
????????return?str.replace(/(^\s*)|(\s*)$/g,"");?//去除前后空白符
????}
}
39. 寫一個(gè)函數(shù)實(shí)現(xiàn)一個(gè)數(shù)組合并的方法
for循環(huán)數(shù)組
var?arr3?=?[];
//?遍歷arr1
for?(var?i?=?0;?i???arr3.push(arr1[i]);
}
//?遍歷arr2
for?(var?j?=?0;?j???arr3.push(arr2[j]);
}
console.log(arr3);?//?[1,2,3,4,5,6]
concat()方法:concat()方法,作用是連接兩個(gè)或更多的數(shù)組,并返回一個(gè)新的數(shù)組。
var?arr3?=?arr1.concat(arr2);
console.log(arr3);?//?[1,2,3,4,5,6]
apply()方法
arr1.push.apply(arr1,?arr2);
40. 工作中,常用的邏輯運(yùn)算符有哪些
&&運(yùn)算符||運(yùn)算符!運(yùn)算符
41. 什么是事件代理(事件委托)
事件代理,又稱為事件委托,就是把原本需要綁定的事件委托給父元素,讓父元素負(fù)責(zé)事件監(jiān)聽(tīng),事件代理的原理是DOM元素的事件冒泡,使用事件代理的好處是提高性能。
42. 什么是未聲明和未定義的變量
未聲明的變量出現(xiàn)中不存在且未聲明的變量。如果程序嘗試讀取未聲明變量的值,則會(huì)遇到運(yùn)行時(shí)錯(cuò)誤。
xxx?is?not?defined
未定義的變量是在程序中聲明但尚未給出任何值的變量。如果程序嘗試讀取未定義變量的值,則返回未定義的值。
已經(jīng)通過(guò)var指令聲明,但是沒(méi)有賦值,沒(méi)有定義類型,所以會(huì)打印undefined未定義
43. 什么是全局變量,這些變量如何聲明,使用全局變量有哪些問(wèn)題
全家變量是整個(gè)代碼中都可用的變量,這些變量沒(méi)有任何作用域。var關(guān)鍵字用于聲明局部變量或?qū)ο?,如果省略var關(guān)鍵字,則聲明一個(gè)全局變量。
使用全局變量所面臨的問(wèn)題是局部變量和全局變量名稱的沖突,很難調(diào)試和測(cè)試依賴于全局變量的代碼。
44. 常用的定時(shí)器工作說(shuō)明,使用定時(shí)器的缺點(diǎn)
setTimeout(function,delay)函數(shù)用于啟動(dòng)在所屬延遲之后調(diào)用特定功能的定時(shí)器。setInterval(function,delay)函數(shù)用于在提到的延遲中重復(fù)執(zhí)行給定的功能,只有在取消時(shí)才停止。clearInterval(id)函數(shù)指示定時(shí)器停止。
45. 說(shuō)說(shuō)ViewState和SessionState有什么區(qū)別
ViewState用于會(huì)話中的頁(yè)面 SessionState用于Web應(yīng)用程序中的所有頁(yè)面上訪問(wèn)的用戶特定數(shù)據(jù)
46. 什么是===運(yùn)算符
===為嚴(yán)格等式運(yùn)算符,只有當(dāng)兩個(gè)操作數(shù)具有相同的值和類型時(shí),,才會(huì)返回true
47. JavaScript中的循環(huán)結(jié)構(gòu)有哪些
for,?while,?do...while,?for_in,?for?of?(es6新增)
while(條件表達(dá)式語(yǔ)句)
{
????執(zhí)行語(yǔ)句塊;
}
do
{
????執(zhí)行語(yǔ)句塊;
}
while(條件表達(dá)式語(yǔ)句);
for(初始化表達(dá)式;循環(huán)條件表達(dá)式;循環(huán)后的操作表達(dá)式)
{
????執(zhí)行語(yǔ)句塊;
}
48. 在JavaScript中的null表示什么
null 用于表示無(wú)值或無(wú)對(duì)象,表示沒(méi)有對(duì)象或空字符串,沒(méi)有有效的布爾值,沒(méi)有數(shù)值和數(shù)組對(duì)象。
49. delete操作符的功能有什么
delete操作符用于刪除對(duì)象中的某個(gè)屬性,但是不能刪除變量,函數(shù)等。
????var?obj?=?{
????????name:?'jeskson'
????}
????console.log(obj.name);//'jeskson'
????delete?obj.name;
????console.log(obj.name);//undefined
50. 在JavaScript中有哪些類型的彈出框
alert, confirm, prompt
51. 常見(jiàn)的void(0)的作用是什么
其作用是用于防止頁(yè)面刷新,并在調(diào)用時(shí)傳遞參數(shù)“0”;用于調(diào)用另一種方法而不刷新頁(yè)面
52. 什么是JavaScript cookie
cookie是一些數(shù)據(jù),存儲(chǔ)你電腦上的文本文件中,當(dāng)web服務(wù)器向?yàn)g覽器發(fā)送web頁(yè)面時(shí),在連接關(guān)閉后,服務(wù)端不會(huì)記錄用戶的信息。
Cookie的形式,Cookie是由name=value形式成對(duì)存在的,Cookie字符串必須以分號(hào)作為結(jié)束符,Cookie除了name屬性之外還存在其他4個(gè)相關(guān)屬性。
設(shè)置Cookie的語(yǔ)法如下:?set-Cookie:name=value;[expires=date];[path=dir];[domain=domainn];[secure]
53. 解釋JavaScript中的pop()方法
pop()方法將最后一個(gè)元素從給定的數(shù)組中取出并返回
var?da?=?[?1,?2,?3];
da.pop();
//?da:?[1,2]
54. 在JavaScript中,datatypes的兩個(gè)基本組是什么
datatypes的兩個(gè)基本組是 原始類型和引用類型。
55. typeof是用來(lái)做什么的
typeof是一個(gè)運(yùn)算符,用于返回變量類型的字符串描述。
56. 在JavaScript中,push方法的作用是什么
push方法是將一個(gè)或多個(gè)元素添加或附加到數(shù)組的末尾。
57. 在JavaScript中,unshift方法的作用是什么
unshift方法是將一個(gè)或多個(gè)元素添加到數(shù)組的開(kāi)頭。
58. 如何為對(duì)象添加屬性
為對(duì)象添加屬性的方法,常用兩種:
中括號(hào)語(yǔ)法 點(diǎn)語(yǔ)法
59. 說(shuō)說(shuō)window.onload和onDocumentReady
在將頁(yè)面加載到瀏覽器中時(shí),這兩個(gè)功能都可以用來(lái)執(zhí)行任務(wù),但是它們?cè)趫?zhí)行方式和執(zhí)行時(shí)間方面存在細(xì)微的差異。
當(dāng)瀏覽器加載DOM樹(shù)和所有其他資源(例如圖像,對(duì)象等)時(shí),“ window.onload”將執(zhí)行代碼。
onDocumentReady在構(gòu)建DOM樹(shù)時(shí)執(zhí)行,而無(wú)需等待其他資源加載。這樣可以使用onDocumentReady更快地針對(duì)DOM執(zhí)行代碼。
另一個(gè)區(qū)別是window.onload與跨瀏覽器不兼容,而使用類似jQuery的document.ready()則可以在所有瀏覽器上很好地工作。
60. 說(shuō)說(shuō)for-in循環(huán)
用于循環(huán)對(duì)象的屬性:
for?(var?item?in?object
61. 說(shuō)說(shuō)JavaScript中的匿名函數(shù)
被聲明為沒(méi)有任何命名標(biāo)識(shí)符的函數(shù),一般來(lái)說(shuō),匿名函數(shù)在聲明后無(wú)法訪問(wèn)。
var?da?=?function()?{
?console.log('dadaqianduan.cn')
}
da();
62. 說(shuō)說(shuō)一下事件冒泡
單擊子級(jí)的處理程序,父級(jí)的處理程序也將執(zhí)行同樣的工作。
對(duì)事件冒泡機(jī)制的理解?
事件流的執(zhí)行順序,捕獲階段-》目標(biāo)階段-》冒泡階段。冒泡從里到外的執(zhí)行。在div上定義的事件,點(diǎn)擊span的時(shí)候會(huì)觸發(fā)span上面綁定的事件,之后也會(huì)觸發(fā)外面div上面的事件,這就是冒泡。
冒泡階段是從目標(biāo)到window對(duì)象的過(guò)程。事件默認(rèn)是冒泡的,當(dāng)父元素添加監(jiān)聽(tīng)事件,點(diǎn)擊子元素后,父元素上的事件會(huì)被觸發(fā),這就是典型的冒泡。
63. JavaScript里函數(shù)參數(shù)arguments是數(shù)組嗎
它只是一個(gè)類數(shù)組對(duì)象,并沒(méi)有數(shù)組的方法。
64. 什么是構(gòu)造函數(shù),它與普通函數(shù)有什么區(qū)別
構(gòu)造函數(shù)是用來(lái)創(chuàng)建對(duì)象時(shí)初始化對(duì)象,與new一起試用,創(chuàng)建對(duì)象的語(yǔ)句中構(gòu)造函數(shù)的名稱必須與類名完全相同。
構(gòu)造函數(shù)只能由new關(guān)鍵字調(diào)用 構(gòu)造函數(shù)可以創(chuàng)建實(shí)例化對(duì)象 構(gòu)造函數(shù)是類的標(biāo)志
65. 說(shuō)說(shuō)split()與join()函數(shù)的區(qū)別
split()方法是用來(lái)切割成數(shù)組的形式join()方法是將數(shù)組轉(zhuǎn)換成字符串
"abcdef".split("")???//??["a",?"b",?"c",?"d",?"e",?"f"]
"abcdef".split()????//?["abcdef"]
"2:3:4:5".split(":",3)??//??["2",?"3",?"4"]
[1,2,3,4,5].join()???//?"1,2,3,4,5"
[1,2,3,4,5].join(':')??//?"1:2:3:4:5"
66. 說(shuō)說(shuō)你對(duì)原型鏈, prototype的理解
JavaScript的每個(gè)對(duì)象都繼承另一個(gè)父級(jí)對(duì)象,父級(jí)對(duì)象稱為原型(prototype)對(duì)象。
原型鏈幾乎是前端面試的必問(wèn)題目
每一個(gè)實(shí)例對(duì)象都有一個(gè)私有屬性__proto__指向其構(gòu)造函數(shù)的原型對(duì)象prototype,該原型對(duì)象也會(huì)作為實(shí)例對(duì)象有一個(gè)私有屬性__proto__,層層向上直到一個(gè)對(duì)象的原型對(duì)象值為null。
當(dāng)訪問(wèn)一個(gè)對(duì)象的屬性或方法時(shí),js引擎會(huì)先查找該對(duì)象本身是否包含,如果沒(méi)有,會(huì)去該對(duì)象的__proto__屬性所指向的原型對(duì)象上找,如果沒(méi)有,會(huì)繼續(xù)向上一層找,直到某個(gè)對(duì)象的__proto__值為null,這就是原型鏈。
在js中,每個(gè)構(gòu)造函數(shù)都有一個(gè)prototype屬性,指向另外一個(gè)對(duì)象,說(shuō)明整個(gè)對(duì)象所有的屬性和方法都會(huì)被構(gòu)造函數(shù)所擁有。
function?Person?(name,?age)?{
??this.name?=?name
??this.age?=?age
}
?
console.log(Person.prototype)
?
Person.prototype.type?=?'it'
?
Person.prototype.sayName?=?function?()?{
??console.log(this.name)
}
?
var?p1?=?new?Person('jeskson',?18);
var?p2?=?new?Person('dada',?18);
?
console.log(p1.sayName?===?p2.sayName)?//?=>?true
構(gòu)造函數(shù)Person:
function?Person()?{}
-->?原型屬性(prototype)?神秘的對(duì)象Person.prototype
-->?由構(gòu)造函數(shù)創(chuàng)建?Person實(shí)例?-->?__proto__?原型對(duì)象?-->?神秘對(duì)象
任何一個(gè)構(gòu)造函數(shù)都有一個(gè)prototype屬性,該屬性是一個(gè)object對(duì)象。
構(gòu)造函數(shù)的prototype對(duì)象都有一個(gè)默認(rèn)的constructor屬性,指向prototype對(duì)象所在函數(shù)。
通過(guò)構(gòu)造函數(shù)得到的實(shí)例對(duì)象內(nèi)部會(huì)包含一個(gè)指向構(gòu)造函數(shù)的 prototype 對(duì)象的指針 __proto__
console.log(obj.__proto__);
console.log(obj.prototype);
console.log(obj.__proto__?===?Object.prototype);
構(gòu)造函數(shù)(prototype)指向原型 構(gòu)造函數(shù),New實(shí)例化(實(shí)例對(duì)象),實(shí)例對(duì)象中(.constructor)指向構(gòu)造函數(shù) 實(shí)例對(duì)象 (.__proto__)指向原型
1.?實(shí)例對(duì)象.__proto__===原型
2.?原型.constructor===構(gòu)造函數(shù)
3.?構(gòu)造函數(shù).prototype===原型
67. typeof與instanceof的區(qū)別是什么
typeof 是一個(gè)一元運(yùn)算,它返回值是一個(gè)字符串,該字符串說(shuō)明運(yùn)算數(shù)的類型。
instanceof,判斷該對(duì)象是誰(shuí)的實(shí)例
instanceof 運(yùn)算符用來(lái)測(cè)試一個(gè)對(duì)象在其原型鏈中是否存在一個(gè)構(gòu)造函數(shù)的prototype屬性,instanceof只能用來(lái)判斷對(duì)象和函數(shù),不能用來(lái)判斷字符串和數(shù)字
function?getDataType(obj)?{
if?(obj?===?null)?{
return?“null”;
}?else?if?(typeof?obj?===?“object”)?{
if?(obj?instanceof?Array)?{
return?“array”;
}?else?{
return?“object”;
}
}?else?{
return?typeof?obj;
}
}
68. 說(shuō)說(shuō)事件流吧
事件流是指從 頁(yè)面中接收事件的順序。
69. 說(shuō)說(shuō)事件捕獲
指不太具體的元素更早地接收到事件,而最具體的節(jié)點(diǎn)最后接收到事件。
70. 說(shuō)說(shuō)什么是回調(diào)函數(shù)
它就是一個(gè)通過(guò)函數(shù)指針調(diào)用的函數(shù)。
71. 什么是自執(zhí)行函數(shù),它有哪些應(yīng)用場(chǎng)景,有什么好處
自執(zhí)行函數(shù)是指聲明的一個(gè)匿名函數(shù),可以立即調(diào)用整個(gè)匿名函數(shù),一般用于框架,插件等場(chǎng)景,好處在于避免各種JavaScript庫(kù)的沖突,隔離作用域,避免污染。
72. 什么是事件委托,有什么好處
事件委托是利用冒泡的原理,把事件加到父級(jí)上,觸發(fā)執(zhí)行效果。好處在于,減少事件數(shù)量,提高性能,避免內(nèi)存外泄。
73. 什么是強(qiáng)制類型轉(zhuǎn)換,什么是隱式類型轉(zhuǎn)換
在 JavaScript 中,數(shù)據(jù)類型的轉(zhuǎn)換有:隱式類型轉(zhuǎn)換和強(qiáng)制類型轉(zhuǎn)換(也叫顯式類型轉(zhuǎn)換)兩種方式。
隱式類型轉(zhuǎn)換:
==??只做值的判斷,實(shí)際隱式轉(zhuǎn)換了類型,然后才進(jìn)行的比較
強(qiáng)制類型轉(zhuǎn)換:
parseInt()?????將字符串強(qiáng)類型制轉(zhuǎn)換為數(shù)字整數(shù)類型
parseFloat()??將字符串類型轉(zhuǎn)換為浮點(diǎn)類型
Number()??????只能將純數(shù)字的字符轉(zhuǎn)換為數(shù)字
74. NaN是什么,它的類型是什么,如何可靠地判斷一個(gè)值是否等于NaN
NaN表示“不是數(shù)字”,但是它的類型是Number,NaN和任何內(nèi)容比較,甚至是自己,結(jié)果都是false.
75. 什么是跨域
廣義跨域就是指跨域訪問(wèn),簡(jiǎn)單來(lái)說(shuō)就是 A 網(wǎng)站的 javascript 代碼試圖訪問(wèn) B 網(wǎng)站,包括提交容和獲取內(nèi)容容。由于安全原因,跨域訪問(wèn)是被各大瀏覽器所默認(rèn)禁止的。
跨域是指不同域名之間的相互訪問(wèn)。
76. 以YYYY-MM-DD的方式,輸出當(dāng)天的日期,比如當(dāng)天是2020年1月1日,則輸出2020-01-01
var?d?=?new?Date();
var?year?=?d.getFullYear();
var?month?=?d.getMonth()?+?1;
month?=?month?10???"0"?+?month?:?month;
var?day?=?d.getDate();
daty?=?day<10??"0"+day?:?day;
console.log(year+'-'+month+'-'+day);
77. 用JavaScript隨機(jī)選取10到100之間的10個(gè)數(shù)字,把它們存入一個(gè)數(shù)組中并排序
var?isArray?=?[];
function?getRandom(start,?end)?{
?return?Math.floor(Math.random()?*?(end-start+1)?+?start)
}
for(var?i?=?0;?i<10;?i++){
?isArray.push(getRandom(10,100))
}
isArray.sort()
console.log(isArray)
78. 為了實(shí)現(xiàn)一個(gè)函數(shù)clonoe,可以對(duì)JavaScript中5種主要的數(shù)據(jù)類型(Number,String,Object,Array,Boolean)進(jìn)行值(深)復(fù)制。
function?clone(obj)?{
?var?buf;
?if(obj?instanceof?Array)?{
??var?i?=?obj.lenght;
??buf?=?[];
??while(i--)?{
???buf[i]?=?clone(obj[i])
??}
??return?buf;
?}else?if(obj?instanceof?Object)?{
??buf?=?{};
??for(var?i?in?obj)?{
???buf[i]?=?clone(obj[i])
??}
??return?buf;
?}else{
??return?buf?=?obj;
?}
}
79. 如何消除數(shù)組中重復(fù)的元素
function?noRepeat(arr)?{
?var?i?=?0,
?len?=?arr.length,
?obj?=?{},
?result?=?[];
?while(++i??obj[arr[i]]?||?result.push(arr[i])
?obj[arr[i]]?=?true;
}
return?result;
}
80. 說(shuō)明DOM對(duì)象的3中查詢方式
getElementById()根據(jù)元素id查找getElementsByTagName(tag)根據(jù)標(biāo)簽名稱查找getElementsByName(name)根據(jù)元素名稱進(jìn)行查找
81. 用面向?qū)ο蟮腏avaScript代碼介紹一下自己
function?Person(name,?job,?site)?{
?this.name?=?name;
?this.job?=?job;
?this.site?=?site;
}
Person.prototype?=?{
?getName:?function()?{
??console.log('my?name'+this.name);
?}
?getJob:?function()?{
??console.log('my?job'+?this.job);
?}
?getWork:?function()?{
??console.log('my?work'?+?this.site);
?}
}
var?da?=?new?Person('dada',?'it',?'shenzheng');
da.getName();
da.getJob();
da.getWork();
82. 什么是變量作用域
變量作用域,變量的可用性范圍。通常來(lái)說(shuō),一段程序代碼中所用到的名字并不總是有效可用的,而限定這個(gè)名字的可用性的代碼范圍就是這個(gè)名字的作用域。作用域的使用,可提高程序邏輯的局部性,增強(qiáng)程序的可靠性,減少名字沖突。從作用域角度區(qū)分,變量可分為全局變量和局部變量。
83. 在JavaScript中的繼承是如何工作的
在子構(gòu)造函數(shù)中,將父類的構(gòu)造函數(shù)在子類的作用域中執(zhí)行 在子類的原型中,復(fù)制父類構(gòu)造函數(shù)原型上的屬性方法
JavaScript是如何實(shí)現(xiàn)繼承的(六種方式)
1.原型鏈:利用原型讓一個(gè)引用類型繼承另外一個(gè)引用類型的屬性和方法。
原型鏈實(shí)現(xiàn)繼承例子:
function?SuperType()?{
this.property?=?true;
}
SuperType.prototype.getSuperValue?=?function()?{
return?this.property;
}
function?SubType()?{
this.property?=?false;
}
//繼承了SuperType
SubType.prototype?=?new?SuperType();
SubType.prototype.getSubValue?=?function?(){
return?this.property;
}
var?instance?=?new?SubType();
console.log(instance.getSuperValue());//true
2.借用構(gòu)造函數(shù):在子類型構(gòu)造函數(shù)的內(nèi)部調(diào)用超類構(gòu)造函數(shù),通過(guò)使用call()和apply()方法可以在新創(chuàng)建的對(duì)象上執(zhí)行構(gòu)造函數(shù)。
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?SubType();
console.log(instance2.colors);//"red","blue","green"
3.組合繼承:將原型鏈和借用構(gòu)造函數(shù)的技術(shù)組合在一塊,從而發(fā)揮兩者之長(zhǎng)的一種繼承模式。
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("da",18);
instance1.colors.push("black");
consol.log(instance1.colors);//"red","blue","green","black"
instance1.sayName();//"EvanChen"
instance1.sayAge();//18
var?instance2?=?new?SubType("dada",20);
console.log(instance2.colors);//"red","blue","green"
instance2.sayName();//"dada"
instance2.sayAge();//20
4.原型式繼承:借助原型可以基于已有的對(duì)象創(chuàng)建新對(duì)象,同時(shí)還不必須因此創(chuàng)建自定義的類型。
5.寄生式繼承:創(chuàng)建一個(gè)僅用于封裝繼承過(guò)程的函數(shù),該函數(shù)在內(nèi)部以某種方式來(lái)增強(qiáng)對(duì)象,最后再像真正是它做了所有工作一樣返回對(duì)象。
6.寄生組合式繼承:通過(guò)借用函數(shù)來(lái)繼承屬性,通過(guò)原型鏈的混成形式來(lái)繼承方法
84. 說(shuō)說(shuō)你對(duì)作用域鏈的理解
作用域鏈與函數(shù)執(zhí)行棧相對(duì)應(yīng)。js運(yùn)行環(huán)境分為全局、函數(shù)以及eval三類,每當(dāng)代碼執(zhí)行進(jìn)入了一個(gè)新的運(yùn)行環(huán)境就會(huì)將環(huán)境的執(zhí)行上下文入棧,退出環(huán)境時(shí)將其出棧,從棧頂?shù)綏5仔纬蓮膬?nèi)層到外層的嵌套關(guān)系。
由執(zhí)行上下文創(chuàng)建的詞法環(huán)境持有外層執(zhí)行上下文的詞法環(huán)境引用,當(dāng)JS引擎在當(dāng)前詞法環(huán)境中找不到相應(yīng)的變量時(shí),會(huì)逐層向外查找,如此形成的鏈表即為作用域鏈。
作用域鏈指的是代碼執(zhí)行時(shí),查找變量的規(guī)則,先在當(dāng)前自身的作用域查找,找不到在往上級(jí)作用域查找,查不到的話直至全局環(huán)境,當(dāng)然全局環(huán)境不能訪問(wèn)局部作用域的變量
85. 說(shuō)說(shuō)JavaScript中的原型鏈

JavaScript中的每個(gè)對(duì)象都有一個(gè)prototype屬性,稱為原型,而原型的值也是一個(gè)對(duì)象,因此它也有自己的原型,這樣就形成了一條原型鏈,原型鏈的鏈頭是object,它的prototype比較特殊,值為null。
__proto__是在查找鏈中用于解析方法的實(shí)際對(duì)象等,prototype使用以下命令__proto__創(chuàng)建對(duì)象時(shí)用于構(gòu)建的對(duì)象new:
(new?Foo).__proto__?===?Foo.prototype;
(new?Foo).prototype?===?undefined;
prototype是Function對(duì)象的屬性,它是由該功能構(gòu)造的對(duì)象的原型。
__proto__是對(duì)象的內(nèi)部屬性,指向其原型。當(dāng)前提供了Object.getPrototypeOf(o)方法,盡管事實(shí)上的標(biāo)準(zhǔn)__proto__更快。
可以使用instanceof通過(guò)將函數(shù)prototype與對(duì)象的__proto__鏈進(jìn)行比較來(lái)找到關(guān)系,也可以通過(guò)更改來(lái)打破這些關(guān)系。
function?Point(x,?y)?{
????this.x?=?x;
????this.y?=?y;
}
var?myPoint?=?new?Point();
//?the?following?are?all?true
myPoint.__proto__?==?Point.prototype
myPoint.__proto__.__proto__?==?Object.prototype
myPoint?instanceof?Point;
myPoint?instanceof?Object;
86. 說(shuō)說(shuō)函數(shù)的三種定義方式
有參函數(shù) 無(wú)參函數(shù) 空函數(shù)
1、 函數(shù)式聲明 2、 函數(shù)表達(dá)式(函數(shù)字面量) 3、 函數(shù)構(gòu)造法,參數(shù)必須加引號(hào) 4、 對(duì)象直接量 5、 原型繼承 6、 工廠模式
//?通過(guò)函數(shù)字面量
function?da()?{}
//?函數(shù)表達(dá)式
var?da?=?function()?{}
//?通過(guò)構(gòu)造函數(shù)
var?da?=?new?Function();
87. JavaScript里的全局對(duì)象是什么,如何調(diào)用
全局屬性和函數(shù)可用于所有內(nèi)建的 JavaScript 對(duì)象。默認(rèn)的this指向window,默認(rèn)全局對(duì)象的屬性和方法不用在前面加window,可以直接調(diào)用。
頂層函數(shù)(全局函數(shù)):
decodeURI()?解碼某個(gè)編碼的 URI。
decodeURIComponent()?解碼一個(gè)編碼的 URI 組件。
encodeURI()?把字符串編碼為 URI。
encodeURIComponent()?把字符串編碼為 URI 組件。
escape()?對(duì)字符串進(jìn)行編碼。
eval()?計(jì)算 JavaScript 字符串,并把它作為腳本代碼來(lái)執(zhí)行。
getClass()?返回一個(gè) JavaObject 的 JavaClass。
isFinite()?檢查某個(gè)值是否為有窮大的數(shù)。
isNaN()?檢查某個(gè)值是否是數(shù)字。
Number()?把對(duì)象的值轉(zhuǎn)換為數(shù)字。
parseFloat()?解析一個(gè)字符串并返回一個(gè)浮點(diǎn)數(shù)。
parseInt()?解析一個(gè)字符串并返回一個(gè)整數(shù)。
String()?把對(duì)象的值轉(zhuǎn)換為字符串。
unescape()?對(duì)由 escape()?編碼的字符串進(jìn)行解碼。
頂層屬性(全局屬性)
Infinity 代表正的無(wú)窮大的數(shù)值。
java 代表 java.*?包層級(jí)的一個(gè) JavaPackage。
NaN 指示某個(gè)值是不是數(shù)字值。
Packages 根 JavaPackage 對(duì)象。
undefined 指示未定義的值。
88. 說(shuō)說(shuō)幾個(gè)常見(jiàn)的JavaScript內(nèi)置對(duì)象,并指出它們的優(yōu)點(diǎn)
常用的是Array對(duì)象、Date對(duì)象、正則表達(dá)式對(duì)象、string對(duì)象、Global對(duì)象
Concat():表示把幾個(gè)數(shù)組合并成一個(gè)數(shù)組。?
Join():返回字符串值,其中包含了連接到一起的數(shù)組的所有元素,元素由指定的分隔符分隔開(kāi)來(lái)。?
Pop():移除數(shù)組最后一個(gè)元素。?
Shift():移除數(shù)組中第一個(gè)元素。?
Slice(start,end):返回?cái)?shù)組中的一段。?
Push():往數(shù)組中新添加一個(gè)元素,返回最新長(zhǎng)度。?
Sort():對(duì)數(shù)組進(jìn)行排序。?
Reverse():反轉(zhuǎn)數(shù)組的排序。?
toLocaleString();返回當(dāng)前系統(tǒng)時(shí)間。
ceil():向上取整。
floor():向下取整。
round():四舍五入。
random():取隨機(jī)數(shù)。
get/setDate():返回或設(shè)置日期。
get/setFullYear():返回或設(shè)置年份,用四位數(shù)表示。
get/setYear():返回或設(shè)置年份。
get/setMonth():返回或設(shè)置月份。0為一月
get/setHours():返回或設(shè)置小時(shí),24小時(shí)制
get/setMinutes():返回或設(shè)置分鐘數(shù)。
get/setSeconds():返回或設(shè)置秒鐘數(shù)。
get/setTime():返回或設(shè)置時(shí)間(毫秒為單位)。
89. 什么是DOM,DOM分為哪三種
DOM,文檔對(duì)象模型(Document Object Model)。DOM是 W3C(萬(wàn)維網(wǎng)聯(lián)盟)的標(biāo)準(zhǔn),DOM定義了訪問(wèn)HTML和XML文檔的標(biāo)準(zhǔn)。在W3C的標(biāo)準(zhǔn)中,DOM是獨(dú)于平臺(tái)和語(yǔ)言的接口,它允許程序和腳本動(dòng)態(tài)地訪問(wèn)和更新文檔的內(nèi)容、結(jié)構(gòu)和樣式。
分三種:
核心DOM,針對(duì)任何結(jié)構(gòu)化文檔的標(biāo)準(zhǔn)模型 xml Dom,針對(duì)xml文檔的標(biāo)準(zhǔn)模型 html Dom,針對(duì)HTML文檔的標(biāo)準(zhǔn)模型
90. 說(shuō)說(shuō)cookie的兼容性,缺點(diǎn)等



91. 說(shuō)說(shuō)棧和隊(duì)列的區(qū)別
隊(duì)列是先進(jìn)先出的,棧是先進(jìn)后出的 棧和隊(duì)列都是線性表,都是限制了插入刪除點(diǎn)的線性表,都是只能在線性表的端點(diǎn)插入和刪除
92. 說(shuō)說(shuō)cookie和session的區(qū)別
cookie數(shù)據(jù)存放在客戶的瀏覽器上,session數(shù)據(jù)存放在服務(wù)器上 cookie不是很安全 session會(huì)在一定時(shí)間內(nèi)保持在服務(wù)器上,當(dāng)訪問(wèn)多時(shí),會(huì)影響服務(wù)器的性能。 用戶驗(yàn)證這種場(chǎng)合一般會(huì)用 session session 可以放在 文件、數(shù)據(jù)庫(kù)、或內(nèi)存中都可以 Cookie和Session都是會(huì)話技術(shù) Cookie有大小限制以及瀏覽器在存cookie的個(gè)數(shù)也有限制,Session是沒(méi)有大小限制和服務(wù)器的內(nèi)存大小有關(guān)
我是Jeskson(達(dá)達(dá)前端),感謝各位人才的:點(diǎn)贊、收藏和評(píng)論,我們下期見(jiàn)!
關(guān)注數(shù):10億+?文章數(shù):10億+
粉絲量:10億+?點(diǎn)擊量:10億+
?懸賞博主專區(qū)請(qǐng)掃描這里
喜愛(ài)數(shù):?1億+?發(fā)帖數(shù):?1億+
回帖數(shù):?1億+?結(jié)貼率:?99.9%
—————END—————
喜歡本文的朋友,歡迎關(guān)注公眾號(hào)?程序員哆啦A夢(mèng),收看更多精彩內(nèi)容
點(diǎn)個(gè)[在看],是對(duì)小達(dá)最大的支持!
如果覺(jué)得這篇文章還不錯(cuò),來(lái)個(gè)【分享、點(diǎn)贊、在看】三連吧,讓更多的人也看到~



