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