防衝突
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 = _.identity
return 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,對作者也是一種鼓勵。