今天面試仍侥,不知怎么說(shuō)要出,面試官詢問(wèn)的很多,完全感覺(jué)自己的知識(shí)儲(chǔ)備略微有點(diǎn)不夠农渊,下面看看有些啥問(wèn)題患蹂。
問(wèn)題一:是關(guān)于Object類型的數(shù)據(jù),如果只改變屬性值要如何去監(jiān)聽(tīng)砸紊?
在ES5中传于,便有defineProperty(obj, prop, descriptor)方法,但此方法是用于直接在一個(gè)對(duì)象上定義一個(gè)新的屬性醉顽,或者修改一個(gè)已存在的屬性沼溜,并返回這個(gè)對(duì)象。
obj: 目標(biāo)對(duì)象徽鼎;
prop: 目標(biāo)屬性盛末;
descriptor: 對(duì)定義或修改的屬性描述符弹惦。
同時(shí)還有defineProperties(obj, prop)方法否淤,來(lái)修改、設(shè)置棠隐、監(jiān)聽(tīng)多個(gè)屬性
obj: 目標(biāo)對(duì)象石抡;
prop: 目標(biāo)屬性組合而成的新對(duì)象;
let obj = {bb:"yang"};
Object.defineProperty(obj,'data',{ //對(duì)單個(gè)屬性進(jìn)行監(jiān)聽(tīng)設(shè)置等操作
enumerable: true, //true時(shí)助泽,該屬性才會(huì)出現(xiàn)在對(duì)象的枚舉屬性中
value: val,//默認(rèn)值為undefined啰扛,可以是任何有效的JavaScript值(數(shù)值嚎京,對(duì)象,函數(shù)等)
writable: true,//true時(shí)隐解,value才能被賦值運(yùn)算符改變
上面三個(gè)屬性鞍帝,是用于設(shè)置 ’data‘ 的一些配制,當(dāng)下面有g(shù)et或者set時(shí)煞茫,則不能使用writable與value帕涌,否則會(huì)報(bào)錯(cuò)
get:function(){
return data;
},
set:function(newValue){
data = newValue;
console.log('set :',newValue);
//需要觸發(fā)的渲染函數(shù)寫(xiě)在這...
}
});
Object.defineProperties(obj,{
bb : {
configurable: false, //true時(shí),該屬性才能被刪除
get: function(){
return bb;
},
set: function(value){
bb = value;
console.log('b',value);
}
},
data: {
enumerable: true,
configurable: false,
get: function(){
return data;
},
set: function(value){
data = value;
console.log('data',value);
}
}
});
obj.data = 5;
obj.bb = "ll"
這里會(huì)存在一個(gè)明顯的問(wèn)題续徽,那就是如果直接 console.log(obj)蚓曼,打印結(jié)果:{},但是如果用obj.data又能獲取到值:5钦扭。
上面兩個(gè)操作在ES6也有對(duì)應(yīng)的Proxy(target, handler)方法纫版,該方法還可以劫持?jǐn)?shù)組,但兼容性不好
target:目標(biāo)對(duì)象(可以是任何類型的對(duì)象客情,包括原生數(shù)組其弊,函數(shù),甚至可以是另一個(gè)代理)
handler: 一個(gè)對(duì)象膀斋,其屬性是當(dāng)執(zhí)行一個(gè)操作時(shí)定義代理的行為函數(shù)
let handler = {
get: function(target,name){//如果沒(méi)有屬性瑞凑,則返回默認(rèn)值37
return name in target ? target[name] : 37;
},
set: function(obj, prop, value){
if(prop == 'age'){
if(!Number.isInteger(value)){
//Number.isInteger,是用來(lái)校驗(yàn)數(shù)據(jù)是不是整數(shù),’10‘概页,也是false
throw new TypeError('age屬性設(shè)置的值非整數(shù)籽御!');
}
}
}
}
let p = new Proxy({},handler);
p.age = '123'; //拋出錯(cuò)誤
p.age = 123; //正常
查詢相關(guān)質(zhì)料時(shí),發(fā)現(xiàn)一個(gè)很騷的操作:如何讓 a==1 && a==2 && a==3 為 true
方法一:
let b = 1;
Object.defineProperty(window,'a',{
get: function(){
return b++;
}
})
方法二:
let a = {
b: 1,
toString(){
return this.b++;
}
}
問(wèn)題二:深淺拷貝
目的是為了解決引用數(shù)據(jù)類型復(fù)制的問(wèn)題惰匙。
來(lái)技掏,直接上我之前寫(xiě)過(guò)的一個(gè)方法:
getType(data){
// console.log(Object.prototype.toString.call(data));
return Object.prototype.toString.call(data).slice(8,-1);
},
dpClone(obj){
let that = this, getT = this.getType(obj);
switch(getT){
case "Object":
(function(){
let o = {};
for(let val in obj){
o[val] = that.dpClone(obj[val]);
}
})();
break;
case "Array":
(function(){
let arr = [];
for(let i = 0; i < obj.length; i++){
arr[i] = that.dpClone(obj[i]);
}
})();
break;
case "Function":
return new Function('return ' + obj.toString()).call(that);
case "Date":
return new Date(obj.valueOf());
case "RegExp":
return new RegExp(obj);
case "Map":
return (function(){
let m = new Map();
obj.forEach((v,k) => {
m.set(k,that.dpClone(v));
});
return m;
})();
case "Set":
return (function(){
let s = new Set();
for(let val of obj.values()){
s.add(that.dpClone(val))
}
return s;
})();
default :
return obj;
}
}
問(wèn)題三:map()函數(shù)
它是定義在Array中,返回一個(gè)新的數(shù)組项鬼,數(shù)組中的元素為原始數(shù)組調(diào)用函數(shù)處理后的值哑梳。
map()函數(shù)不會(huì)對(duì)空數(shù)組進(jìn)行檢測(cè),也不會(huì)改變?cè)瓟?shù)組绘盟。
arr.map(function(item,index,a){
//do something
},thisIndex)
item:當(dāng)前元素的值鸠真; 必須
index:當(dāng)前元素的索引; 可選
a:當(dāng)前元素屬于的數(shù)組對(duì)象龄毡; 可選
thisIndex:對(duì)象作為該執(zhí)行回調(diào)時(shí)使用吠卷,傳遞給函數(shù),用作“this”的值
擴(kuò)充知識(shí):Map集合與Set集合
Map集合
它是一組鍵值對(duì)的結(jié)構(gòu)沦零,具有極快的查找速度祭隔。
比如說(shuō),用兩個(gè)數(shù)組分存水果與對(duì)應(yīng)價(jià)格
let fruits = ['蘋(píng)果','香蕉','菠蘿','蜜桃'];
let prices = [23,15,18,20];
如果需要找菠蘿的價(jià)格路操,是不是比較麻煩疾渴,要先確定菠蘿在fruits數(shù)組的位置千贯,然后再到prices數(shù)組里取。
而用Map來(lái)實(shí)現(xiàn)搞坝,就很好處理搔谴。
let fruitPrices = new Map([['蘋(píng)果',23],['香蕉',15],['菠蘿',18],['蜜桃',20]]);
現(xiàn)在取菠蘿價(jià)格的就很簡(jiǎn)單了,
fruitPrices.get('菠蘿');
而添加桩撮、刪除數(shù)據(jù)也很方便己沛,
fruitPrices.set('鳳梨',26)距境;
fruitPrices.delete("香蕉");
注意:如果出現(xiàn)重復(fù)設(shè)置申尼,后面會(huì)將前面的替換,因?yàn)榈婀穑@里是鍵值對(duì)师幕,鍵重復(fù),后者替換前者诬滩。
Set集合
Set與Map不同霹粥,它是 鍵 的集合,不存 值 疼鸟,所以 Set 集合里不存在重復(fù)的 鍵后控,很多時(shí)候,數(shù)組去重空镜,就是用Set來(lái)操作的浩淘。
let setA = new Set(['a','b',1,2,3,'3']);
注意:這里的 3 與 ‘3’ 是不一樣的,所以不會(huì)被去重吴攒。
添加张抄、刪除數(shù)據(jù)
setA.add('e');
setA.delete(3);
在數(shù)組去重時(shí),可以用map()函數(shù)洼怔,以及Set集合來(lái)處理署惯。
問(wèn)題四:slice()與splice()之間的區(qū)別
相同:都是數(shù)組的內(nèi)置方法,都可以用來(lái)截取數(shù)組的镣隶。
不同:
1.入?yún)⒉灰粯樱?br>
slice极谊,
一個(gè)參數(shù)時(shí),便是截取的起始下標(biāo)安岂,一直到數(shù)組最后轻猖;
兩個(gè)參數(shù)時(shí),則是截取的起嗜闻、止下標(biāo)蜕依,
注意:slice截取桅锄,含起不含止样眠,很多這種類似需要起始位置的操作,基本都是
同時(shí),下標(biāo)是可以為負(fù)值束倍,當(dāng)截止為負(fù)值被丧,則說(shuō)位置是從后往前數(shù),記住一點(diǎn) -1 表示數(shù)組最后一位绪妹,-2表示數(shù)組倒數(shù)第二位甥桂。舉個(gè)例子:
let arr = [1,2,3,4,5,6,7,'a','b','c',8,9];
console.log(arr.slice(-2,-1));//輸出[8],起始是8邮旷,結(jié)束是9(不包括)
splice黄选,
一個(gè)參數(shù),從下標(biāo)開(kāi)始截取到數(shù)組最后一個(gè)婶肩;
兩個(gè)參數(shù)办陷,第一個(gè)參數(shù)是截取起始位置,第二個(gè)參數(shù)是截取個(gè)數(shù)律歼;
三個(gè)參數(shù)以上民镜,第一個(gè)參數(shù)是截取起始位置,第二個(gè)參數(shù)是截取個(gè)數(shù)险毁,第三個(gè)參數(shù)即后面的參數(shù)制圈,都是替換被截取的位置。
let arr = [1,2,3,4,5,6,7,'a','b','c',8,9];
arr.splice(2,1,'fg','lk')
console.log(arr);//輸出[1, 2, 'fg', 'lk', 4, 5, 6, 7, 'a', 'b', 'c', 8, 9]
2.截取的效果也不一樣
slice返回的是生成新的數(shù)組畔况,不影響原數(shù)組离唐,只是截取操作。
splice返回的是不需要的部分问窃,而原數(shù)組也變成了我們需要的部分亥鬓,這是直接在原數(shù)組上操作,可以截取域庇、替換嵌戈,插入操作。
問(wèn)題五:Promise
目的:解決回調(diào)深淵的問(wèn)題听皿,讓代碼看起來(lái)更加舒服熟呛,更容易理解與書(shū)寫(xiě)。
這里面存在一些問(wèn)題尉姨,第一庵朝,Promise一旦新建就會(huì)立即執(zhí)行,無(wú)法中途取消;第二九府,如果沒(méi)有設(shè)置回調(diào)函數(shù)椎瘟,Promise內(nèi)部拋出錯(cuò)誤,不會(huì)反應(yīng)到外部侄旬;第三肺蔚,當(dāng)處于pending狀態(tài)時(shí),無(wú)法得知目前進(jìn)展到哪一個(gè)階段儡羔。
pending:待定宣羊;
fulfilled:解決(resolved);
rejected:拒絕汰蜘;
剛剛細(xì)查了一下Promise的資料仇冯,加上自測(cè),發(fā)現(xiàn)一些我自己沒(méi)有想到的問(wèn)題族操,下面總結(jié)一下赞枕。
1、Promise里面是一個(gè)方法坪创,這個(gè)方法里面有兩個(gè)固定參數(shù)炕婶,兩個(gè)參數(shù)都是方法,參數(shù)一 (res) 表示成功莱预,參數(shù)二 (rej) 表示失敗柠掂,res(值) 會(huì)被后面緊跟著的.then(res1,rej1),里面的res1接收到依沮,rej(值) 會(huì)被rej1接收涯贞,這里接收的是括號(hào)里面的--值。
這個(gè)兩個(gè)方法參數(shù)危喉,只要有一個(gè)執(zhí)行宋渔,便直接進(jìn)入后續(xù)。
注意辜限,這個(gè)--值皇拣,可以是普通數(shù)據(jù)類型,也可以是引用數(shù)據(jù)類型薄嫡,還可以是一個(gè)方法氧急,等。
2毫深、.then(res,rej)里面的rej吩坝,是可以接收到前面未接收過(guò)的 rej(值) ,如果當(dāng)前的rej里面有返回值哑蔫,會(huì)被下一個(gè).then(res1,rej1)里面的res1所接收
3钉寝、.catch(rej=>{})弧呐,這里是捕獲錯(cuò)誤,但前提是嵌纲,前面的then里面沒(méi)有第二個(gè)參數(shù)rej才行俘枫,一旦某個(gè)then里面有rej,那么前面的失敗是走不到catch里面疹瘦,catch也是有返回值的崩哩,如果后面再接一個(gè)then也是可以接收到這個(gè)返回值巡球。
4言沐、.finally(),它沒(méi)有入?yún)⒑ㄕ唬灰獙?xiě)上去就會(huì)執(zhí)行险胰,不管是中間,還是最后矿筝,建議是最后起便,這個(gè)方法類似最后的收尾工作,
個(gè)人建議窖维,在有.finally()時(shí)榆综,catch寫(xiě)在它前面一個(gè)就行。
如果看不明白铸史,可以拿我這個(gè)自測(cè)的代碼玩一下鼻疮,
let promise = new Promise(function(res,rej){
// res("su");
rej(1);
}).then(res1=>{
console.log('res1',res1);
},rej1=>{
console.log('rej1',rej1);
return 0;
}).then(res2=>{
console.log('res2',res2);
return 'res2'
},rej2=>{
console.log('rej2',rej2);
}).catch(rej3=>{
console.log('catch',rej3);
return 2;
}).finally(()=>{
console.log("finally");
})
上面的都是串行,一個(gè)接一個(gè)的操作琳轿,多個(gè)并行判沟,Promise自然也有:Promise.all()方法
let fn1 = function(){};
let fn2 = function(){};
let arr = [fn1,fn2];//fn1,fn2都是異步函數(shù)
Promise.all(arr).then(([data1,data2])=>{}).catch((rej)=>{})
該方法存在一個(gè)問(wèn)題,如果其中一個(gè)方法出問(wèn)題崭篡,大家一起GG挪哄。
所以,在有已知異步函數(shù)的情況下琉闪,還是串行相對(duì)要好迹炼。
那如果存方法的數(shù)組里不確定有多少個(gè)異步方法?
于是乎,用reduce()來(lái)改進(jìn)
let arr = [fn1,fn2,…];
arr.reduce((task,promise)=>{
return task.then(()=> return promise).then(res=>{})
},Promise,resolve())
面對(duì)數(shù)組的reduce()方法颠毙,我又開(kāi)始進(jìn)行探索疗涉,(喵的,寫(xiě)了快一整天了吟秩,居然才寫(xiě)到問(wèn)題五咱扣,這樣研究下去,可以研究一個(gè)星期)
來(lái)來(lái)涵防,介紹一下reduce(callback,[initVal])
這個(gè)方法類型for循環(huán)跟forEach方法的功能類似闹伪,就是遍歷沪铭。
參數(shù)一:
callback(prev,cur,index,arr):就是一個(gè)回調(diào)函數(shù),不過(guò)這回調(diào)函數(shù)的入?yún)⒂悬c(diǎn)子多--四個(gè)
prev: 在reduce有第二個(gè)參數(shù)initVal時(shí)偏瓤,prev的第一次就是initVal杀怠,記住是第一次,第二次開(kāi)始就是前面處理的返回值厅克。
如果reduce沒(méi)有第二個(gè)參數(shù)赔退,那么他就是數(shù)組的第一個(gè)元素,而下面的cur變成了第二個(gè)
cur:當(dāng)前被遍歷到的元素
index:當(dāng)前元素的下標(biāo)
arr:就是調(diào)用reduce的數(shù)組
參數(shù)二:
initVal:作為callback第一次調(diào)用時(shí)的入?yún)ⅲ?/p>
下面代碼证舟,大家拿回去自測(cè)一下
var arr = [1, 2, 3, 4];
var sum = arr.reduce(function(prev, cur, index, arr) {
console.log(prev, cur, index);
return prev + cur;
})
console.log(arr, sum);
最開(kāi)始不是說(shuō)Promise一旦建立就沒(méi)法中途取消硕旗,我就想著,能不能搞點(diǎn)事情女责,比如說(shuō)異步處理中定一個(gè)超時(shí)漆枚。
想了一下,真的取消是不可能抵知,那就只能利用Promise的機(jī)制墙基,通過(guò)reject,resolve讓他直接跳到最后的catch刷喜。
function stopPromise(fn,times){ //fn可以是reject残制,也可以是resolve
setTimeout(()=>{
fn(定義傳給后面的數(shù)據(jù))
},times)
}
//使用
function myPromise(callback){
return new Promise((res,rej)=>{
//處理代碼
callback && callback(rej,5000);//上面代碼5s內(nèi)沒(méi)有處理,便直接跳到下一步
})
}
myPromise(stopPromise).then().catch()
然后我又百度了一下資料掖疮,發(fā)現(xiàn)還有另外一種方法初茶,Promise.race()
科普Promise.race():該方法也是傳入 異步函數(shù)數(shù)組,與Promise.all()類似氮墨。
不同之處:
all()的返回值是大家一起執(zhí)行完纺蛆,將結(jié)果組成一個(gè)新數(shù)組返回,其順序是根據(jù)入?yún)?shù)組里的順序排列的规揪,
race()誰(shuí)先執(zhí)行完桥氏,就返回那個(gè)結(jié)果,不管結(jié)果是成功還是失敗猛铅。
因此字支,利用這個(gè)特點(diǎn)來(lái)操作。
let myStop = new Promise((res,rej)=>{
setTimeout(()=>{
//res()或rej()
},5000)
})
let myPromise = new Promise(res,rej)=>{
//執(zhí)行代碼
})
Promise.race([myStop,myPromise]).then().catch()
這里有一個(gè)狠明顯的問(wèn)題奸忽,那就是超時(shí)時(shí)間不能隨心所欲堕伪。
問(wèn)題六:變量聲明的區(qū)別
let聲明的變量不能在聲明之前使用;
var聲明的變量很隨意栗菜,這也是ES6 新增兩個(gè)聲明的原因欠雌;
const聲明的變量是不允許修改的,不過(guò)對(duì)象里修改屬性疙筹,或者新增屬性富俄,不會(huì)報(bào)錯(cuò)禁炒,因?yàn)榈刂窙](méi)變
問(wèn)題七:ES6中some與every之間的區(qū)別
既然都說(shuō)了ES6的方法了,那索性就一并拿出來(lái)瞅瞅霍比。
數(shù)組相關(guān)
filter方法幕袱,用來(lái)過(guò)濾數(shù)組,生成一個(gè)新的數(shù)組
let newArr = arr.filter((val,index,arr)=>{
//val當(dāng)前元素悠瞬,index當(dāng)前元素下標(biāo)们豌,arr原數(shù)組
//操作過(guò)程
return true; 返回值為true,則當(dāng)前元素返回
})
reduce方法前面說(shuō)了浅妆,就不復(fù)述了
reduceRight方法拌阴,與reduce方法一樣炭臭,但是箕憾,它是從數(shù)組右邊往左遍歷
Array.from方法诬辈,將類數(shù)組轉(zhuǎn)為數(shù)組混弥,只要是含有l(wèi)ength屬性的都可以轉(zhuǎn)趴乡,
最騷的是,如果一個(gè)對(duì)象里面有l(wèi)ength屬性蝗拿,也能轉(zhuǎn)晾捏,看例子
let str = 'abcd';
let strArr = Array.from(str);//['a','b','c','d']
let obj = {name:"test",age:18,2:'two',5:'fi','3':'three',length:6}
console.log(Array.from(obj));//輸出[undefined,undefined,'two','three',undefined,'fi']
從這個(gè)例子,大家應(yīng)該看出點(diǎn)門(mén)道來(lái)了吧哀托,第一個(gè)就不說(shuō)了惦辛,第二個(gè)能轉(zhuǎn),就是一個(gè) length:6 這個(gè)屬性仓手,就轉(zhuǎn)成了一個(gè)長(zhǎng)度為6的數(shù)組胖齐,轉(zhuǎn)換的規(guī)矩是看鍵名,是否有 0-5 之間的 數(shù)字與字符串嗽冒,匹配上呀伙,其鍵值就是新數(shù)組對(duì)應(yīng)位置上的值,匹配不上的位置就是undefined添坊。
Array.of方法剿另,將一組值轉(zhuǎn)換數(shù)組,類似聲明一個(gè)數(shù)組(new Array())
Array.of('123');//['123']
Array.of({a:23,b:4})//[{a:23,b:4}]
new Array('33');//['33']
copyWithin方法贬蛙,在數(shù)組內(nèi)部將指定的一段數(shù)組雨女,復(fù)制到其他位置,會(huì)改變?cè)瓟?shù)組
參數(shù)一阳准,替換的開(kāi)始位置氛堕,必傳
參數(shù)二,指定數(shù)組的起始下標(biāo)野蝇,默認(rèn)0讼稚,為負(fù)值位喂,則從右向左(類似splice方法里為負(fù)值),可選
參數(shù)三乱灵,指定數(shù)組的結(jié)束下標(biāo)塑崖,默認(rèn)為數(shù)組長(zhǎng)度,為負(fù)值痛倚,表示倒數(shù)规婆,可選
let arr = [1, 2, 3, 4, 5];
// console.log(arr.copyWithin(3)); [1, 2, 3, 1, 2]
// console.log(arr.copyWithin(0,3)); [4, 5, 3, 4, 5]
// console.log(arr.copyWithin(0,3,4)); [4, 2, 3, 4, 5]
// console.log(arr.copyWithin(-1)); [1, 2, 3, 4, 1]
// console.log(arr.copyWithin(-2,-3)); [1, 2, 3, 3, 4]
//console.log(arr.copyWithin(-5,-3,-1)); [3, 4, 3, 4, 5]
find方法,找出第一條符合條件的數(shù)組項(xiàng)
let arr = [2,3,4,5]
arr.find((item,index,arr)=>{
// item當(dāng)前元素,index當(dāng)前元素下標(biāo),arr當(dāng)前數(shù)組
return item > 3;//返回4
})
findIndex方法蝉稳,找出第一條符合條件的數(shù)組想的下標(biāo)抒蚜,與find方法一樣操作
fill方法,使用指定值填充整個(gè)數(shù)組耘戚,會(huì)改變?cè)瓟?shù)組
參數(shù)一嗡髓,填充值
參數(shù)二,開(kāi)始填充的起始下標(biāo)
參數(shù)三收津,結(jié)束填充的截止下標(biāo)饿这,不包括
let arr = [1, 2, 3, 4, 5];
console.log(arr.fill('a',2,4));//[1, 2, 'a', 'a', 5]
some方法,數(shù)組迭代方法撞秋,用來(lái)判斷數(shù)組里面有沒(méi)有符合要求的數(shù)據(jù)长捧,只要有一個(gè)滿足,返回true吻贿,沒(méi)有符合的返回false
every方法串结,數(shù)組迭代方法,用來(lái)判斷數(shù)組里面的所有數(shù)據(jù)是否符合要求舅列,必須要全部符合才會(huì)返回true肌割,有一個(gè)不符合,返回false
[44,32,54,12].some((item,index,arr)=>{return item > 50}) //true
[44,32,54,12].every((item,index,arr)=>{return item > 50}) //false
keys方法帐要,遍歷數(shù)組的鍵名(一般針對(duì)Map/Set集合)
let arr = [1,2,3,4];
//keys方法
let arr2 = arr.keys();
console.log(arr2)//打印 Array Iterator {}
for(let key of arr2){
console.log(key);//0,1,2,3
}
//value方法
let arr3 = arr.value();
console.log(arr3);//Array Iterator {}
for(let val of arr3){
console.log(val);//1,2,3,4
}
//entries方法
let arr4 = arr.entries();
console.log(arr4);//Array Iterator {}
for(let item of arr4){
console.log(item);//[0,1],[1,2],[2,3],[3,4]
}
有沒(méi)有發(fā)現(xiàn)上面的那個(gè)奇怪的問(wèn)題把敞,直接打印數(shù)組是沒(méi)有什么數(shù)據(jù),但遍歷還是有數(shù)據(jù)的宠叼,ES6新增的Object.defineProprety()先巴、Object.definePropreties()中的set操作也會(huì)有類似的問(wèn)題
value方法,與keys()方法相對(duì)應(yīng)冒冬,它遍歷鍵值(一般針對(duì)Map/Set集合)伸蚯,案例就寫(xiě)上面了
entries方法,結(jié)合keys與value简烤,遍歷數(shù)組的鍵值與鍵名(一般針對(duì)Map/Set集合)剂邮,案例就寫(xiě)上面了方便一起對(duì)比
for…of與for…in的區(qū)別
for…of只能遍歷數(shù)組,而for…in能遍歷對(duì)象和數(shù)組(下標(biāo)可以視為鍵横侦,數(shù)據(jù)項(xiàng)為值)
如果動(dòng)態(tài)給數(shù)組添加一個(gè)鍵值對(duì)挥萌,for…in會(huì)數(shù)組的鍵包括添加的屬性名一起遍歷绰姻,而for…of只會(huì)遍歷原數(shù)組據(jù)項(xiàng)
字符串新增方法
includes方法,校驗(yàn)字符串中是否包含指定字符串引瀑,返回true狂芋、false
參數(shù)一:指定字符串;
參數(shù)二:查找起始下標(biāo)位置
let str = 'ewwrfsdfsf';
console.log(str.includes("ww")); //true
console.log(str.includes("ww",2));//false,從下標(biāo)2開(kāi)始往后查憨栽,是匹配不到的
console.log(str.startsWith("ww",1));//true
console.log(str.endsWith("ww",3));//true
startWith方法帜矾,校驗(yàn)字符串是特定位置開(kāi)始,是否以特定字符開(kāi)頭
參數(shù)一:指定字符串
參數(shù)二:起始下標(biāo)
案例寫(xiě)在上面了屑柔。
endsWith方法屡萤,校驗(yàn)字符串是否以特定字符串結(jié)尾,
參數(shù)一:指定字符串
參數(shù)二:結(jié)束下標(biāo)
案例寫(xiě)上面
repeat方法掸宛,重復(fù)當(dāng)前字符串死陆,不會(huì)影響原數(shù)組
參數(shù):重復(fù)次數(shù)
let str1 = 'abc';
console.log(str1.repeat(2));//abcabc
console.log(str1);//abc
padStart方法,字符串首位補(bǔ)全唧瘾,生成新字符串
參數(shù)一:字符串的長(zhǎng)度
參數(shù)二:補(bǔ)充的字符串
let str2 = 'efgj';
console.log(str2.padStart(6,'12'));//12efgj
console.log(str2.padStart(8,'12'));//1212efgj,補(bǔ)充字符串長(zhǎng)度不夠措译,則重復(fù)替換
console.log(str2.padStart(8));// efgj,沒(méi)有傳補(bǔ)充字符串劈愚,則以空格代替
console.log(str2.padStart(8,'123456'));//1234efgj瞳遍,補(bǔ)充字符串長(zhǎng)度過(guò)長(zhǎng)闻妓,則截取前面部分
console.log(str2.padEnd(6,'12'));//efgj12,
console.log(str2.padEnd(8,'12'));//efgj1212,
console.log(str2.padEnd(8));//efgj ,
console.log(str2.padEnd(8,'123456'));//efgj1234
padEnd方法菌羽,與padStart方法相反,從字符串末尾補(bǔ)全
參數(shù)一:字符串長(zhǎng)度
參數(shù)二:補(bǔ)充字符串
案例寫(xiě)上面
trimStart方法由缆,過(guò)渡字符串前面的空格部分注祖,
trimEnd方法,過(guò)濾字符串后面的空格部分均唉,
trim方法是晨,過(guò)濾字符串前后的空格部分
let str3 = ' hjk ';
console.log(str3.trim()); //hjk,
console.log(str3.trimStart());//hjk ,
console.log(str3.trimEnd()); // hjk,
replace方法,替換字符串中所以指定的字符片段
參數(shù)一:被替換的字符片段
參數(shù)二:替換的字符片段
let str4 = 'bcdfjk';
console.log(str4.replace('df','hhh'));//bchhhjk
console.log(str4.replace('dj','hhh'));//bcdfjk
問(wèn)題八:forEach如何跳出循環(huán)
首先舔箭,return false是沒(méi)有用的罩缴,然后break、continue這些也不管用层扶。
查了一下資料箫章,forEach、map這兩個(gè)方法都是不能中途終止的镜会,除非拋出異常錯(cuò)誤才能終止(遍歷完不算)檬寂,所以,想終止那就手動(dòng)拋異常戳表,
還有一點(diǎn)要注意桶至,如果用throw new Error()昼伴,那就得用try{}catch(e){}來(lái)捕捉這個(gè)錯(cuò)誤,不然代碼就 走不下去了镣屹。
問(wèn)題九:vue v-for與v-if
在vue 2.X版本里圃郊,同一個(gè)元素上,v-for的優(yōu)先級(jí)是大于v-if的女蜈,在同一個(gè)標(biāo)簽一起使用就有點(diǎn)耗費(fèi)性能描沟,一般情況下,會(huì)選擇通過(guò)computed計(jì)算屬性鞭光,將if判斷為true的數(shù)據(jù)篩選吏廉,然后篩選的數(shù)據(jù)拿去v-for。
網(wǎng)上還有一個(gè)操作惰许,避免渲染本該隱藏的列表項(xiàng)席覆,將v-if放到template,將v-for包括起來(lái)汹买。
但是佩伤,在vue 3.X版本里,v-if總是優(yōu)先與v-for生效
問(wèn)題十::key的基礎(chǔ)晦毙,為什么index沒(méi)有id好(v-for里最為明顯)
首先生巡,咱先說(shuō)說(shuō):key的作用,它相當(dāng)于給DOM對(duì)象加了一個(gè)標(biāo)識(shí)见妒,方便在diff算法執(zhí)行時(shí)孤荣,能更快的找到對(duì)于的節(jié)點(diǎn),高效的更新虛擬dom须揣。
如果DOM發(fā)生變化盐股,Vue里面首先要做的是,生產(chǎn)最新的虛擬DOM耻卡,然后拿舊的虛擬DOM來(lái)與之對(duì)比疯汁,對(duì)比就是以:key綁定的值為準(zhǔn),如果值相同卵酪,就直接拿來(lái)用幌蚊,如果不同則重新創(chuàng)建。
這樣就可以看出溃卡,用index的問(wèn)題溢豆,如果新值是從數(shù)據(jù)最前面插入的,那么v-for遍歷修改后的數(shù)據(jù)時(shí)塑煎,是不是每個(gè)新的虛擬DOM都要重新創(chuàng)建沫换,而老的虛擬DOM都要?jiǎng)h除,而用id作為唯一標(biāo)識(shí),那么就只需要將新增的虛擬DOM加入就行讯赏。
拓展一下:
如果沒(méi)有:key垮兑,那么vue會(huì)使用一種最大限度減少動(dòng)態(tài)元素并盡可能的嘗試就地修改/復(fù)用相同類型元素的算法。
說(shuō)一下響應(yīng)式數(shù)據(jù)更新后漱挎,是怎么個(gè)操作系枪,
先會(huì)觸發(fā) 渲染W(wǎng)atcher 的回調(diào)函數(shù) vm._update(vm._render()) 驅(qū)動(dòng)視圖更新,
vm._render() 其實(shí)生成的就是 vnode 磕谅,而 vm._update 就會(huì)帶著新的 vnode 去觸發(fā) patch
patch的過(guò)程:
1私爷、不是相同節(jié)點(diǎn):isSameNode為false,直接銷(xiāo)毀舊的 vnode 膊夹,渲染新的 vnode衬浑。
2、是相同的節(jié)點(diǎn)放刨,就會(huì)繼續(xù)往下對(duì)比工秩,盡快能做到節(jié)點(diǎn)的復(fù)用
這里會(huì)調(diào)用 src/core/vdom/patch.js 里的patchVNode方法
新vnode是文字:直接調(diào)用瀏覽器的 dom api 將節(jié)點(diǎn)直接替換文字內(nèi)容。
新vnode不是文字:那就要開(kāi)始對(duì)比 子節(jié)點(diǎn) children进统,一直類推助币。
有新children沒(méi)有舊children:直接 addVnodes 添加新子節(jié)點(diǎn)
無(wú)新children有舊children:直接 removeVnodes 刪除舊子節(jié)點(diǎn)
寫(xiě)到這里我想到一個(gè)問(wèn)題:
<ul>
<li v-for="(val,index) in vFor" :key="index">
{{val}}
<input type="text">
</li>
</ul>
<button @click="addFor">addvFor</button>
methods:{
addFor(){
this.vFor.unshift(8);
}
}
這一部分代碼放入vue中,點(diǎn)擊按鈕會(huì)出現(xiàn)什么情況螟碎?
看到?jīng)]有眉菱,很騷氣吧,直接復(fù)用了掉分!
而且俭缓,哪怕在input里加入了:key="index",也是這個(gè)結(jié)果叉抡,這也是在說(shuō)明index的不足之處
問(wèn)題十一:v-model這個(gè)語(yǔ)法糖是優(yōu)化那些方法的尔崔,原理是什么?
v-model即可以作用于表單元素褥民,又可作用于自定義組件,最終會(huì)生成一個(gè)屬性和一個(gè)事件洗搂。
當(dāng)其作用于表單元素時(shí)消返,vue
會(huì)根據(jù)作用的表單元素類型而生成合適的屬性和事件。例如耘拇,作用于普通文本框的時(shí)候撵颊,它會(huì)生成value
屬性和input
事件,而當(dāng)其作用于單選框或多選框時(shí)惫叛,它會(huì)生成checked
屬性和change
事件倡勇。
當(dāng)其作用于自定義組件時(shí),默認(rèn)情況下嘉涌,它會(huì)生成一個(gè)value
屬性和input
事件妻熊;可以通過(guò)組件的model
配置來(lái)改變生成的屬性和事件
問(wèn)題十二:compute與watch直接的區(qū)別夸浅,以及他們的使用
1、computed支持緩存扔役,只有當(dāng)依賴的數(shù)據(jù)發(fā)生變化帆喇,才會(huì)重新計(jì)算。而watch不支持緩存亿胸,數(shù)據(jù)變化坯钦,立即出發(fā)相應(yīng)操作。
2侈玄、computed不支持異步婉刀,異步操作在computed內(nèi)是無(wú)效的,無(wú)法監(jiān)聽(tīng)到數(shù)據(jù)變化序仙。而watch支持異步路星。
3、computed屬性值會(huì)默認(rèn)走緩存诱桂,計(jì)算屬性是基于它們的響應(yīng)式依賴進(jìn)行緩存的洋丐,也就是基于data中的聲明過(guò)或者父組件傳遞的props中的數(shù)據(jù)通過(guò)計(jì)算得到的值;watch監(jiān)聽(tīng)的函數(shù)接收兩個(gè)參數(shù)挥等,第一個(gè)參數(shù)是最新值友绝,第二個(gè)參數(shù)是變化之前的舊值
4、如果一個(gè)屬性是由其他屬性計(jì)算而來(lái)肝劲,這個(gè)屬性依賴其他屬性迁客,是一對(duì)一或者一對(duì)多,或者說(shuō)多個(gè)數(shù)據(jù)影響該計(jì)算屬性辞槐,一般就用computed掷漱。如果屬性變化時(shí),需要執(zhí)行一些操作榄檬,或者該數(shù)據(jù)會(huì)影響多個(gè)數(shù)據(jù)卜范,一般就是watch
5、在computed中鹿榜,屬性都有g(shù)et和set方法海雪,如果computed的屬性值是函數(shù),那么就會(huì)走get方法舱殿,函數(shù)的返回值就是屬性的屬性值奥裸,如果依賴的數(shù)據(jù)變化,則調(diào)用set方法沪袭。
一次面試湾宙,總結(jié)三天,我太難了!
寫(xiě)了近七千字的總結(jié)侠鳄,都快寫(xiě)吐我了埠啃。
嘿嘿!其實(shí)畦攘,還有兩個(gè)問(wèn)題霸妹,vuex狀態(tài)管理,以及為何不用瀏覽器緩存而是用vuex來(lái)管理數(shù)據(jù)知押,(剛剛準(zhǔn)備上傳文章時(shí)叹螟,才想起來(lái))
能看到最后的小伙伴,可以自己思考一二台盯,然后留個(gè)言吧0照馈!静盅!