underscore 系列之防冲突与 Utility Functions
防沖突
underscore 使用 _ 作為函數(shù)的掛載對象,如果頁面中已經(jīng)存在了 _ 對象,underscore 就會覆蓋該對象,舉個(gè)例子:
var _ = {value: 1 }// 引入 underscore 后 console.log(_.value); // undefined 復(fù)制代碼所以 underscore 提供了 noConflict 功能,可以放棄 underscore 的控制變量 _,返回 underscore 對象的引用。
var _ = {value: 1 }// 引入 underscore 后// 放棄 "_",使用 "$" var $ = _.noConflict();console.log(_.value); // 1// 使用 underscore 的方法 $.each([1, 2, 3], alert); 復(fù)制代碼那么 noConflict 函數(shù)是如何實(shí)現(xiàn)的呢?
首先,在 underscore 執(zhí)行的時(shí)候,會儲存之前的 _ 對象,然后當(dāng)執(zhí)行 noConflict 函數(shù)的時(shí)候,再將之前儲存的 _ 對象賦給全局對象,最后返回 underscore 對象。這樣,我們就可以利用返回的 underscore 對象使用 underscore 提供的各種方法。
// 源碼一開始的時(shí)候便儲存之前的 _ 對象 var previousUnderscore = root._;_.noConflict = function() {root._ = previousUnderscore;return this; }; 復(fù)制代碼是的,就是這么簡單。你可以輕松為你的函數(shù)庫添加防沖突功能。
接下來我們看 underscore 中的一些功能函數(shù)。
_.identity
_.identity = function(value) {return value; }; 復(fù)制代碼看起來匪夷所思的一個(gè)函數(shù),傳入一個(gè)值,然后返回該值,為什么不直接使用該值呢?
還記得我們在《underscore 系列之內(nèi)部函數(shù) cb 和 optimizeCb》中接觸過這個(gè)函數(shù)嗎?
如果我們自己編寫了一個(gè) _.map 函數(shù):
_.map = function(arr, iteratee){return arr.map(iteratee) } 復(fù)制代碼然而當(dāng)我們這樣使用 _.map([1, 2, 3]) 時(shí)便會報(bào)錯(cuò),因?yàn)槲覀儧]有傳入 iteratee 函數(shù),然而使用 underscore 卻沒有問題,結(jié)果是返回一個(gè)相同的新數(shù)組,原因就在于當(dāng) iteratee 為 undefined 的時(shí)候,underscore 視為傳入了 _.identity 函數(shù)。就相當(dāng)于:
_.map = function(arr, iteratee){if (!iteratee) iteratee = _.identityreturn arr.map(iteratee) } 復(fù)制代碼簡而言之,如果我們想要復(fù)制一個(gè)數(shù)組:
var clonedArr = [1, 2, 3].map(_.identity) // [1, 2, 3] 復(fù)制代碼_.constant
_.constant = function(value) {return function() {return value;}; }; 復(fù)制代碼該函數(shù)傳入一個(gè) value,然后返回一個(gè)返回該 value 的函數(shù),這又有什么用呢?我們來看個(gè) demo:
var value = 1; var getValue = _.constant(value);value = 2;getValue(); // 1 getValue(); // 1 復(fù)制代碼這很容易讓人想到 ES6 的 const,我一開始以為就是用來表示 ES6 的 const ,后來看了這個(gè)函數(shù)起源的 issue,才發(fā)現(xiàn)并非如此,它其實(shí)像下面的 _.noop 函數(shù)一樣可以作為默認(rèn)函數(shù)使用。
舉個(gè)例子:
_.select(collection, filterFunction || function() { return true; }) 復(fù)制代碼我們根據(jù) filterFunction 篩選 collection 中符合條件的元素,如果沒有傳 filterFunction,我們就返回所有的元素,如果有 _.constant 函數(shù),我們可以將其簡化為:
_.select(collection, filterFunction || _.constant(true)) 復(fù)制代碼盡管沒有什么大的改變,但是語義更加明確。
_.noop
_.noop = function(){}; 復(fù)制代碼一個(gè)空函數(shù),看起來依舊沒什么用……
noop 函數(shù)可以用于作為默認(rèn)值,這樣就可以省去是否存在的判斷,舉個(gè)例子:
// 不使用 noop function a(value, callback){// 每次使用 callback 都要判斷一次_.isFunction(callback) && callback() }// 使用 noop function a(value, callback) {// 判斷一次if(!_.isFunction(callback)) callback = _.noop;// 以后都可以直接使用callback() } 復(fù)制代碼deepGet
var deepGet = function(obj, path) {var length = path.length;for (var i = 0; i < length; i++) {if (obj == null) return void 0;obj = obj[path[i]];}return length ? obj : void 0; }; 復(fù)制代碼deepGet 用于獲得對象深層次的值。舉個(gè)例子:
var obj = { value: { deepValue: 2} }console.log(deepGet(obj, ['value', 'deepValue'])) 復(fù)制代碼使用這個(gè)函數(shù),可以避免深層次取值時(shí),因?yàn)闆]有其中的一個(gè)屬性,導(dǎo)致的報(bào)錯(cuò)。
shallowProperty
var shallowProperty = function(key) {return function(obj) {return obj == null ? void 0 : obj[key];}; }; 復(fù)制代碼shallowProperty 也是用于獲取對象的屬性,也許你會好奇在開發(fā)中,直接使用. 不就可以獲取對象的屬性了,為什么還要寫成這樣呢?我們來舉個(gè)例子:
// 獲取 arr 所有元素的 name 屬性 var arr = [{value: 1,name: 'Kevin'},{value: 2,name: 'Daisy'} ]// 普通方式 var names = arr.map(function(item){return item.name; })// 使用 shallowProperty var names = arr.map(shallowProperty('name')) 復(fù)制代碼_.property
_.property = function(path) {if (!_.isArray(path)) {return shallowProperty(path);}return function(obj) {return deepGet(obj, path);}; }; 復(fù)制代碼_.property 結(jié)合了 deepGet 和 shallowProperty,可以獲取元素深層次的值。上面一個(gè)例子也可以寫成:
var names = arr.map(_.property('name')) 復(fù)制代碼_.propertyOf
_.propertyOf = function(obj) {if (obj == null) {return function(){};}return function(path) {return !Array.isArray(path) ? obj[path] : deepGet(obj, path);}; }; 復(fù)制代碼_.property 返回一個(gè)函數(shù),這個(gè)函數(shù)返回任何傳入的對象的指定屬性。
_.propertyOf 與 _.property 相反。需要一個(gè)對象,并返回一個(gè)函數(shù),這個(gè)函數(shù)將返回一個(gè)提供的屬性的值。
我們寫個(gè)例子:
// 獲取 person 對象的所有屬性值 var person = {name: 'Kevin',age: '18' };// 普通方式 var values = Object.keys(person).map((key) => person[key]); // ["Kevin", "18"]// 使用 _.propertyOf var values = Object.keys(person).map(_.propertyOf(person)); // ["Kevin", "18" 復(fù)制代碼_.random
返回一個(gè) min 和 max 之間的隨機(jī)整數(shù)。如果你只傳遞一個(gè)參數(shù),那么將返回 0 和這個(gè)參數(shù)之間的整數(shù)。
_.random = function(min, max) {if (max == null) {max = min;min = 0;}return min + Math.floor(Math.random() * (max - min + 1));}; 復(fù)制代碼注意:該隨機(jī)值有可能是 min 或 max。
underscore 系列
underscore 系列目錄地址:github.com/mqyqingfeng…。
underscore 系列預(yù)計(jì)寫八篇左右,重點(diǎn)介紹 underscore 中的代碼架構(gòu)、鏈?zhǔn)秸{(diào)用、內(nèi)部函數(shù)、模板引擎等內(nèi)容,旨在幫助大家閱讀源碼,以及寫出自己的 undercore。
如果有錯(cuò)誤或者不嚴(yán)謹(jǐn)?shù)牡胤?#xff0c;請務(wù)必給予指正,十分感謝。如果喜歡或者有所啟發(fā),歡迎 star,對作者也是一種鼓勵(lì)。
與50位技術(shù)專家面對面20年技術(shù)見證,附贈技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的underscore 系列之防冲突与 Utility Functions的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 脑科学助力人工智能,离不开大数据
- 下一篇: Day5 类和对象