91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

關于JS中一些重要的api實現,鞏固你的原生JS功底

發布時間:2020-03-19 08:37:36 來源:網絡 閱讀:335 作者:可樂程序員 欄目:web開發

在面試中,常常會遇到一些手寫XXX之類的面試題,因此好好總結一下,對于鞏固我們的原生js的基礎是非常必要的。

盡管在網上已經有了非常多的總結文章,但在我看來有一個普遍的問題,那就是把原理性的東西過于復雜化了。如果站在面試官的角度,他的目的是在最短的時間內考察出面試者對于JS語言的理解程度,但是在看了網站的諸多總結文章后我發現其中的代碼有很大一部分是做意義不大的操作,比如實現一個簡單的防抖,只要是核心的流程展示即可,至于其他的一些等模式則沒有必要再去深挖,一大堆的if-else讓人看上去也眼花繚亂,甚至誤導別人直接去背代碼,另外,核心的邏輯都能展示出來,再去橫向的實現其他的類似情況恐怕也不是什么問題了。

在以下的整理中,建議大家先照的核心要點自己寫一遍,然后對照下面的代碼,復習效果更好。本文的目的就在于以最簡潔的代碼幫你從第一性原理的角度理解api的內部運作流程,凡是對于我們理解api沒有幫助的的邊界情況都不做處理

一、用ES5實現數組的map方法

核心要點:

1.回調函數的參數有哪些,返回值如何處理。

2.不修改原來的數組。

Array.prototype.MyMap?=?function(fn,?context){
?var?arr?=?Array.prototype.slice.call(this);//由于是ES5所以就不用...展開符了
?var?mappedArr?=?[];
?for?(var?i?=?0;?i?<?arr.length;?i++?){
?mappedArr.push(fn.call(context,?arr[i],?i,?this));
?}
?return?mappedArr;
}
復制代碼

二、用ES5實現數組的reduce方法

核心要點:

1、初始值不傳怎么處理

2、回調函數的參數有哪些,返回值如何處理。

Array.prototype.myReduce?=?function(fn,?initialValue)?{
?var?arr?=?Array.prototype.slice.call(this);
?var?res,?startIndex;
?res?=?initialValue???initialValue?:?arr[0];
?startIndex?=?initialValue???0?:?1;
?for(var?i?=?startIndex;?i?<?arr.length;?i++)?{
?res?=?fn.call(null,?res,?arr[i],?i,?this);
?}
?return?res;
}
復制代碼

三、實現call/apply

思路: 利用this的上下文特性。

//實現apply只要把下一行中的...args換成args即可?
Function.prototype.myCall?=?function(context?=?window,?...args)?{
?let?func?=?this;
?let?fn?=?Symbol("fn");
?context[fn]?=?func;
?let?res?=?context[fn](...args);//重點代碼,利用this指向,相當于context.caller(...args)
?delete?context[fn];
?return?res;
}
復制代碼

四、實現Object.create方法(常用)

function?create(proto)?{
?function?F()?{};
?F.prototype?=?proto;
?F.prototype.constructor?=?F;
?
?return?new?F();
}
復制代碼

五、實現bind方法

核心要點:

1.對于普通函數,綁定this指向

2.對于構造函數,要保證原函數的原型對象上的屬性不能丟失

Function.prototype.bind?=?function(context,?...args)?{
?let?self?=?this;//謹記this表示調用bind的函數
?let?fBound?=?function()?{
?//this?instanceof?fBound為true表示構造函數的情況。如new?func.bind(obj)
?return?self.apply(this?instanceof?fBound???this?:?context?||?window,?args);
?}
?fBound.prototype?=?Object.create(this.prototype);//保證原函數的原型對象上的屬性不丟失
?return?fBound;
}
復制代碼

大家平時說的手寫bind,其實就這么簡單:)

六、實現new關鍵字

核心要點:

  1. 創建一個全新的對象,這個對象的__proto__要指向構造函數的原型對象

  2. 執行構造函數

  3. 返回值為object類型則作為new方法的返回值返回,否則返回上述全新對象

function?myNew(fn,?...args)?{
?let?instance?=?Object.create(fn.prototype);
?let?res?=?fn.apply(instance,?args);
?return?typeof?res?===?'object'???res:?instance;
}
復制代碼

七、實現instanceof的作用

核心要點:原型鏈的向上查找。

function?myInstanceof(left,?right)?{
?let?proto?=?Object.getPrototypeOf(left);
?while(true)?{
?if(proto?==?null)?return?false;
?if(proto?==?right.prototype)?return?true;
?proto?=?Object.getPrototypeof(proto);
?}
}
復制代碼

八、實現單例模式

核心要點: 用閉包和Proxy屬性攔截

function?proxy(func)?{
?let?instance;
?let?handler?=?{
?constructor(target,?args)?{
?if(!instance)?{
?instance?=?Reflect.constructor(fun,?args);
?}
?return?instance;
?}
?}
?return?new?Proxy(func,?handler);
}
復制代碼

九、實現數組的flat

方式其實很多,之前我做過系統整理,有六種方法,請參考:

JS數組扁平化(flat)方法總結

十、實現防抖功能

核心要點:

如果在定時器的時間范圍內再次觸發,則重新計時。

const?debounce?=?(fn,?delay)?=>?{
?let?timer?=?null;
?return?(...args)?=>?{
?clearTimeout(timer);
?timer?=?setTimeout(()?=>?{
?fn.apply(this,?args);
?},?delay);
?};
};
復制代碼

十一、實現節流功能

核心要點:

如果在定時器的時間范圍內再次觸發,則不予理睬,等當前定時器完成,才能啟動下一個定時器。

const?throttle?=?(fn,?delay?=?500)?=>?{
?let?flag?=?true;
?return?(...args)?=>?{
?if?(!flag)?return;
?flag?=?false;
?setTimeout(()?=>?{
?fn.apply(this,?args);
?flag?=?true;
?},?delay);
?};
};
復制代碼

十二、用發布訂閱模式實現EventEmit

參考我的另一篇文章:

基于"發布-訂閱"的原生JS插件封裝中的手寫發布訂閱部分。

十三、實現深拷貝

以下為簡易版深拷貝,沒有考慮循環引用的情況和Buffer、Promise、Set、Map的處理,如果一一實現,過于復雜,面試短時間寫出來不太現實,如果有興趣可以去這里深入實現:

深拷貝終極探索。

const?clone?=?parent?=>?{
?//?判斷類型
?const?isType?=?(target,?type)?=>?`[object?${type}]`?===?Object.prototype.toString.call(target)
?//?處理正則
?const?getRegExp?=?re?=>?{
?let?flags?=?"";
?if?(re.global)?flags?+=?"g";
?if?(re.ignoreCase)?flags?+=?"i";
?if?(re.multiline)?flags?+=?"m";
?return?flags;
?};
?const?_clone?=?parent?=>?{
?if?(parent?===?null)?return?null;
?if?(typeof?parent?!==?"object")?return?parent;
?let?child,?proto;
?if?(isType(parent,?"Array"))?{
?//?對數組做特殊處理
?child?=?[];
?}?else?if?(isType(parent,?"RegExp"))?{
?//?對正則對象做特殊處理
?child?=?new?RegExp(parent.source,?getRegExp(parent));
?if?(parent.lastIndex)?child.lastIndex?=?parent.lastIndex;
?}?else?if?(isType(parent,?"Date"))?{
?//?對Date對象做特殊處理
?child?=?new?Date(parent.getTime());
?}?else?{
?//?處理對象原型
?proto?=?Object.getPrototypeOf(parent);
?//?利用Object.create切斷原型鏈
?child?=?Object.create(proto);
?}
?for?(let?i?in?parent)?{
?//?遞歸
?child[i]?=?_clone(parent[i]);
?}
?return?child;
?};
?return?_clone(parent);
};
復制代碼

十四、實現Promise

重點難點,比較復雜,請參考我的另一篇步步拆解文章:

我如何實現Promise

十五、使用ES5實現類的繼承效果

也是重點知識,我之前做過詳細拆解,有五個版本,如果每一版本都能說清楚,能夠很好的體現自己對于原型鏈的理解,文章地址:

ES5實現繼承的那些事

?



向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

es5 j
AI

兴隆县| 长治县| 紫云| 河北区| 罗田县| 从化市| 张掖市| 仲巴县| 惠水县| 灵寿县| 昌宁县| 客服| 茌平县| 海城市| 同仁县| 南和县| 包头市| 上林县| 贵南县| 六盘水市| 澄迈县| 洪湖市| 鄱阳县| 密山市| 郴州市| 株洲市| 沂南县| 德化县| 彰武县| 称多县| 罗田县| 磴口县| 手游| 清镇市| 淮北市| 沭阳县| 满洲里市| 佛冈县| 永登县| 冷水江市| 肃北|