初學者也能看懂的 Vue2 源碼中那些實用的基礎工具函數

1. 前言

大家好,我是若川。最近組織了源碼共讀活動,感興趣的可以加我微信 ruochuan12

想學源碼,極力推薦之前我寫的《學習源碼整體架構系列》jQueryunderscorelodashvuexsentryaxiosreduxkoavue-devtoolsvuex4koa-composevue-next-releasevue-thiscreate-vue玩具vite等10余篇源碼文章。

本文倉庫 vue-analysis,求個star^_^[1]

最近組織了源碼共讀活動

之前寫了 Vue3 相關的兩篇文章。

  • 初學者也能看懂的 Vue3 源碼中那些實用的基礎工具函數

這篇寫了如何學習 JavaScript 基礎知識推薦了很多書籍和學習資料還有我的一些經驗分享

  • Vue 3.2 發布了,那尤雨溪是怎么發布 Vue.js 的?

參加源碼共讀的讀者反饋,TA 其實還是用著 Vue2。能不能寫篇 Vue2 基礎工具函數。作為一名知識博主卑微號主,本著學我所學,為我所用,幫助他人的宗旨,于是寫上了這篇文章。算是 Vue3 工具函數的姐妹篇,本文和這篇文章會有類似的地方。

閱讀本文,你將學到:

1.?Vue2?源碼?shared?模塊中的幾十個實用工具函數
2.?如何學習源碼中優秀代碼和思想,投入到自己的項目中
3.?如何學習?JavaScript?基礎知識,會推薦很多學習資料
4.?我的一些經驗分享
5.?等等

2. 環境準備

2.1 讀開源項目 貢獻指南

打開 vue 倉庫[2], 開源項目一般都能在 README.md 或者 .github/contributing.md[3] 找到貢獻指南。

而貢獻指南寫了很多關于參與項目開發的信息。比如怎么跑起來,項目目錄結構是怎樣的。怎么投入開發,需要哪些知識儲備等。

我們可以在 項目目錄結構[4] 描述中,找到shared模塊。

shared: contains utilities shared across the entire codebase.

README.mdcontributing.md 一般都是英文的。可能會難倒一部分人。其實看不懂,完全可以可以借助劃詞翻譯,整頁翻譯和谷歌翻譯等翻譯工具。再把英文加入后續學習計劃。

本文就是講 shared 模塊,對應的文件路徑是:`vue/vue/src/shared`[5]

也可以用github1s訪問,速度更快。github1s vue/vue/src/shared[6]

2.2 為了降低文章難度,直接學習打包后的源碼

源代碼的代碼`vue/vue/src/shared`[7],使用了Flow[8] 類型,可能不太好理解。

為了降低文章難度,我們直接學習源碼倉庫中的打包后的 dist/vue.js 14行到379行[9]

當然,前面可能比較啰嗦。我可以直接講 3. 工具函數。但通過我上文的介紹,即使是初學者,都能看懂一些開源項目源碼,也許就會有一定的成就感。另外,面試問到被類似的問題或者筆試題時,你說看Vue2源碼學到的,面試官絕對對你刮目相看。

3. 工具函數

打包后的 vue.js 14行到379行[10],接下來就是解釋其中的這些方法。

3.1 emptyObject

/*!*?Vue.js?v2.6.14*?(c)?2014-2021?Evan?You*?Released?under?the?MIT?License.*/
/*??*/
var?emptyObject?=?Object.freeze({});

凍結對象。第一層無法修改。對象中也有判斷是否凍結的方法。

Object.isFrozen(emptyObject);?//?true

關于對象 API 推薦看之前我的文章 JavaScript 對象所有API解析[11]

還可以看阮一峰老師的ES6 入門書籍 reflect[12]

3.2 isUndef 是否是未定義

//?These?helpers?produce?better?VM?code?in?JS?engines?due?to?their
//?explicitness?and?function?inlining.
function?isUndef?(v)?{return?v?===?undefined?||?v?===?null
}

3.3 isDef 是否是已經定義

JavaScript中假值有六個。

false
null
undefined
0
''?(空字符串)
NaN

為了判斷準確,Vue2 源碼中封裝了isDefisTrueisFalse函數來準確判斷。

見名知意。

function?isDef?(v)?{return?v?!==?undefined?&&?v?!==?null
}

3.4 isTrue 是否是 true

見名知意。

function?isTrue?(v)?{return?v?===?true
}

3.5 isFalse 是否是 false

見名知意。

function?isFalse?(v)?{return?v?===?false
}

3.6 isPrimitive 判斷值是否是原始值

判斷是否是字符串、或者數字、或者 symbol、或者布爾值。

/***?Check?if?value?is?primitive.*/
function?isPrimitive?(value)?{return?(typeof?value?===?'string'?||typeof?value?===?'number'?||//?$flow-disable-linetypeof?value?===?'symbol'?||typeof?value?===?'boolean')
}

3.7 isObject 判斷是對象

因為 typeof null 是 'object'。數組等用這個函數判斷也是 true

/***?Quick?object?check?-?this?is?primarily?used?to?tell*?Objects?from?primitive?values?when?we?know?the?value*?is?a?JSON-compliant?type.*/
function?isObject?(obj)?{return?obj?!==?null?&&?typeof?obj?===?'object'
}//?例子:
isObject([])?//?true
//?有時不需要嚴格區分數組和對象

3.8 toRawType 轉換成原始類型

Object.prototype.toString() 方法返回一個表示該對象的字符串。

mdn[13]

ecma 規范[14],說明了這些類型。

afa01777b523884ad7c20360d6cf02ad.png
ecma 規范

ECMAScript5.1 中文版[15]

/***?Get?the?raw?type?string?of?a?value,?e.g.,?[object?Object].*/
var?_toString?=?Object.prototype.toString;function?toRawType?(value)?{return?_toString.call(value).slice(8,?-1)
}//?例子:
toRawType('')?//?'String'
toRawType()?//?'Undefined'

3.9 isPlainObject 是否是純對象

/***?Strict?object?type?check.?Only?returns?true*?for?plain?JavaScript?objects.*/
function?isPlainObject?(obj)?{return?_toString.call(obj)?===?'[object?Object]'
}//?上文?isObject([])?也是?true
//?這個就是判斷對象是純對象的方法。
//?例子:
isPlainObject([])?//?false
isPlainObject({})?//?true

3.10 isRegExp 是否是正則表達式

function?isRegExp?(v)?{return?_toString.call(v)?===?'[object?RegExp]'
}//?例子:
//?判斷是不是正則表達式
isRegExp(/ruochuan/)?//?true

3.11 isValidArrayIndex 是否是可用的數組索引值

數組可用的索引值是 0 ('0')、1 ('1') 、2 ('2') ...

/***?Check?if?val?is?a?valid?array?index.*/
function?isValidArrayIndex?(val)?{var?n?=?parseFloat(String(val));return?n?>=?0?&&?Math.floor(n)?===?n?&&?isFinite(val)
}

該全局 isFinite() 函數用來判斷被傳入的參數值是否為一個有限數值(finite number)。在必要情況下,參數會首先轉為一個數值。

isFinite mdn[16]

isFinite(Infinity);??//?false
isFinite(NaN);???????//?false
isFinite(-Infinity);?//?falseisFinite(0);?????????//?true
isFinite(2e64);??????//?true,?在更強壯的Number.isFinite(null)中將會得到falseisFinite('0');???????//?true,?在更強壯的Number.isFinite('0')中將會得到false

3.12 isPromise 判斷是否是 promise

function?isPromise?(val)?{return?(isDef(val)?&&typeof?val.then?===?'function'?&&typeof?val.catch?===?'function')
}//?例子:
isPromise(new?Promise())?//?true

這里用 isDef 判斷其實相對 isObject 來判斷 來說有點不嚴謹。但是夠用。

3.13 toString 轉字符串

轉換成字符串。是數組或者對象并且對象的 toString 方法是 Object.prototype.toString,用 JSON.stringify 轉換。

/***?Convert?a?value?to?a?string?that?is?actually?rendered.*/
function?toString?(val)?{return?val?==?null??'':?Array.isArray(val)?||?(isPlainObject(val)?&&?val.toString?===?_toString)??JSON.stringify(val,?null,?2):?String(val)
}

3.14 toNumber 轉數字

轉換成數字。如果轉換失敗依舊返回原始字符串。

/***?Convert?an?input?value?to?a?number?for?persistence.*?If?the?conversion?fails,?return?original?string.*/
function?toNumber?(val)?{var?n?=?parseFloat(val);return?isNaN(n)???val?:?n
}toNumber('a')?//?'a'
toNumber('1')?//?1
toNumber('1a')?//?1
toNumber('a1')?//?'a1'

3.15 makeMap 生成一個 map (對象)

傳入一個以逗號分隔的字符串,生成一個 map(鍵值對),并且返回一個函數檢測 key 值在不在這個 map 中。第二個參數是小寫選項。

/***?Make?a?map?and?return?a?function?for?checking?if?a?key*?is?in?that?map.*/
function?makeMap?(str,expectsLowerCase
)?{var?map?=?Object.create(null);var?list?=?str.split(',');for?(var?i?=?0;?i?<?list.length;?i++)?{map[list[i]]?=?true;}return?expectsLowerCase??function?(val)?{?return?map[val.toLowerCase()];?}:?function?(val)?{?return?map[val];?}
}//?Object.create(null)?沒有原型鏈的空對象

3.16 isBuiltInTag 是否是內置的 tag

/***?Check?if?a?tag?is?a?built-in?tag.*/
var?isBuiltInTag?=?makeMap('slot,component',?true);//?返回的函數,第二個參數不區分大小寫
isBuiltInTag('slot')?//?true
isBuiltInTag('component')?//?true
isBuiltInTag('Slot')?//?true
isBuiltInTag('Component')?//?true

3.17 isReservedAttribute 是否是保留的屬性

/***?Check?if?an?attribute?is?a?reserved?attribute.*/
var?isReservedAttribute?=?makeMap('key,ref,slot,slot-scope,is');isReservedAttribute('key')?//?true
isReservedAttribute('ref')?//?true
isReservedAttribute('slot')?//?true
isReservedAttribute('slot-scope')?//?true
isReservedAttribute('is')?//?true
isReservedAttribute('IS')?//?undefined

3.18 remove 移除數組中的中一項

/***?Remove?an?item?from?an?array.*/
function?remove?(arr,?item)?{if?(arr.length)?{var?index?=?arr.indexOf(item);if?(index?>?-1)?{return?arr.splice(index,?1)}}
}

splice 其實是一個很耗性能的方法。刪除數組中的一項,其他元素都要移動位置。

引申:`axios InterceptorManager` 攔截器源碼[17] 中,攔截器用數組存儲的。但實際移除攔截器時,只是把攔截器置為 null 。而不是用splice移除。最后執行時為 null 的不執行,同樣效果。axios 攔截器這個場景下,不得不說為性能做到了很好的考慮。因為攔截器是用戶自定義的,理論上可以有無數個,所以做性能考慮是必要的

看如下 axios 攔截器代碼示例:

//?代碼有刪減
//?聲明
this.handlers?=?[];//?移除
if?(this.handlers[id])?{this.handlers[id]?=?null;
}//?執行
if?(h?!==?null)?{fn(h);
}

3.19 hasOwn 檢測是否是自己的屬性

/***?Check?whether?an?object?has?the?property.*/
var?hasOwnProperty?=?Object.prototype.hasOwnProperty;
function?hasOwn?(obj,?key)?{return?hasOwnProperty.call(obj,?key)
}//?例子://?特別提醒:__proto__?是瀏覽器實現的原型寫法,后面還會用到
//?現在已經有提供好幾個原型相關的API
//?Object.getPrototypeOf
//?Object.setPrototypeOf
//?Object.isPrototypeOf// .call 則是函數里 this 顯示指定以為第一個參數,并執行函數。hasOwn({__proto__:?{?a:?1?}},?'a')?//?false
hasOwn({?a:?undefined?},?'a')?//?true
hasOwn({},?'a')?//?false
hasOwn({},?'hasOwnProperty')?//?false
hasOwn({},?'toString')?//?false
//?是自己的本身擁有的屬性,不是通過原型鏈向上查找的。

3.20 cached 緩存

利用閉包特性,緩存數據

/***?Create?a?cached?version?of?a?pure?function.*/
function?cached?(fn)?{var?cache?=?Object.create(null);return?(function?cachedFn?(str)?{var?hit?=?cache[str];return?hit?||?(cache[str]?=?fn(str))})
}

系統學習正則推薦老姚:《JavaScript 正則表達式迷你書》問世了![18],看過的都說好。所以本文不會很詳細的描述正則相關知識點。

3.21 camelize 連字符轉小駝峰

連字符 - 轉駝峰 ?on-click => onClick

/***?Camelize?a?hyphen-delimited?string.*/
var?camelizeRE?=?/-(\w)/g;
var?camelize?=?cached(function?(str)?{return?str.replace(camelizeRE,?function?(_,?c)?{?return?c???c.toUpperCase()?:?'';?})
});

3.22 capitalize 首字母轉大寫

首字母轉大寫

/***?Capitalize?a?string.*/
var?capitalize?=?cached(function?(str)?{return?str.charAt(0).toUpperCase()?+?str.slice(1)
});

3.23 hyphenate 小駝峰轉連字符

onClick => on-click

/***?Hyphenate?a?camelCase?string.*/
var?hyphenateRE?=?/\B([A-Z])/g;
var?hyphenate?=?cached(function?(str)?{return?str.replace(hyphenateRE,?'-$1').toLowerCase()
});

3.24 polyfillBind bind 的墊片

/***?Simple?bind?polyfill?for?environments?that?do?not?support?it,*?e.g.,?PhantomJS?1.x.?Technically,?we?don't?need?this?anymore*?since?native?bind?is?now?performant?enough?in?most?browsers.*?But?removing?it?would?mean?breaking?code?that?was?able?to?run?in*?PhantomJS?1.x,?so?this?must?be?kept?for?backward?compatibility.*//*?istanbul?ignore?next?*/
function?polyfillBind?(fn,?ctx)?{function?boundFn?(a)?{var?l?=?arguments.length;return?l??l?>?1??fn.apply(ctx,?arguments):?fn.call(ctx,?a):?fn.call(ctx)}boundFn._length?=?fn.length;return?boundFn
}function?nativeBind?(fn,?ctx)?{return?fn.bind(ctx)
}var?bind?=?Function.prototype.bind??nativeBind:?polyfillBind;

簡單來說就是兼容了老版本瀏覽器不支持原生的 bind 函數。同時兼容寫法,對參數的多少做出了判斷,使用callapply實現,據說參數多適合用 apply,少用 call 性能更好。

如果對于call、apply、bind的用法和實現不熟悉,可以查看我在面試官問系列面試官問:能否模擬實現JS的call和apply方法面試官問:能否模擬實現JS的bind方法

3.25 toArray 把類數組轉成真正的數組

把類數組轉換成數組,支持從哪個位置開始,默認從 0 開始。

/***?Convert?an?Array-like?object?to?a?real?Array.*/
function?toArray?(list,?start)?{start?=?start?||?0;var?i?=?list.length?-?start;var?ret?=?new?Array(i);while?(i--)?{ret[i]?=?list[i?+?start];}return?ret
}//?例子:
function?fn(){var?arr1?=?toArray(arguments);console.log(arr1);?//?[1,?2,?3,?4,?5]var?arr2?=?toArray(arguments,?2);console.log(arr2);?//?[3,?4,?5]
}
fn(1,2,3,4,5);

3.26 extend 合并

/***?Mix?properties?into?target?object.*/
function?extend?(to,?_from)?{for?(var?key?in?_from)?{to[key]?=?_from[key];}return?to
}//?例子:
const?data?=?{?name:?'若川'?};
const?data2?=?extend(data,?{?mp:?'若川視野',?name:?'是若川啊'?});
console.log(data);?//?{?name:?"是若川啊",?mp:?"若川視野"?}
console.log(data2);?//?{?name:?"是若川啊",?mp:?"若川視野"?}
console.log(data?===?data2);?//?true

3.27 toObject 轉對象

/***?Merge?an?Array?of?Objects?into?a?single?Object.*/
function?toObject?(arr)?{var?res?=?{};for?(var?i?=?0;?i?<?arr.length;?i++)?{if?(arr[i])?{extend(res,?arr[i]);}}return?res
}//?數組轉對象
toObject(['若川',?'若川視野'])
//?{0:?'若',?1:?'川',?2:?'視',?3:?'野'}

3.28 noop 空函數

/*?eslint-disable?no-unused-vars?*/
/***?Perform?no?operation.*?Stubbing?args?to?make?Flow?happy?without?leaving?useless?transpiled?code*?with?...rest?(https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/).*/
function?noop?(a,?b,?c)?{}//?初始化賦值

3.29 no 一直返回 false

/***?Always?return?false.*/
var?no?=?function?(a,?b,?c)?{?return?false;?};
/*?eslint-enable?no-unused-vars?*/

3.30 identity 返回參數本身

/***?Return?the?same?value.*/
var?identity?=?function?(_)?{?return?_;?};

3.31 genStaticKeys 生成靜態屬性

/***?Generate?a?string?containing?static?keys?from?compiler?modules.*/
function?genStaticKeys?(modules)?{return?modules.reduce(function?(keys,?m)?{return?keys.concat(m.staticKeys?||?[])},?[]).join(',')
}

3.32 looseEqual 寬松相等

由于數組、對象等是引用類型,所以兩個內容看起來相等,嚴格相等都是不相等。

var?a?=?{};
var?b?=?{};
a?===?b;?//?false
a?==?b;?//?false

所以該函數是對數組、日期、對象進行遞歸比對。如果內容完全相等則寬松相等。

/***?Check?if?two?values?are?loosely?equal?-?that?is,*?if?they?are?plain?objects,?do?they?have?the?same?shape?*/
function?looseEqual?(a,?b)?{if?(a?===?b)?{?return?true?}var?isObjectA?=?isObject(a);var?isObjectB?=?isObject(b);if?(isObjectA?&&?isObjectB)?{try?{var?isArrayA?=?Array.isArray(a);var?isArrayB?=?Array.isArray(b);if?(isArrayA?&&?isArrayB)?{return?a.length?===?b.length?&&?a.every(function?(e,?i)?{return?looseEqual(e,?b[i])})}?else?if?(a?instanceof?Date?&&?b?instanceof?Date)?{return?a.getTime()?===?b.getTime()}?else?if?(!isArrayA?&&?!isArrayB)?{var?keysA?=?Object.keys(a);var?keysB?=?Object.keys(b);return?keysA.length?===?keysB.length?&&?keysA.every(function?(key)?{return?looseEqual(a[key],?b[key])})}?else?{/*?istanbul?ignore?next?*/return?false}}?catch?(e)?{/*?istanbul?ignore?next?*/return?false}}?else?if?(!isObjectA?&&?!isObjectB)?{return?String(a)?===?String(b)}?else?{return?false}
}

3.33 looseIndexOf 寬松的 indexOf

該函數實現的是寬松相等。原生的 indexOf 是嚴格相等。

/***?Return?the?first?index?at?which?a?loosely?equal?value?can?be*?found?in?the?array?(if?value?is?a?plain?object,?the?array?must*?contain?an?object?of?the?same?shape),?or?-1?if?it?is?not?present.*/
function?looseIndexOf?(arr,?val)?{for?(var?i?=?0;?i?<?arr.length;?i++)?{if?(looseEqual(arr[i],?val))?{?return?i?}}return?-1
}

3.34 once 確保函數只執行一次

利用閉包特性,存儲狀態

/***?Ensure?a?function?is?called?only?once.*/
function?once?(fn)?{var?called?=?false;return?function?()?{if?(!called)?{called?=?true;fn.apply(this,?arguments);}}
}const?fn1?=?once(function(){console.log('哎嘿,無論你怎么調用,我只執行一次');
});fn1();?//?'哎嘿,無論你怎么調用,我只執行一次'
fn1();?//?不輸出
fn1();?//?不輸出
fn1();?//?不輸出

3.35 生命周期等

var?SSR_ATTR?=?'data-server-rendered';var?ASSET_TYPES?=?['component','directive','filter'
];[Vue?生命周期](https://cn.vuejs.org/v2/api/#%E9%80%89%E9%A1%B9-%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F%E9%92%A9%E5%AD%90?"Vue?生命周期")var?LIFECYCLE_HOOKS?=?['beforeCreate','created','beforeMount','mounted','beforeUpdate','updated','beforeDestroy','destroyed','activated','deactivated','errorCaptured','serverPrefetch'
];

4. 最后推薦一些文章和書籍

這部分和Vue3工具函數文章一樣,值得推薦,所以復制到這里。

先推薦我認為不錯的JavaScript API的幾篇文章和幾本值得讀的書。

JavaScript字符串所有API全解密[19]

【深度長文】JavaScript數組所有API全解密[20]

正則表達式前端使用手冊[21]

老姚:《JavaScript 正則表達式迷你書》問世了![22]

老姚淺談:怎么學JavaScript?

JavaScript 對象所有API解析

MDN JavaScript[23]

《JavaScript高級程序設計》第4版[24]

《JavaScript 權威指南》第7版[25]

《JavaScript面向對象編程2》[26] 面向對象講的很詳細。

阮一峰老師:《ES6 入門教程》[27]

《現代 JavaScript 教程》[28]

《你不知道的JavaScript》上中卷[29]

《JavaScript 設計模式與開發實踐》[30]

我也是從小白看不懂書經歷過來的。到現在寫文章分享。

我看書的方法:多本書同時看,看相同類似的章節,比如函數。看完這本可能沒懂,看下一本,幾本書看下來基本就懂了,一遍沒看懂,再看幾遍,可以避免遺忘,鞏固相關章節。當然,剛開始看書很難受,看不進。這些書大部分在微信讀書都有,如果習慣看紙質書,那可以買來看。

這時可以看些視頻和動手練習一些簡單的項目。

比如:可以自己注冊一個github賬號,分章節小節,抄寫書中的代碼,提交到github,練習了才會更有感覺。

再比如 freeCodeCamp 中文在線學習網站[31] 網站。看書是系統學習非常好的方法。后來我就是看源碼較多,寫文章分享出來給大家。

5. 總結

本文通過查看 Vue2 源碼中 shared 模塊打包后的 dist/vue.js 14行到379行[32]源碼也不是那么難,至少很多能看懂,比如工具函數。難可能是難在:不知道應用場景。

Vue2 工具函數命名很規范,比如:is 判斷,to 轉換,has 是否有,讓開發者一眼就能看出函數語意。

這些函數也非常單一,基本一個函數只做一件事。

建議讀者朋友把不熟悉的函數,動手寫寫,有助于鞏固基礎知識,查漏補缺。

最后歡迎加我微信 ruochuan12源碼共讀 活動,大家一起學習源碼,共同進步。

參考資料

[1]

本文倉庫 vue-analysis,求個star^_^: https://github.com/lxchuan12/vue-analysis.git

[2]

vue 倉庫: https://github.com/vuejs/vue

[3]

更多參考資料可以點擊閱讀原文查看


最近組建了一個江西人的前端交流群,如果你是江西人可以加我微信?ruochuan12?私信 江西?拉你進群。

推薦閱讀

1個月,200+人,一起讀了4周源碼
我歷時3年才寫了10余篇源碼文章,但收獲了100w+閱讀

老姚淺談:怎么學JavaScript?

我在阿里招前端,該怎么幫你(可進面試群)

d8d8df012255114a94e0a2358cd5d0da.gif

·················?若川簡介?·················

你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列
從2014年起,每年都會寫一篇年度總結,已經寫了7篇,點擊查看年度總結。
同時,最近組織了源碼共讀活動

66fa136c1768d7f18cba9e06faa71762.png

識別方二維碼加我微信、拉你進源碼共讀

今日話題

略。歡迎分享、收藏、點贊、在看我的公眾號文章~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/275267.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/275267.shtml
英文地址,請注明出處:http://en.pswp.cn/news/275267.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

清除浮動mini版

1&#xff09; 清除浮動mini版(簡約而不簡單).clr:after { content:"";display:table;clear:both;}.clr{zoom:1;} 轉載于:https://www.cnblogs.com/jinbiao/archive/2011/09/26/2191170.html

Fiddler 十分鐘最全使用介紹

Wireshark 、HTTPWatch、Fiddler的介紹 Firebug雖然可以抓包&#xff0c;但是對于分析http請求的詳細信息&#xff0c;不夠強大。模擬http請求的功能也不夠&#xff0c;且firebug常常是需要“無刷新修改”&#xff0c;如果刷新了頁面&#xff0c;所有的修改都不會保存。Wiresha…

視覺測試_視覺設計流行測驗

視覺測試重點 (Top highlight)I often discuss the topic of improving visual design skills with junior and mid-level designers. While there are a number of design principles the designers should learn and practice, one important skill that is not often consid…

如何給開源項目提過 PR 呢?其實很簡單

大家好&#xff0c;我是若川。最近組織了源碼共讀活動&#xff0c;感興趣的可以加我微信 ruochuan12源碼共讀群里有小伙伴聊到如何給開源項目提PR&#xff0c;所以今天分享這篇文章。你有給開源的庫或者框架提過 PR 嗎&#xff1f;如果沒有&#xff0c;那么今天的文章會教你怎么…

一次回母校教前端的經歷

大家好&#xff0c;我是若川。最近組織了源碼共讀活動&#xff0c;感興趣的可以加我微信 ruochuan12已進行了三個月&#xff0c;很多小伙伴都表示收獲頗豐。分享一篇武大畢業的耀耀大佬的文章。有些時候會受限于環境影響&#xff0c;特別是在校大學生。所以要融入到積極上進的環…

設計插畫工具_5個強大的設計師插畫工具

設計插畫工具As Product Designers, most likely, we have come across illustrative work. Visual design is one important element in enhancing the user experience. As many gravitate toward attractive looking products, designers are also adapting to the changing…

如何才能更合理地分配項目獎金?

項目獎金通常情況下都是屬于基本工資之外的一種績效獎勵&#xff0c;也就是說&#xff0c;它在員工的薪酬中&#xff0c;是屬于浮動的那一部分收入&#xff0c;而不是一種固定收入。基于這樣一種認知&#xff0c;跟大家討論下如何才能更合理地進行項目獎金的分配&#xff1f; 首…

Codeforces 741 D - Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

D - Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths 思路&#xff1a; 樹上啟發式合并 從根節點出發到每個位置的每個字符的奇偶性記為每個位置的狀態&#xff0c;每次統計一下每個狀態的最大深度 為了保證鏈經過當前節點u&#xff0c;我們先計算每個子樹的答案…

figma下載_切換到Figma并在其中工作不必是火箭科學,這就是為什么

figma下載We have seen Elon Musk and SpaceX making Rocket Science look like a child’s play. In the same spirit, should design tools be rocket science that is too hard to master? Not at all.我們已經看到埃隆馬斯克(Elon Musk)和SpaceX使Rocket Science看起來像是…

npm、yarn、cnpm、pnpm 使用操作都在這了

大家好&#xff0c;我是若川。最近組織了源碼共讀活動&#xff0c;感興趣的可以加我微信 ruochuan12有時候想查個命令&#xff0c;或者換個鏡像找了幾篇文章才找到&#xff0c;最近閑著沒事干&#xff0c;干脆整理一篇文檔&#xff0c;以后就不用在網上瞎搜有的還寫不全。Usage…

CAN控制器的選擇

在進行CAN總線開發前&#xff0c;首先要選擇好CAN總線控制器。下面就比較一些控制器的特點。 一些主要的CAN總線器件產品 制造商 產品型號 器件功能及特點 Intel 82526 82527 8XC196CA/CB CAN通信控制器&#xff0c;符合CAN2.0A CAN通信控制器&#xff0c;符合CAN2.0B 擴展…

洛谷 4115 Qtree4——鏈分治

題目&#xff1a;https://www.luogu.org/problemnew/show/P4115 論文&#xff1a;https://wenku.baidu.com/view/1bc2e4ea172ded630b1cb602.html 重鏈剖分&#xff0c;分別用線段樹維護每條重鏈。線段樹葉子的信息是該點輕孩子的信息&#xff1b;線段樹區間的信息是考慮重鏈的一…

每次啟動項目的服務,電腦竟然乖乖的幫我打開了瀏覽器,100行源碼揭秘!

1. 前言大家好&#xff0c;我是若川。最近組織了源碼共讀活動&#xff0c;感興趣的可以加我微信 ruochuan12 參與&#xff0c;已進行三個月了&#xff0c;大家一起交流學習&#xff0c;共同進步。想學源碼&#xff0c;極力推薦之前我寫的《學習源碼整體架構系列》 包含jQuery、…

初級爬蟲師_初級設計師的4條視覺原則

初級爬蟲師重點 (Top highlight)Like many UXers, I got into the industry from a non-visual background (in my case it was Business and later on Human Cognition). Even though I found great benefits coming from those backgrounds, it also meant I had no UI/Visua…

String類中IndexOf與SubString

IndexOfpublic: int IndexOf( String^ value, int startIndex, int count ) 說明&#xff1a; value類型&#xff1a;System..::.String要查找的 String。 startIndex類型&#xff1a;System..::.Int32搜索起始位置。 count類型&#xff1a;System..::.Int32要檢查的字符位置…

開源監控解決方案OpenFalcon系列(一)

OpenFalcon是由小米的運維團隊開源的一款企業級、高可用、可擴展的開源監控解決方案&#xff0c;&#xff0c;在眾多開源愛好者的支持下&#xff0c;功能越來越豐富&#xff0c;文檔更加的完善&#xff0c;OpenFalcon 已經成為國內最流行的監控系統之一。小米、美團、金山云、快…

如何利用 webpack 在項目中做出亮點

大家好&#xff0c;我是若川。最近這幾年&#xff0c;在前端代碼打包器領域內&#xff0c;webpack 算得上是時下最流行的前端打包工具。它可以分析各個模塊的依賴關系&#xff0c;最終打包成我們常見的靜態文件&#xff1a;.js 、 .css 、 .jpg 、.png&#xff0c;極大地提升了…

[轉]上下拉電阻

上下拉電阻有什么用&#xff1f; 對這個問題&#xff0c;平時沒有留意過&#xff0c;搞設計的時候都是照本宣科&#xff0c;沒有真正弄懂意思&#xff0e; 很多單片機開發的入門者&#xff0c;以及一些從事軟件開發的人&#xff0c;往往在開發單片機的時候遇到上拉電阻、下拉…

yum安裝Mariadb,二進制安裝Mariadb

yum安裝Mariadb 設置Mariadb的yum源 vim /etc/yum.repos.d/mariadb.repo [mariadb] namemariadb baseurlhttps://mirrors.tuna.tsinghua.edu.cn/mariadb/yum/10.2/centos7-amd64/ gpgcheck0 使用清華yum源安裝Mariadb,可以選擇不同的版本&#xff0c;此處安裝10.2.23 yum in…

Oracle中的wmsys.wm_concat

Oracle中的wmsys.wm_concat主要實現行轉列功能(說白了就是將查詢的某一列值使用逗號進行隔開拼接&#xff0c;成為一條數據)。 wmsys.wm_concat除了單獨使用外還可以和over函數結合使用。 開始看看具體使用方法&#xff1a; select t.rank, t.Name from t_menu_item t; rank…