5 個提升你 JavaScript 編碼水平的實例

雖然 2020 的今天浓体,各種前端框架、工具林立渐裸,而這些框架跟工具也幫我們提前解決了不少麻煩的問題,但是工具始終是工具装悲,扎實的基本功才是最核心的昏鹃,現(xiàn)在一起來通過幾個實際的代碼片段來提高我們原生 JS 的編碼水平。

在這里小編建了一個前端學習交流扣扣群:1093794329诀诊,我自己整理的最新的前端資料和高級開發(fā)教程洞渤,如果有想需要的,可以加群一起學習交流

判斷數(shù)據(jù)類型

首先來提問一個:typeof是否能正確判斷類型属瓣?

答案是:不可以载迄,因為由于歷史原因,在判斷原始類型時抡蛙,typeof null會等于object护昧。而且對于對象來說,除了函數(shù)粗截,都會轉(zhuǎn)換成object惋耙。例子如下:

typeof 1; // 'number'

typeof "1"; // 'string'

typeof null; //

typeof []; // 'object'

typeof {}; // 'object'

typeof window.alert; // 'function'

再來提問一個,instanceof是否能正確判斷類型慈格?

答案是:還是不可以怠晴,雖然instanceof是通過原型鏈來判斷的,但是對于對象來說浴捆,Array也會被轉(zhuǎn)換成Object蒜田,而且也不能區(qū)分基本類型string和boolean。例如:

function Func() {}

const func = new Func();

console.log(func instanceof Func); // true

const obj = {};

const arr = [];

obj instanceof Object; // true

arr instanceof Object; // true

arr instanceof Array; // true

const str = "abc";

const str2 = new String("abc");

str instanceof String; // false

str2 instanceof String; // true

所以該怎么辦呢选泻?

這時候我們可以使用:Object.prototype.toString.call()

所以為什么冲粤?

因為每個對象都有一個toString()方法,當要將對象表示為文本值或以預期字符串的方式引用對象時页眯,會自動調(diào)用該方法梯捕。默認情況下,從Object派生的每個對象都會繼承toString()方法窝撵。如果此方法未在自定義對象中被覆蓋傀顾,則toString()返回[Object type],其中type是對象類型碌奉。所以就有以下例子:

Object.prototype.toString.call(new Date()); // [object Date]

Object.prototype.toString.call("1"); // [object String]

Object.prototype.toString.call(1); // [object Numer]

Object.prototype.toString.call(undefined); // [object Undefined]

Object.prototype.toString.call(null); // [object Null]

所以綜合上述知識點短曾,我們可以封裝出以下通用類型判斷方法:

var type = function(data) {

var toString = Object.prototype.toString;

var dataType = data instanceof Element

? 'element' // 為了統(tǒng)一DOM節(jié)點類型輸出

: toString

.call(data)

.replace(/\[object\s(.+)\]/, ''$1')

.toLowerCase()

return dataType

}

使用方法如下:

type("a"); // string

type(1); // number

type(window); // window

type(document.querySelector("h1")); // element

通用的數(shù)組/類數(shù)組對象封裝

如果我們使用 ES5/ES6+的數(shù)組 API寒砖,很容易就能夠?qū)?shù)組進行各類的循環(huán)操作,但是如果我們要循環(huán)一個類數(shù)組對象呢嫉拐?

例如NodeList哩都。直接循環(huán)是會報錯的:

document.querySelectorAll("div").map(e => e); // Uncaught TypeError: document.querySelectorAll(...).map is not a function

當然我們可以用擴展運算符:

[...document.querySelectorAll("div")].map(e => e);

那如果我們不用擴展運算符呢?

那么我們就可以利用call的特性婉徘,將NodeList里的元素一個一個的插入到數(shù)組中漠嵌,例子如下:

var listMap = function(array, type, fn) {

return !fn ? array : Array.prototype[type]["call"](array, fn);};

使用方法如下:

var divs = document.querySelectorAll("div");

listMap(divs, "forEach", function(e) {

console.log(e);

});

獲取 dom 元素節(jié)點的偏移量

如果有用過jQuery的童鞋,就一定不會忘記$('').offset()這個 api 的強大功能盖呼,這個 api 可以輕易獲取元素的偏移量儒鹿,那么如果我們不用jQuery該怎么實現(xiàn)呢?

我們先來看看例子:

var getOffset = function(el) {

var scrollTop =

el.getBoundingClientRect().top +

document.body.scrollTop +

document.documentElement.scrollTop;

var scrollLeft =

el.getBoundingClientRect().left +

document.body.scrollLeft +

document.documentElement.scrollLeft;

return {

top: scrollTop,

left: scrollLeft

};

};

首先我們先來看getBoundingClientRect()這個方法几晤。

getBoundingClientRect()方法返回元素的大小及其相對于視口的位置挺身。返回值是一個 DOMRect 對象,是與該元素相關(guān)的 CSS 邊框集合 锌仅。

然后就是document.body.scrollTop 跟 document.documentElement.scrollTop這兩個是一個功能章钾,只不過在不同的瀏覽器下會有一個始終為 0,所以做了以上的兼容性處理热芹。所以當我們做拖拽功能的時候贱傀,就可以依賴上以上屬性。

使用方法如下:

var el = document.querySelector(".moveBox");

getOffset(el); // {top: xxx, left: xxx}

我們可以看上面的搖桿效果伊脓,這里就是利用了offset()去做位置判斷府寒。具體實現(xiàn)代碼可以看:https://codepen.io/krischan77/pen/zYxPNPy

Fade 特效

// Fade in

var fadeIn = function (el) {

el.style.opacity = 0

var last = +new Date()

var tick = function() {

el.style.opacity = +el.style.opacity + (new Date() - last) / 400

last = +new Date()

if (+el.style.opacity < 1) {

requestAnimationFrame(tick))

}

}

tick()

}

// Fade out

var fadeOut = function (el) {

el.style.opacity = 1

var last = +new Date()

var tick = function() {

el.style.opacity = +el.style.opacity - (new Date() - last) / 400

last = +new Date()

if (+el.style.opacity > 0) {

requestAnimationFrame(tick)

}

}

tick()

}

上述是淡入淡出效果的具體實現(xiàn),這里是利用requestAnimationFrame對opacity通過遞歸的方式進行修改报腔。

其實這里需要提一個概念株搔,就是時間分片

這是一個非常重要的概念纯蛾,例如ReactFiber核心實現(xiàn)就是時間分片纤房。它會將一個長任務(wù)切分成一個含有若干小任務(wù)的任務(wù)隊列,然后一個接著一個的執(zhí)行翻诉。

requestAnimationFrame就是這樣一個 API炮姨,它可以根據(jù)系統(tǒng)來決定回調(diào)函數(shù)的執(zhí)行時機,其實也就是在下一次重繪之前更新動畫幀碰煌,因為有這樣的機制舒岸,所以能防止丟幀。

利用隊列的概念進行數(shù)據(jù)操作

隊列(queue)芦圾,是先進先出(FIFO, First-In-First-Out)的線性表蛾派。在具體應(yīng)用中通常用鏈表或者數(shù)組來實現(xiàn)。隊列只允許在后端(稱為 rear)進行插入操作,在前端(稱為 front)進行刪除操作洪乍。

雖然很多人覺得了解數(shù)據(jù)結(jié)構(gòu)對前端作用不大梭依,但是如果我們懂一些基礎(chǔ)的概念,是否在編碼時能夠更加擴散我們的思維呢典尾?我們看下面兩個例子:

獲取節(jié)點在該父節(jié)點下的坐標。

如果我們要操作原生 DOM糊探,那么是繞不開獲取節(jié)點在該父節(jié)點的下標的這個功能的钾埂,那么我們該如何實現(xiàn)呢?

當然就是利用我們的循環(huán)啦科平,對子元素集合進行遍歷褥紫,直到確定下標為止,代碼如下:

var index = function(el) {

if (!el) {

return -1;

}

var i = 0;

while ((el = el.previousElementSibling)) {

i++;

}

return i;

};

清空子節(jié)點

如果我們要清空某個 DOM 節(jié)點的子節(jié)點瞪慧,我們有以下的方法:

var empty = function(el) {

while (el.firstChild) {

el.removeChild(el.firstChild);

}

};

上面只是提供一個思路髓考,其實el.innerHTML = ''會更簡潔。

利用 reduce 進行數(shù)據(jù)優(yōu)化

數(shù)組去重

沒錯弃酌,又是一個老生常談的問題氨菇,數(shù)組去重,但是我們這次去除的不僅僅是單個的數(shù)據(jù)妓湘,而是擁有某個相同鍵值的對象集合查蓉。例如下面的例子,我們有以下的數(shù)據(jù):

牛逼的 reduce

數(shù)據(jù)去重

首先我們來看看一個老生常談的問題榜贴,我們假設(shè)有這樣的一個對象:

const data = [

{

name: "Kris",? ? age: "24"

},

{

name: "Andy",? ? age: "25"

},

{

name: "Kitty",? ? age: "25"

},

{

name: "Andy",? ? age: "25"

},

{

name: "Kitty",? ? age: "25"

},

{

name: "Andy",? ? age: "25"

},

{

name: "Kitty",? ? age: "25"

}];

現(xiàn)在我們要去重里面name重復的對象豌研,這時候我們可以利用reduce,例子如下:

const dataReducer = (prev, cur, idx) => {

let obj = {};

const { name } = cur;

obj[name] = cur;

return {

...prev,

...obj

};

};

const reducedData = data.reduce(dataReducer, {});

let newData = Object.values(reducedData);

批量生成對象元素

在魚頭的實際業(yè)務(wù)中唬党,有一個操作是需要對類似以下的對象進行操作的:

{

a1: 'data',

a2: 'data',

...,

an: 'data'

}

像我這么懶的魚鹃共,肯定不會一個個手寫,所以就有了以下方法

const createList = (item, idx) => {

let obj = {};

obj[`a${idx}`] = "data";

return obj;

};

const listReducer = (acc, cur) => (!acc ? { ...cur } : { ...cur, ...acc });

const obj = Array.from(new Array(20), createList).reduce(listReducer);

小節(jié)

今天的內(nèi)容就和大家分享到這里驶拱,感謝你的閱讀霜浴。如果你喜歡我的分享,麻煩給個關(guān)注蓝纲、點贊加轉(zhuǎn)發(fā)哦坷随,你的支持,就是我分享的動力驻龟,后續(xù)會持續(xù)分享代碼片段温眉,歡迎持續(xù)關(guān)注。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末翁狐,一起剝皮案震驚了整個濱河市类溢,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖闯冷,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件砂心,死亡現(xiàn)場離奇詭異,居然都是意外死亡蛇耀,警方通過查閱死者的電腦和手機辩诞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來纺涤,“玉大人译暂,你說我怎么就攤上這事×么叮” “怎么了外永?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長拧咳。 經(jīng)常有香客問我伯顶,道長,這世上最難降的妖魔是什么骆膝? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任祭衩,我火速辦了婚禮,結(jié)果婚禮上阅签,老公的妹妹穿的比我還像新娘汪厨。我一直安慰自己,他們只是感情好愉择,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布劫乱。 她就那樣靜靜地躺著,像睡著了一般锥涕。 火紅的嫁衣襯著肌膚如雪衷戈。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天层坠,我揣著相機與錄音殖妇,去河邊找鬼。 笑死破花,一個胖子當著我的面吹牛谦趣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播座每,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼前鹅,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了峭梳?” 一聲冷哼從身側(cè)響起舰绘,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后捂寿,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體口四,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年秦陋,在試婚紗的時候發(fā)現(xiàn)自己被綠了蔓彩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡驳概,死狀恐怖赤嚼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情抡句,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布杠愧,位于F島的核電站待榔,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏流济。R本人自食惡果不足惜锐锣,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望绳瘟。 院中可真熱鬧雕憔,春花似錦、人聲如沸糖声。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蘸泻。三九已至琉苇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間悦施,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留瑰枫,地道東北人秤朗。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像昼汗,于是被迫代替她去往敵國和親肴熏。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

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