<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          2022年我的面試萬字總結(jié)(代碼篇)

          共 27090字,需瀏覽 55分鐘

           ·

          2022-11-12 17:10

          前言

          又到了金九銀十季,最近我也是奔波于各種面試。我自己總結(jié)整理了很多方向的前端面試題。借著國慶這個假期,也把這些題目總結(jié)分享給大家,也祝正在面試的朋友們能夠拿到滿意的offer。

          往期文章

          (1) 2022年我的面試萬字總結(jié)(瀏覽器網(wǎng)絡(luò)篇)[2]

          (2) 2022年我的面試萬字總結(jié)(CSS篇)[3]

          (3) 2022年我的面試萬字總結(jié)(HTML篇)[4]

          (4) 2022年我的面試萬字總結(jié)(JS篇上)[5]

          (5) 2022年我的面試萬字總結(jié)(JS篇下)[6]

          (7) 2022年我的面試萬字總結(jié)(Vue上)[7]

          (8) 2022年我的面試萬字總結(jié)(Vue下)[8]

          一、手寫代碼題

          1. 手寫Object.create

          思路:將傳入的對象作為原型

                function?create(obj)?{
          ??function?F()?{}
          ??F.prototype?=?obj
          ??return?new?F()
          }
          復(fù)制代碼

          2. 手寫instanceof

          instanceof 運(yùn)算符用于判斷構(gòu)造函數(shù)的 prototype 屬性是否出現(xiàn)在對象的原型鏈中的任何位置。

          實現(xiàn)步驟:

          1.             首先獲取類型的原型
          2.             然后獲得對象的原型
          3.             然后一直循環(huán)判斷對象的原型是否等于類型的原型,直到對象原型為 `null`,因為原型鏈最終為 `null`
                function?myInstanceof(left,?right)?{
          ??let?proto?=?Object.getPrototypeOf(left),?//?獲取對象的原型
          ??????prototype?=?right.prototype;?//?獲取構(gòu)造函數(shù)的?prototype?對象

          ??//?判斷構(gòu)造函數(shù)的?prototype?對象是否在對象的原型鏈上
          ??while?(true)?{
          ????if?(!proto)?return?false;
          ????if?(proto?===?prototype)?return?true;

          ????proto?=?Object.getPrototypeOf(proto);
          ??}
          }
          復(fù)制代碼

          3. 手寫 new

          (1)首先創(chuàng)建了一個新的空對象

          (2)設(shè)置原型,將對象的原型設(shè)置為函數(shù)的 prototype 對象。

          (3)讓函數(shù)的 this 指向這個對象,執(zhí)行構(gòu)造函數(shù)的代碼(為這個新對象添加屬性)

          (4)判斷函數(shù)的返回值類型,如果是值類型,返回創(chuàng)建的對象。如果是引用類型,就返回這個引用類型的對象。

                ?function?myNew(fn,?...args)?{
          ??????//?判斷參數(shù)是否是一個函數(shù)
          ??????if?(typeof?fn?!==?"function")?{
          ????????return?console.error("type?error");
          ??????}
          ??????//?創(chuàng)建一個對象,并將對象的原型綁定到構(gòu)造函數(shù)的原型上
          ??????const?obj?=?Object.create(fn.prototype);
          ??????const?value?=?fn.apply(obj,?args);?//?調(diào)用構(gòu)造函數(shù),并且this綁定到obj上
          ??????//?如果構(gòu)造函數(shù)有返回值,并且返回的是對象,就返回value?;否則返回obj
          ??????return?value?instanceof?Object???value?:?obj;
          ????}
          復(fù)制代碼

          4. 手寫promise(簡易版)

                class?MyPromise?{
          ??constructor(fn){
          ????//?存儲?reslove?回調(diào)函數(shù)列表
          ????this.callbacks?=?[]
          ????const?resolve?=?(value)?=>?{
          ??????this.data?=?value?//?返回值給后面的?.then
          ??????while(this.callbacks.length)?{
          ????????let?cb?=?this.callbacks.shift()
          ????????cb(value)
          ??????}
          ????}
          ????fn(resolve)
          ??}
          ??then(onResolvedCallback)?{
          ????return?new?MyPromise((resolve)?=>?{
          ??????this.callbacks.push(()?=>?{
          ????????const?res?=?onResolvedCallback(this.data)
          ????????if?(res?instanceof?MyPromise)?{
          ??????????res.then(resolve)
          ????????}?else?{
          ??????????resolve(res)
          ????????}
          ??????})
          ????})
          ??}
          }
          //?這是測試案例
          new?MyPromise((resolve)?=>?{
          ??setTimeout(()?=>?{
          ????resolve(1)
          ??},?1000)
          }).then((res)?=>?{
          ????console.log(res)
          ????return?new?MyPromise((resolve)?=>?{
          ??????setTimeout(()?=>?{
          ????????resolve(2)
          ??????},?1000)
          ????})
          }).then(res?=>{console.log(res)})
          復(fù)制代碼

          4.2 Promise.all

                MyPromise.all?=?function?(promisesList)?{
          ??return?new?MyPromise((resolve,?reject)?=>?{
          ????if?(!Array.isArray(promiselList)?return?reject(new?Error('必須是數(shù)組'))
          ????if?(!promisesList.length)?return?resolve([])
          ????let?arr?=?[],?count?=?0
          ????//?直接循環(huán)同時執(zhí)行傳進(jìn)來的promise
          ????for?(let?i?=?0,?len?=?promisesList.length;?i?<?len;?i++)?{
          ??????//?因為有可能是?promise?有可能不是,所以用resolve()不管是不是都會自動轉(zhuǎn)成promise
          ??????Promise.resolve(promise).then(result?=>?{
          ??????????//?由到promise在初始化的時候就執(zhí)行了,.then只是拿結(jié)果而已,所以執(zhí)行完成的順序有可能和傳進(jìn)來的數(shù)組不一樣
          ??????????//?也就是說直接push到arr的話,順序有可能會出錯
          ??????????count++
          ??????????arr[i]?=?result
          ??????????//?不能用arr.length===len,是因為數(shù)組的特性
          ??????????//?arr=[];?arr[3]='xx';?console.log(arr.length)?這打印出來會是4?而不是1
          ??????????if(count?===?len)?resolve(arr)
          ??????}).catch(err?=>?reject(err))
          ????}
          ??})
          }
          復(fù)制代碼

          4.3 Promise.race

          傳參和上面的 all 一模一樣,傳入一個 Promise 實例集合的數(shù)組,然后全部同時執(zhí)行,誰先快先執(zhí)行完就返回誰,只返回一個結(jié)果

                MyPromise.race?=?function(promisesList)?{
          ??return?new?MyPromise((resolve,?reject)?=>?{
          ????//?直接循環(huán)同時執(zhí)行傳進(jìn)來的promise
          ????for?(const?promise?of?promisesList)?{
          ??????//?直接返回出去了,所以只有一個,就看哪個快
          ??????promise.then(resolve,?reject)
          ????}
          ??})
          }
          復(fù)制代碼

          5. 防抖和節(jié)流

          函數(shù)防抖是指在事件被觸發(fā) n 秒后再執(zhí)行回調(diào),如果在這 n 秒內(nèi)事件又被觸發(fā),則重新計時。這可以使用在一些點擊請求的事件上,避免因為用戶的多次點擊向后端發(fā)送多次請求。

          函數(shù)節(jié)流是指規(guī)定一個單位時間,在這個單位時間內(nèi),只能有一次觸發(fā)事件的回調(diào)函數(shù)執(zhí)行,如果在同一個單位時間內(nèi)某事件被觸發(fā)多次,只有一次能生效。節(jié)流可以使用在 scroll 函數(shù)的事件監(jiān)聽上,通過事件節(jié)流來降低事件調(diào)用的頻率。

                //?//防抖
          function?debounce(fn,?date)?{
          ??let?timer??//聲明接收定時器的變量
          ??return?function?(...arg)?{??//?獲取參數(shù)
          ????timer?&&?clearTimeout(timer)??//?清空定時器
          ????timer?=?setTimeout(()?=>?{??//??生成新的定時器
          ??????//因為箭頭函數(shù)里的this指向上層作用域的this,所以這里可以直接用this,不需要聲明其他的變量來接收
          ??????fn.apply(this,?arg)?//?fn()
          ????},?date)
          ??}
          }
          //--------------------------------
          //?節(jié)流
          function?debounce(fn,?data)?{
          ??let?timer?=?+new?Date()??//?聲明初始時間
          ??return?function?(...arg)?{?//?獲取參數(shù)
          ????let?newTimer?=?+new?Date()??//?獲取觸發(fā)事件的時間
          ????if?(newTimer?-?timer?>=?data)?{??//?時間判斷,是否滿足條件
          ??????fn.apply(this,?arg)??//?調(diào)用需要執(zhí)行的函數(shù),修改this值,并且傳入?yún)?shù)
          ??????timer?=?+new?Date()?//?重置初始時間
          ????}
          ??}
          }
          復(fù)制代碼

          6. 手寫 call 函數(shù)

          call 函數(shù)的實現(xiàn)步驟:

          1.             判斷調(diào)用對象是否為函數(shù),即使我們是定義在函數(shù)的原型上的,但是可能出現(xiàn)使用 call 等方式調(diào)用的情況。
          2.             判斷傳入上下文對象是否存在,如果不存在,則設(shè)置為 window 。
          3.             處理傳入的參數(shù),截取第一個參數(shù)后的所有參數(shù)。
          4.             將函數(shù)作為上下文對象的一個屬性。
          5.             使用上下文對象來調(diào)用這個方法,并保存返回結(jié)果。
          6.             刪除剛才新增的屬性。
          7.             返回結(jié)果。
                //?call函數(shù)實現(xiàn)
          Function.prototype.myCall?=?function(context)?{
          ??//?判斷調(diào)用對象
          ??if?(typeof?this?!==?"function")?{
          ????console.error("type?error");
          ??}
          ??//?獲取參數(shù)
          ??let?args?=?[...arguments].slice(1),
          ??????result?=?null;
          ??//?判斷?context?是否傳入,如果未傳入則設(shè)置為?window
          ??context?=?context?||?window;
          ??//?將調(diào)用函數(shù)設(shè)為對象的方法
          ??context.fn?=?this;
          ??//?調(diào)用函數(shù)
          ??result?=?context.fn(...args);
          ??//?將屬性刪除
          ??delete?context.fn;
          ??return?result;
          };
          復(fù)制代碼

          7. 手寫 apply 函數(shù)

          apply 函數(shù)的實現(xiàn)步驟:

          1.             判斷調(diào)用對象是否為函數(shù),即使我們是定義在函數(shù)的原型上的,但是可能出現(xiàn)使用 call 等方式調(diào)用的情況。
          2.             判斷傳入上下文對象是否存在,如果不存在,則設(shè)置為 window 。
          3.             將函數(shù)作為上下文對象的一個屬性。
          4.             判斷參數(shù)值是否傳入
          5.             使用上下文對象來調(diào)用這個方法,并保存返回結(jié)果。
          6.             刪除剛才新增的屬性
          7.             返回結(jié)果
                //?apply?函數(shù)實現(xiàn)
          Function.prototype.myApply?=?function(context)?{
          ??//?判斷調(diào)用對象是否為函數(shù)
          ??if?(typeof?this?!==?"function")?{
          ????throw?new?TypeError("Error");
          ??}
          ??let?result?=?null;
          ??//?判斷?context?是否存在,如果未傳入則為?window
          ??context?=?context?||?window;
          ??//?將函數(shù)設(shè)為對象的方法
          ??context.fn?=?this;
          ??//?調(diào)用方法
          ??if?(arguments[1])?{
          ????result?=?context.fn(...arguments[1]);
          ??}?else?{
          ????result?=?context.fn();
          ??}
          ??//?將屬性刪除
          ??delete?context.fn;
          ??return?result;
          };
          復(fù)制代碼

          8. 手寫 bind 函數(shù)

          bind 函數(shù)的實現(xiàn)步驟:

          1.             判斷調(diào)用對象是否為函數(shù),即使我們是定義在函數(shù)的原型上的,但是可能出現(xiàn)使用 call 等方式調(diào)用的情況。
          2.             保存當(dāng)前函數(shù)的引用,獲取其余傳入?yún)?shù)值。
          3.             創(chuàng)建一個函數(shù)返回
          4.             函數(shù)內(nèi)部使用 apply 來綁定函數(shù)調(diào)用,需要判斷函數(shù)作為構(gòu)造函數(shù)的情況,這個時候需要傳入當(dāng)前函數(shù)的 this 給 apply 調(diào)用,其余情況都傳入指定的上下文對象。
                //?bind?函數(shù)實現(xiàn)
          Function.prototype.myBind?=?function(context)?{
          ??//?判斷調(diào)用對象是否為函數(shù)
          ??if?(typeof?this?!==?"function")?{
          ????throw?new?TypeError("Error");
          ??}
          ??//?獲取參數(shù)
          ??var?args?=?[...arguments].slice(1),
          ??????fn?=?this;
          ??return?function?Fn()?{
          ????//?根據(jù)調(diào)用方式,傳入不同綁定值
          ????return?fn.apply(
          ??????this?instanceof?Fn???this?:?context,
          ??????args.concat(...arguments)
          ????);
          ??};
          };
          復(fù)制代碼

          9. 函數(shù)柯里化的實現(xiàn)

          函數(shù)柯里化指的是一種將使用多個參數(shù)的一個函數(shù)轉(zhuǎn)換成一系列使用一個參數(shù)的函數(shù)的技術(shù)。

                
          function?curry(fn,?...args)?{
          ??return?fn.length?<=?args.length???fn(...args)?:?curry.bind(null,?fn,?...args);
          }
          復(fù)制代碼

          10. 手寫AJAX請求

          創(chuàng)建AJAX請求的步驟:

          • 創(chuàng)建一個 XMLHttpRequest 對象。
          • 在這個對象上使用 open 方法創(chuàng)建一個 HTTP 請求,open 方法所需要的參數(shù)是請求的方法、請求的地址、是否異步和用戶的認(rèn)證信息。
          • 在發(fā)起請求前,可以為這個對象添加一些信息和監(jiān)聽函數(shù)。比如說可以通過 setRequestHeader 方法來為請求添加頭信息。還可以為這個對象添加一個狀態(tài)監(jiān)聽函數(shù)。一個 XMLHttpRequest 對象一共有 5 個狀態(tài),當(dāng)它的狀態(tài)變化時會觸發(fā)onreadystatechange 事件,可以通過設(shè)置監(jiān)聽函數(shù),來處理請求成功后的結(jié)果。當(dāng)對象的 readyState 變?yōu)?4 的時候,代表服務(wù)器返回的數(shù)據(jù)接收完成,這個時候可以通過判斷請求的狀態(tài),如果狀態(tài)是 2xx 或者 304 的話則代表返回正常。這個時候就可以通過 response 中的數(shù)據(jù)來對頁面進(jìn)行更新了。
          • 當(dāng)對象的屬性和監(jiān)聽函數(shù)設(shè)置完成后,最后調(diào)用 sent 方法來向服務(wù)器發(fā)起請求,可以傳入?yún)?shù)作為發(fā)送的數(shù)據(jù)體。
                const?SERVER_URL?=?"/server";
          let?xhr?=?new?XMLHttpRequest();
          //?創(chuàng)建?Http?請求
          xhr.open("GET",?SERVER_URL,?true);
          //?設(shè)置狀態(tài)監(jiān)聽函數(shù)
          xhr.onreadystatechange?=?function()?{
          ??if?(this.readyState?!==?4)?return;
          ??//?當(dāng)請求成功時
          ??if?(this.status?===?200)?{
          ????handle(this.response);
          ??}?else?{
          ????console.error(this.statusText);
          ??}
          };
          //?設(shè)置請求失敗時的監(jiān)聽函數(shù)
          xhr.onerror?=?function()?{
          ??console.error(this.statusText);
          };
          //?設(shè)置請求頭信息
          xhr.responseType?=?"json";
          xhr.setRequestHeader("Accept",?"application/json");
          //?發(fā)送?Http?請求
          xhr.send(null);
          復(fù)制代碼

          11. 使用Promise封裝AJAX請求

                // promise 封裝實現(xiàn):
          function?getJSON(url)?{
          ??//?創(chuàng)建一個?promise?對象
          ??let?promise?=?new?Promise(function(resolve,?reject)?{
          ????let?xhr?=?new?XMLHttpRequest();
          ????//?新建一個?http?請求
          ????xhr.open("GET",?url,?true);
          ????//?設(shè)置狀態(tài)的監(jiān)聽函數(shù)
          ????xhr.onreadystatechange?=?function()?{
          ??????if?(this.readyState?!==?4)?return;
          ??????//?當(dāng)請求成功或失敗時,改變?promise?的狀態(tài)
          ??????if?(this.status?===?200)?{
          ????????resolve(this.response);
          ??????}?else?{
          ????????reject(new?Error(this.statusText));
          ??????}
          ????};
          ????//?設(shè)置錯誤監(jiān)聽函數(shù)
          ????xhr.onerror?=?function()?{
          ??????reject(new?Error(this.statusText));
          ????};
          ????//?設(shè)置響應(yīng)的數(shù)據(jù)類型
          ????xhr.responseType?=?"json";
          ????//?設(shè)置請求頭信息
          ????xhr.setRequestHeader("Accept",?"application/json");
          ????//?發(fā)送?http?請求
          ????xhr.send(null);
          ??});
          ??return?promise;
          }
          復(fù)制代碼

          12. 手寫深拷貝

                ?function?fn(obj)?{
          ??????//?判斷數(shù)據(jù)是否是復(fù)雜類型
          ??????if?(obj?instanceof?Object)?{
          ????????//判斷數(shù)據(jù)是否是數(shù)組
          ????????if?(Array.isArray(obj))?{
          ??????????//聲明一個空數(shù)組來接收拷貝后的數(shù)據(jù)
          ??????????let?result?=?[]
          ??????????obj.forEach(item?=>?{
          ????????????//?需要遞歸深層遍歷,否則復(fù)制的是地址
          ????????????result.push(fn(item))
          ??????????})
          ??????????//?返回輸出這個數(shù)組,數(shù)組拷貝完成
          ??????????return?result
          ????????}?else?{
          ??????????//如果是對象,就聲明一個空對象來接收拷貝后的數(shù)據(jù)
          ??????????let?result?=?{}
          ??????????for?(let?k?in?obj)?{
          ????????????//?使用遞歸深層遍歷
          ????????????result[k]?=?fn(obj[k])
          ??????????}
          ??????????//?返回輸出這個對象,對象拷貝完成
          ??????????return?result
          ????????}
          ??????}
          ??????//?簡單數(shù)據(jù)類型則直接返回輸出
          ??????return?obj
          ????}
          復(fù)制代碼

          13. 手寫打亂數(shù)組順序的方法

          主要的實現(xiàn)思路就是:

          • 取出數(shù)組的第一個元素,隨機(jī)產(chǎn)生一個索引值,將該第一個元素和這個索引對應(yīng)的元素進(jìn)行交換。
          • 第二次取出數(shù)據(jù)數(shù)組第二個元素,隨機(jī)產(chǎn)生一個除了索引為1的之外的索引值,并將第二個元素與該索引值對應(yīng)的元素進(jìn)行交換
          • 按照上面的規(guī)律執(zhí)行,直到遍歷完成
                let arr = [1,2,3,4,5,6,7,8,9,10];
          for (let i = 0; i < arr.length; i++) {
          ?const randomIndex = Math.round(Math.random() * (arr.length - 1 - i)) + i;
          [arr[i], arr[randomIndex]] = [arr[randomIndex], arr[i]];
          }
          console.log(arr)

          復(fù)制代碼

          14. 實現(xiàn)數(shù)組扁平化

          通過循環(huán)遞歸的方式,一項一項地去遍歷,如果每一項還是一個數(shù)組,那么就繼續(xù)往下遍歷,利用遞歸程序的方法,來實現(xiàn)數(shù)組的每一項的連接:

                let arr = [1, [2, [3, 4, 5]]];
          function flatten(arr) {
          ?let result = [];

          ?for(let i = 0; i < arr.length; i++) {
          ? ?if(Array.isArray(arr[i])) {
          ? ? ?result = result.concat(flatten(arr[i]));
          ? } else {
          ? ? ?result.push(arr[i]);
          ? }
          }
          ?return result;
          }
          flatten(arr); ?// [1, 2, 3, 4,5]
          復(fù)制代碼

          15. 實現(xiàn)數(shù)組的flat方法

                function?_flat(arr,?depth)?{
          ??if(!Array.isArray(arr)?||?depth?<=?0)?{
          ????return?arr;
          ??}
          ??return?arr.reduce((prev,?cur)?=>?{
          ????if?(Array.isArray(cur))?{
          ??????return?prev.concat(_flat(cur,?depth?-?1))
          ????}?else?{
          ??????return?prev.concat(cur);
          ????}
          ??},?[]);
          }
          復(fù)制代碼

          16. 實現(xiàn)數(shù)組的push方法

                let arr = [];
          Array.prototype.push = function() {
          for( let i = 0 ; i < arguments.length ; i++){
          this[this.length] = arguments[i] ;
          }
          return this.length;
          }

          復(fù)制代碼

          17. 實現(xiàn)數(shù)組的filter方法

                Array.prototype._filter?=?function(fn)?{
          ????if?(typeof?fn?!==?"function")?{
          ????????throw?Error('參數(shù)必須是一個函數(shù)');
          ????}
          ????const?res?=?[];
          ????for?(let?i?=?0,?len?=?this.length;?i?<?len;?i++)?{
          ????????fn(this[i])?&&?res.push(this[i]);
          ????}
          ????return?res;
          }
          復(fù)制代碼

          18. 實現(xiàn)數(shù)組的map方法

                Array.prototype._map?=?function(fn)?{
          ???if?(typeof?fn?!==?"function")?{
          ????????throw?Error('參數(shù)必須是一個函數(shù)');
          ????}
          ????const?res?=?[];
          ????for?(let?i?=?0,?len?=?this.length;?i?<?len;?i++)?{
          ????????res.push(fn(this[i]));
          ????}
          ????return?res;
          }
          復(fù)制代碼

          19. 實現(xiàn) add(1)(2)(3)(4)

          可以實現(xiàn)任意數(shù)量數(shù)字相加,但是需要用+號隱式轉(zhuǎn)換

                 function fn() {
          ? ? ?let result = [];
          ? ? ?function add(...args) {
          ? ? ? ?// ...args剩余參數(shù),可以獲取到傳進(jìn)來的參數(shù)
          ? ? ? ?result = [...result, ...args]
          ? ? ? ?return add;
          ? ? };
          ? ? ?// 創(chuàng)建一個取代 valueOf 方法的函數(shù),覆蓋自定義對象的 valueOf 方法
          ? ? ?add.toString = () => result.reduce((sum, k) => sum + k, 0);
          ? ? ?return add;
          ? };
          let add = fn()
          ? console.log(+add(1)(2)(3)(4)) // --->10
          ? ?// let add2 = fn();
          ? ?console.log(+add2(1, 2, 3)(4)) // --->10
          復(fù)制代碼

          參數(shù)固定的情況下,不需要用+號,可以根據(jù)參數(shù)長度來判斷返回值

                 ? ?function currying(fn, length) {
          ? ? ?length = length || fn.length; // 第一次調(diào)用,給length賦值fn的長度,后面每次重復(fù)調(diào)用,length的長度都會減去參數(shù)的長度
          ? ? ?return function (...args) {
          ? ? ? ?return args.length >= length // 當(dāng)前傳遞進(jìn)來的參數(shù)的長度與length長度進(jìn)行比較
          ? ? ? ? ?? fn.apply(this, args) // 把最后一組實參傳給為賦值的形參,此時所有形參都已賦值,并調(diào)用fn函數(shù)
          ? ? ? ? : currying(fn.bind(this, ...args), length - args.length)
          ? ? ? ?// 每一次調(diào)用fn.bind,都會把當(dāng)前的args里的實參依次傳給fn的形參,length的長度減去參數(shù)的長度
          ? ? ? ?// 相當(dāng)于fn.bind(this, 1).bind(this, 2, 3),bind的連續(xù)調(diào)用,來填充fn的參數(shù)
          ? ? ? ?// 直到某一次調(diào)用,fn的形參即將全部都被賦值時,條件成立,會執(zhí)行fn.apply,把最后的參數(shù)傳遞過去,并且調(diào)用fn
          ? ? }
          ? }
          ? ?function fn(a, b, c, d) {
          ? ? ?return a + b + c + d
          ? }
          ? ?const add = currying(fn)
          ? ?add(4)(3)(1)(2) //10
          ? ?add(1, 3)(4)(2) //10
          ? ?add(1)(3, 4, 2) //10
          復(fù)制代碼

          20. 用Promise實現(xiàn)圖片的異步加載

                let?imageAsync=(url)=>{
          ????????????return?new?Promise((resolve,reject)=>{
          ????????????????let?img?=?new?Image();
          ????????????????img.src?=?url;
          ????????????????img.οnlοad=()=>{
          ????????????????????console.log(`圖片請求成功,此處進(jìn)行通用操作`);
          ????????????????????resolve(image);
          ????????????????}
          ????????????????img.οnerrοr=(err)=>{
          ????????????????????console.log(`失敗,此處進(jìn)行失敗的通用操作`);
          ????????????????????reject(err);
          ????????????????}
          ????????????})
          ????????}
          ????????
          imageAsync("url").then(()=>{
          ????console.log("加載成功");
          }).catch((error)=>{
          ????console.log("加載失敗");
          })
          復(fù)制代碼

          21. 手寫發(fā)布-訂閱模式

                class?EventCenter{
          ??//?1.?定義事件容器,用來裝事件數(shù)組
          ????let?handlers?=?{}

          ??// 2. 添加事件方法,參數(shù):事件名?事件方法
          ??addEventListener(type,?handler)?{
          ????//?創(chuàng)建新數(shù)組容器
          ????if?(!this.handlers[type])?{
          ??????this.handlers[type]?=?[]
          ????}
          ????//?存入事件
          ????this.handlers[type].push(handler)
          ??}

          ??// 3. 觸發(fā)事件,參數(shù):事件名?事件參數(shù)
          ??dispatchEvent(type,?params)?{
          ????//?若沒有注冊該事件則拋出錯誤
          ????if?(!this.handlers[type])?{
          ??????return?new?Error('該事件未注冊')
          ????}
          ????//?觸發(fā)事件
          ????this.handlers[type].forEach(handler?=>?{
          ??????handler(...params)
          ????})
          ??}

          ??// 4. 事件移除,參數(shù):事件名?要刪除事件,若無第二個參數(shù)則刪除該事件的訂閱和發(fā)布
          ??removeEventListener(type,?handler)?{
          ????if?(!this.handlers[type])?{
          ??????return?new?Error('事件無效')
          ????}
          ????if?(!handler)?{
          ??????//?移除事件
          ??????delete?this.handlers[type]
          ????}?else?{
          ??????const?index?=?this.handlers[type].findIndex(el?=>?el?===?handler)
          ??????if?(index?===?-1)?{
          ????????return?new?Error('無該綁定事件')
          ??????}
          ??????//?移除事件
          ??????this.handlers[type].splice(index,?1)
          ??????if?(this.handlers[type].length?===?0)?{
          ????????delete?this.handlers[type]
          ??????}
          ????}
          ??}
          }
          復(fù)制代碼

          22. Object.defineProperty(簡易版)

                ?//??Vue2的響應(yīng)式原理,結(jié)合了Object.defineProperty的數(shù)據(jù)劫持,以及發(fā)布訂閱者模式
          ?//??Vue2的數(shù)據(jù)劫持,就是通過遞歸遍歷data里的數(shù)據(jù),用Object.defineProperty給每一個屬性添加getter和setter,
          ?//??并且把data里的屬性掛載到vue實例中,修改vue實例上的屬性時,就會觸發(fā)對應(yīng)的setter函數(shù),向Dep訂閱器發(fā)布更新消息,
          ?//??對應(yīng)的Watcher訂閱者會收到通知,調(diào)用自身的回調(diào)函數(shù),讓編譯器去更新視圖。
          ????const?obj?=?{
          ??????name:?'劉逍',
          ??????age:?20
          ????}
          ????const?p?=?{}
          ????for?(let?key?in?obj)?{
          ??????Object.defineProperty(p,?key,?{
          ????????get()?{
          ??????????console.log(`有人讀取p里的${key}屬性`);
          ??????????return?obj[key]
          ????????},
          ????????set(val)?{
          ??????????console.log(`有人修改了p里的${key}屬性,值為${val},需要去更新視圖`);
          ??????????obj[key]?=?val
          ????????}
          ??????})
          ????}
          復(fù)制代碼

          23. Proxy數(shù)據(jù)劫持(簡易版)

                ?//?Vue3的數(shù)據(jù)劫持通過Proxy函數(shù)對代理對象的屬性進(jìn)行劫持,通過Reflect對象里的方法對代理對象的屬性進(jìn)行修改,
          ?//?Proxy代理對象不需要遍歷,配置項里的回調(diào)函數(shù)可以通過參數(shù)拿到修改屬性的鍵和值
          ?//?這里用到了Reflect對象里的三個方法,get,set和deleteProperty,方法需要的參數(shù)與配置項中回調(diào)函數(shù)的參數(shù)相同。
          ?// Reflect里的方法與Proxy里的方法是一一對應(yīng)的,只要是Proxy對象的方法,就能在Reflect對象上找到對應(yīng)的方法。
          ???const?obj?=?{
          ??????name:?'劉逍',
          ??????age:?20
          ????}
          ???const?p?=?new?Proxy(obj,?{
          ??????//?讀取屬性的時候會調(diào)用getter
          ??????get(target,?propName)?{??//第一個參數(shù)為代理的源對象,等同于上面的Obj參數(shù)。第二個參數(shù)為讀取的那個屬性值
          ????????console.log(`有人讀取p對象里的${propName}屬性`);
          ????????return?Reflect.get(target,?propName)
          ??????},
          ??????//?添加和修改屬性的時候會調(diào)用setter
          ??????set(target,?propName,?value)?{?//參數(shù)等同于get,第三個參數(shù)為修改后的屬性值
          ????????console.log(`有人修改了p對象里的${propName}屬性,值為${value},需要去修改視圖`);
          ????????Reflect.set(target,?propName,?value)
          ??????},
          ??????//?刪除屬性時,調(diào)用deleteProperty
          ??????deleteProperty(target,?propName)?{?//?參數(shù)等同于get
          ????????console.log(`有人刪除了p對象里的${propName}屬性,需要去修改視圖`);
          ????????return?Reflect.deleteProperty(target,?propName)
          ??????}
          ????})
          復(fù)制代碼

          24. 實現(xiàn)路由(簡易版)

                //?hash路由
          class?Route{
          ??constructor(){
          ????//?路由存儲對象
          ????this.routes?=?{}
          ????//?當(dāng)前hash
          ????this.currentHash?=?''
          ????//?綁定this,避免監(jiān)聽時this指向改變
          ????this.freshRoute?=?this.freshRoute.bind(this)
          ????//?監(jiān)聽
          ????window.addEventListener('load',?this.freshRoute,?false)
          ????window.addEventListener('hashchange',?this.freshRoute,?false)
          ??}
          ??//?存儲
          ??storeRoute?(path,?cb)?{
          ????this.routes[path]?=?cb?||?function?()?{}
          ??}
          ??//?更新
          ??freshRoute?()?{
          ????this.currentHash?=?location.hash.slice(1)?||?'/'
          ????this.routes[this.currentHash]()
          ??}
          }
          復(fù)制代碼

          25. 使用 setTimeout 實現(xiàn) setInterval

          實現(xiàn)思路是使用遞歸函數(shù),不斷地去執(zhí)行 setTimeout 從而達(dá)到 setInterval 的效果

                function mySetInterval(fn, timeout) {
          ?// 控制器,控制定時器是否繼續(xù)執(zhí)行
          ?var timer = {
          ? ?flag: true
          };
          ?// 設(shè)置遞歸函數(shù),模擬定時器執(zhí)行。
          ?function interval() {
          ? ?if (timer.flag) {
          ? ? ?fn();
          ? ? ?setTimeout(interval, timeout);
          ? }
          }
          ?// 啟動定時器
          ?setTimeout(interval, timeout);
          ?// 返回控制器
          ?return timer;
          }
          復(fù)制代碼

          26. 使用setInterval實現(xiàn)setTimeout

                 ? ?function mySetInterval(fn, t) {
          ? ? ?const timer = setInterval(() => {
          ? ? ? ?clearInterval(timer)
          ? ? ? ?fn()
          ? ? }, t)
          ? }

          ? ?mySetInterval(() => {
          ? ? ?console.log('hoho');
          ? }, 1000)
          復(fù)制代碼

          27. 實現(xiàn) jsonp

                // 動態(tài)的加載js文件
          function addScript(src) {
          ?const script = document.createElement('script');
          ?script.src = src;
          ?script.type = "text/javascript";
          ?document.body.appendChild(script);
          }
          addScript("http://xxx.xxx.com/xxx.js?callback=handleRes");
          // 設(shè)置一個全局的callback函數(shù)來接收回調(diào)結(jié)果
          function handleRes(res) {
          ?console.log(res);
          }
          // 接口返回的數(shù)據(jù)格式
          handleRes({a: 1, b: 2});
          復(fù)制代碼

          28. 提取出url 里的參數(shù)并轉(zhuǎn)成對象

                function?getUrlParams(url){
          ??let?reg?=?/([^?&=]+)=([^?&=]+)/g
          ??let?obj?=?{?}
          ??url.replace(reg,?function(){
          ??????obj[arguments[1]]?=?arguments[2]
          ??})
          ??//?或者
          ??const?search?=?window.location.search
          ??search.replace(/([^&=?]+)=([^&]+)/g,?(m,?$1,?$2)=>{obj[$1]?=?decodeURIComponent($2)})
          ??
          ??return?obj
          }
          let?url?=?'https://www.junjin.cn?a=1&b=2'
          console.log(getUrlParams(url))?//?{?a:?1,?b:?2?}
          復(fù)制代碼

          29. 請寫至少三種數(shù)組去重的方法?(原生js)

                //利用filter
          function?unique(arr)?{
          ??return?arr.filter(function(item,?index,?arr)?{
          ????//當(dāng)前元素,在原始數(shù)組中的第一個索引==當(dāng)前索引值,否則返回當(dāng)前元素
          ????return?arr.indexOf(item,?0)?===?index;
          ??});
          }
          ????var?arr?=?[1,1,'true','true',true,true,15,15,false,false,?undefined,undefined,?null,null,?NaN,?NaN,'NaN',?0,?0,?'a',?'a',{},{}];
          ????????console.log(unique(arr))
          復(fù)制代碼
                //利用ES6?Set去重(ES6中最常用)
          function?unique?(arr)?{
          ??return?Array.from(new?Set(arr))
          }
          var?arr?=?[1,1,'true','true',true,true,15,15,false,false,?undefined,undefined,?null,null,?NaN,?NaN,'NaN',?0,?0,?'a',?'a',{},{}];
          console.log(unique(arr))
          ?//[1,?"true",?true,?15,?false,?undefined,?null,?NaN,?"NaN",?0,?"a",?{},?{}]
          復(fù)制代碼
                //利用for嵌套for,然后splice去重(ES5中最常用)
          function unique (arr) {
          ? ? ? ?for(var i=0; i<arr.length; i++){
          ? ? ? ? ? ?for(var j=i+1; j<arr.length; j++){
          ? ? ? ? ? ? ? ?if(arr[i]==arr[j]){ ? ? ? ? //第一個等同于第二個,splice方法刪除第二個
          ? ? ? ? ? ? ? ? ? ?arr.splice(j,1);
          ? ? ? ? ? ? ? ? ? ?j--;
          ? ? ? ? ? ? ? }
          ? ? ? ? ? }
          ? ? ? }
          return arr;
          }
          var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
          ? ?console.log(unique(arr))
          ? ?//[1, "true", 15, false, undefined, NaN, NaN, "NaN", "a", {…}, {…}] ? ?
          //NaN和{}沒有去重,兩個null直接消失了
          復(fù)制代碼
          二、算法基礎(chǔ)

          1. 時間&空間復(fù)雜度

          • 復(fù)雜度是數(shù)量級(方便記憶、推廣),不是具體數(shù)字。
          • 常見復(fù)雜度大小比較:O(n^2) > O(nlogn) > O(n) > O(logn) > O(1)

          1.1 時間復(fù)雜度

          常見時間復(fù)雜度對應(yīng)關(guān)系:

          • O(n^2):2層循環(huán)(嵌套循環(huán))
          • O(nlogn):快速排序(循環(huán) + 二分)
          • O(n):1層循環(huán)
          • O(logn):二分

          1.2 空間復(fù)雜度

          常見空間復(fù)雜度對應(yīng)關(guān)系:

          • O(n):傳入一個數(shù)組,處理過程生成一個新的數(shù)組大小與傳入數(shù)組一致

          2. 八大數(shù)據(jù)結(jié)構(gòu)

          1. 棧

          是一個后進(jìn)先出的數(shù)據(jù)結(jié)構(gòu)。JavaScript中沒有,但是可以用Array實現(xiàn)的所有功能。

                // 數(shù)組實現(xiàn)棧數(shù)據(jù)結(jié)構(gòu)
          const stack = []

          // 入棧
          stack.push(0)
          stack.push(1)
          stack.push(2)

          // 出棧
          const popVal = stack.pop() // popVal 為 2
          復(fù)制代碼

          使用場景

          • 場景一:十進(jìn)制轉(zhuǎn)二進(jìn)制
          • 場景二:有效括號
          • 場景三:函數(shù)調(diào)用堆棧

          2. 隊列

          隊列是一個先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu)。JavaScript中沒有隊列,但是可以用Array實現(xiàn)隊列的所有功能。

                // 數(shù)組實現(xiàn)隊列數(shù)據(jù)結(jié)構(gòu)
          const queue = []

          // 入隊
          stack.push(0)
          stack.push(1)
          stack.push(2)

          // 出隊
          const shiftVal = stack.shift() // shiftVal 為 0

          復(fù)制代碼

          使用場景

          • 場景一:日常測核酸排隊
          • 場景二:JS異步中的任務(wù)隊列
          • 場景三:計算最近請求次數(shù)

          3. 鏈表

          鏈表是多個元素組成的列表,元素存儲不連續(xù),用next指針連在一起。JavaScript中沒有鏈表,但是可以用Object模擬鏈表。

          使用場景

          • 場景一:JS中的原型鏈
          • 場景二:使用鏈表指針獲取 JSON 的節(jié)點值

          4. 集合

          集合是一個無序且唯一的數(shù)據(jù)結(jié)構(gòu)。ES6中有集合:Set,集合常用操作:去重、判斷某元素是否在集合中、求交集。

                //?去重
          const?arr?=?[1,?1,?2,?2]
          const?arr2?=?[...new?Set(arr)]

          //?判斷元素是否在集合中
          const?set?=?new?Set(arr)
          const?has?=?set.has(3)?//?false

          //?求交集
          const?set2?=?new?Set([2,?3])
          const?set3?=?new?Set([...set].filter(item?=>?set2.has(item)))
          復(fù)制代碼

          使用場景

          • 場景一:求交集、差集

          5. 字典(哈希)

          字典也是一種存儲唯一值的數(shù)據(jù)結(jié)構(gòu),但它以鍵值對的形式存儲。ES6中的字典名為Map,

                //?字典
          const?map?=?new?Map()

          //?增
          map.set('key1',?'value1')
          map.set('key2',?'value2')
          map.set('key3',?'value3')

          //?刪
          map.delete('key3')
          //?map.clear()

          //?改
          map.set('key2',?'value222')

          //?查
          map.get('key2')

          復(fù)制代碼

          使用場景

          • 場景:leetcode刷題

          6. 樹

          是一種分層的數(shù)據(jù)模型。前端常見的樹包括:DOM、樹、級聯(lián)選擇、樹形控件……。JavaScript中沒有,但是可以通過ObjectArray構(gòu)建。樹的常用操作:深度/廣度優(yōu)先遍歷、先中后序遍歷。

          使用場景

          • 場景一:DOM樹
          • 場景二:級聯(lián)選擇器

          7. 圖

          是網(wǎng)絡(luò)結(jié)構(gòu)的抽象模型,是一組由邊連接的節(jié)點。圖可以表示任何二元關(guān)系,比如道路、航班。JS中沒有圖,但是可以用ObjectArray構(gòu)建。圖的表示法:鄰接矩陣、鄰接表、關(guān)聯(lián)矩陣。

          使用場景

          • 場景一:道路
          • 場景二:航班

          8. 堆

          是一種特殊的完全二叉樹。所有的節(jié)點都大于等于(最大堆)或小于等于(最小堆)它的子節(jié)點。由于的特殊結(jié)構(gòu),我們可以用數(shù)組表示

          使用場景

          • 場景:leetcode刷題

          3. 排序方法

          3.1 冒泡排序

          比較兩個記錄鍵值的大小,如果這兩個記錄鍵值的大小出現(xiàn)逆序,則交換這兩個記錄

          每遍歷一個元素,都會把之前的所有相鄰的元素都兩兩比較一遍,即便是已經(jīng)排序好的元素

                //[1,3,4,2]->[1,3,2,4]->[1,2,3,4]->[1,2,3,4]

          let n = 0
          function bubbleSort(arr){
          ? ?for(let i = 1;i < arr.length;i++){
          ? ? ? ?for(let j = i;j > 0;j--){
          ? ? ? ? ? ?n++ // 1+2+3+...+arr.length-1
          ? ? ? ? ? ?if(arr[j] < arr[j-1]){
          ? ? ? ? ? ? ? [arr[j],arr[j-1]] = [arr[j-1],arr[j]];
          ? ? ? ? ? }
          ? ? ? }
          ? }
          ? ?return arr;
          }

          復(fù)制代碼

          3.2 插入排序

          第i(i大于等于1)個記錄進(jìn)行插入操作時,R1、 R2,...,是排好序的有序數(shù)列,取出第i個元素,在序列中找到一個合適的位置并將她插入到該位置上即可。

          相當(dāng)于把當(dāng)前遍歷的元素取出,在序列中找到一個合適的位置將它插入。它的第二層循環(huán)不必遍歷當(dāng)前元素之前的所有元素,因為當(dāng)前元素之前的序列是排序好的,碰到第一個小于當(dāng)前元素的值,就可以停止繼續(xù)向前查找了,然后把當(dāng)前元素插入當(dāng)前位置即可

                
          function insertSort(arr){
          ? ?for(let i = 1;i < arr.length;i++){
          ? ? ? ?let j = i-1;
          ? ? ? ?if(arr[i]<arr[j]){
          ? ? ? ? ? ?let temp = arr[i];
          ? ? ? ? ? ?while(j >= 0 && temp < arr[j]){
          ? ? ? ? ? ? ? ?arr[j+1] = arr[j];
          ? ? ? ? ? ? ? ?j--;
          ? ? ? ? ? }
          ? ? ? ? ? ?arr[j+1] = temp;
          ? ? ? }
          ? }
          ? ?return arr;
          }

          //[1,3,4,2] ->[1,3,4,4]->[1,3,3,4]->[1,2,3,4]
          //i=3 temp=2 j=2 arr[j]=4 arr[3]=4 [1,3,4,4];j=1 arr[2]=3 [1,3,3,4];j=0 [1,2,3,4]
          復(fù)制代碼

          3.3 希爾排序

          算法先將要排序的一組數(shù)按某個增量d(n/2,n為要排序數(shù)的個數(shù))分成若干組,每組中記錄的下標(biāo)相差d.對每組中全部元素進(jìn)行直接插入排序,然后再用一個較小的增量(d/2)對它進(jìn)行分組,在每組中再進(jìn)行直接插入排序。當(dāng)增量減到1時,進(jìn)行直接插入排序后,排序完成。

                
          function hillSort(arr){
          ? ?let len = arr.length;
          ? ?for(let gap = parseInt(len / 2);gap >= 1;gap = parseInt(gap / 2)){
          ? ? ? ?for(let i = gap;i < len;i++){
          ? ? ? ? ? ?if(arr[i] < arr[i-gap]){
          ? ? ? ? ? ? ? ?let temp = arr[i];
          ? ? ? ? ? ? ? ?let j = i - gap;
          ? ? ? ? ? ? ? ?while(j >= 0 && arr[j] > temp){
          ? ? ? ? ? ? ? ? ? ?arr[j+gap] = arr[j];
          ? ? ? ? ? ? ? ? ? ?j -= gap;
          ? ? ? ? ? ? ? }
          ? ? ? ? ? ? ? ?arr[j+gap] = temp;
          ? ? ? ? ? }
          ? ? ? }
          ? }
          ? ?return arr;
          }

          復(fù)制代碼
          81399da41ff7e6b7206bfc25e3a662cc.webp微信截圖_20221006102742.png

          3.4 選擇排序

          在第i次選擇操作中,通過n-i次鍵值間比較,從n-i+1個記錄中選出鍵值最小的記錄,并和第i(1小于等于1小于等于n-1)個記錄交換

          每一次遍歷,都把當(dāng)前元素與剩下元素里的最小值交換位置

                //[4,1,3,2]->[1,4,3,2]->[1,2,4,3]->[1,2,3,4]

          function selectSort(arr){
          ? ?for(let i = 0;i < arr.length;i++){
          ? ? ? ?let min = Math.min(...arr.slice(i));
          ? ? ? ?let index
          ? ? ? ?for (let j = i; j < arr.length; j++) {
          ? ? ? ? ?if (arr[j] === min) {
          ? ? ? ? ? ?index = j
          ? ? ? ? ? ?break
          ? ? ? ? }
          ? ? ? }
          ? ? ? [arr[i],arr[index]] = [arr[index],arr[i]];
          ? }
          ? ?return arr;
          }

          復(fù)制代碼

          3.5 快排

          在n個記錄中取某一個記錄的鍵值為標(biāo)準(zhǔn),通常取第一個記錄鍵值為基準(zhǔn),通過一趟排序?qū)⒋诺挠涗浄譃樾∮诨虻扔谶@個鍵值的兩個獨立的部分,這是一部分的記錄鍵值均比另一部分記錄的鍵值小,然后,對這兩部分記錄繼續(xù)分別進(jìn)行快速排序,以達(dá)到整個序列有序

          取當(dāng)前排序數(shù)組的第一個值作為基準(zhǔn)值keys,通過一次遍歷把數(shù)組分為right大于基準(zhǔn)值和left小于等于基準(zhǔn)值的兩部分,然后對兩個部分重復(fù)以上步驟排序,最后return的時候按照[left,keys,right]的順序返回

                
          function quickSort(arr){
          ? ?if(arr.length <= 1) return arr;
          ? ?let right = [],left = [],keys = arr.shift();
          ? ?for(let value of arr){
          ? ? ? ?if(value > keys){
          ? ? ? ? ? ?right.push(value)
          ? ? ? }else{
          ? ? ? ? ? ?left.push(value);
          ? ? ? }
          ? }
          ? ?return quickSort(left).concat(keys,quickSort(right));
          }

          //[4,1,3,2]-->quickSort([1,3,2]).concat(4,quickSort([]))
          // ? ? ? ? -->quickSort([]).concant(1,quickSort([3,2])).concat(4,quickSort([]))
          // ? ? ? ? -->quickSort([]).concant(1,quickSort([2]).concant(3)).concat(4,quickSort([]))
          // ? ? ? ? -->[1,2,3,4]
          //keys=4 R[] L[1,3,2] ?
          -------quickSort(left)
          //keys=1 R[3,2] L[]
          //keys=3 R[] L[2]
          //quickSort(left)=[1,2,3]

          復(fù)制代碼

          3.6各排序算法的穩(wěn)定性,時間復(fù)雜度,空間復(fù)雜度

          46ece0233bc10616e050f0dbe3d30b46.webp

          每個語言的排序內(nèi)部實現(xiàn)都是不同的。

          對于 JS 來說,數(shù)組長度大于 10 會采用快排,否則使用插入排序。選擇插入排序是因為雖然時間復(fù)雜度很差,但是在數(shù)據(jù) 量很小的情況下和 O(N * logN) 相差無幾,然而插入排序需要的常數(shù)時間很小,所以相對別的排序來說更快。

          4. JS尾遞歸優(yōu)化斐波拉契數(shù)列

          正常的斐波拉契數(shù)列js實現(xiàn)方式

                const Fibonacci = (n) => {
          ? ?if (n <= 1) return 1;
          ? ?return ?Fibonacci(n - 1) + Fibonacci(n - 2);
          }
          Fibonacci(10) // 89
          Fibonacci(40) // 165580141 計算緩慢有延遲了
          Fibonacci(100) // 棧溢出,無法得到結(jié)果復(fù)制代碼
          復(fù)制代碼

          使用尾遞歸優(yōu)化該方法

                const Fibonacci = (n, sum1 = 1, sum2 = 1) => {
          ? ? if (n <= 1) return sum2;
          ? ? return Fibonacci(n - 1, sum2, sum1 + sum2)
          }
          Fibonacci(10) // 89
          Fibonacci(100) // 573147844013817200000 速度依舊很快
          Fibonacci(1000) // 7.0330367711422765e+208 還是沒有壓力復(fù)制代碼
          復(fù)制代碼
          尾遞歸優(yōu)化可以在數(shù)量較大的計算中,可以起到很好的作用。作者:逍丶 https://juejin.cn/post/7151221875224346637

          祝 您:2022 年暴富!萬事如意!

          點贊和在看就是最大的支持,26ff3f69f9a04a8f6a63db7fb84a3ff1.webp比心??26ff3f69f9a04a8f6a63db7fb84a3ff1.webp

          瀏覽 70
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  激情综合AV| 人人看人人玩人人摸 | 操逼视频在线免费看 | 亚洲丁香视先锋 | 99热男人|