前端面試遇到的問(wèn)題(一)

今天面試仍侥,不知怎么說(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)什么情況螟碎?


vFor1.png

vFor2.png

看到?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照馈!静盅!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末良价,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蒿叠,更是在濱河造成了極大的恐慌明垢,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件市咽,死亡現(xiàn)場(chǎng)離奇詭異痊银,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)施绎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)溯革,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人谷醉,你說(shuō)我怎么就攤上這事致稀。” “怎么了俱尼?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵抖单,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我号显,道長(zhǎng)臭猜,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任押蚤,我火速辦了婚禮,結(jié)果婚禮上羹应,老公的妹妹穿的比我還像新娘揽碘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布雳刺。 她就那樣靜靜地躺著劫灶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪掖桦。 梳的紋絲不亂的頭發(fā)上本昏,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音枪汪,去河邊找鬼涌穆。 笑死,一個(gè)胖子當(dāng)著我的面吹牛雀久,可吹牛的內(nèi)容都是我干的宿稀。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼赖捌,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼祝沸!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起越庇,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤罩锐,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后卤唉,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體涩惑,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年搬味,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了境氢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡碰纬,死狀恐怖萍聊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情悦析,我是刑警寧澤寿桨,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站强戴,受9級(jí)特大地震影響亭螟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜骑歹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一预烙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧道媚,春花似錦扁掸、人聲如沸翘县。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)锈麸。三九已至,卻和暖如春牺蹄,著一層夾襖步出監(jiān)牢的瞬間忘伞,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工沙兰, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留氓奈,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓僧凰,卻偏偏與公主長(zhǎng)得像探颈,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子训措,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容