摘要:用來(lái)構(gòu)成和兩個(gè)函數(shù),主要針對(duì)的是為了將函數(shù)調(diào)用模式更改為構(gòu)造器調(diào)用和方法調(diào)用。通過(guò)函數(shù)設(shè)定時(shí)間為毫秒后執(zhí)行函數(shù)的回調(diào)函數(shù),用以達(dá)到在規(guī)定時(shí)間毫秒時(shí)執(zhí)行函數(shù)的目的,并且規(guī)定時(shí)間內(nèi)只執(zhí)行一次函數(shù)。
北京的雨已經(jīng)斷斷續(xù)續(xù)下了好久,昏昏欲睡的躲在家里不愿意出門(mén),火影忍者快要結(jié)束了,一拳超人第二季據(jù)說(shuō)還要等好多年,勇者大冒險(xiǎn)貌似斷更了,我又是在不喜歡海賊王的畫(huà)風(fēng),所以,我該看什么好呢。
var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) { if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); var self = baseCreate(sourceFunc.prototype); var result = sourceFunc.apply(self, args); if (_.isObject(result)) return result; return self; };
executeBound 用來(lái)構(gòu)成 _.bind 和 _.partial 兩個(gè)函數(shù),主要針對(duì)的是為了將函數(shù)調(diào)用模式更改為構(gòu)造器調(diào)用和方法調(diào)用。
_.bind = restArgs(function(func, context, args) { if (!_.isFunction(func)) throw new TypeError("Bind must be called on a function"); var bound = restArgs(function(callArgs) { return executeBound(func, bound, context, this, args.concat(callArgs)); }); return bound; });
也許我們可以參考下 Function.prototype.bind(),_.bind 函數(shù)這個(gè)需要仔細(xì)講一下了,先化簡(jiǎn):
_.bind = function(func, context, args) { var length = arguments.length - 2; args = Array(length); for (var index = 0; index < length; index++) { args[index] = arguments[index + startIndex]; } if (!_.isFunction(func)) throw new TypeError("Bind must be called on a function"); var bound = function(args_2){ args_2 = Array(arguments.length); for (var index = 0; index < arguments.length; index++) { args_2[index] = arguments[index]; } (function(sourceFunc, boundFunc, context, callingContext, args) { if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); var self = baseCreate(sourceFunc.prototype); var result = sourceFunc.apply(self, args); if (_.isObject(result)) return result; return self; })(func, bound, context, this, args.concat(args_2)); }; return bound; };
這樣看上去是不是直白很多,官網(wǎng)給它的定義是:綁定函數(shù) function 到對(duì)象 object 上, 也就是無(wú)論何時(shí)調(diào)用函數(shù), 函數(shù)里的 this 都指向這個(gè) object.任意可選參數(shù) arguments 可以傳遞給函數(shù) function , 可以填充函數(shù)所需要的參數(shù),這也被稱(chēng)為 partial application。對(duì)于沒(méi)有結(jié)合上下文的partial application綁定,請(qǐng)使用partial。,怎么聽(tīng)怎么別扭,我們可以這樣理解:_.bind 函數(shù)是為其傳參中的 function 的 this 上綁定相應(yīng)對(duì)象屬性,并且同時(shí)進(jìn)行 function 的參數(shù)傳入,而其中最關(guān)鍵的就是在執(zhí)行這一系列動(dòng)作的同時(shí)將傳入?yún)?shù) context 綁定到了指向它的 Function 對(duì)象本身的 this 身上(可參考函數(shù)調(diào)用模式與方法調(diào)用模式的區(qū)別)。官網(wǎng)有個(gè)栗子:
var func = function(greeting){ return greeting + ": " + this.name }; func = _.bind(func, {name: "moe"}, "hi"); func(); {"hi: moe"}
實(shí)際上呢它等同于:
var func = _.bind(function(greeting){ return greeting + ": " + this.name; }, {name: "moe"}, "hi" ); func(); {"hi: moe"}
結(jié)合前面簡(jiǎn)化的 _.bind 代碼示例可知這個(gè)函數(shù)的核心思想就是先通過(guò) _.bind 初始化的時(shí)候優(yōu)化第3+個(gè)參數(shù) args,為什么叫 3+ 呢,因?yàn)閺牡谌齻€(gè)參數(shù)開(kāi)始,可能是不限定的參數(shù)數(shù)量,所以從第三個(gè)開(kāi)始到最后一個(gè)參數(shù)同一處理為一個(gè)數(shù)組 args。
緊接著就是執(zhí)行剛才初始化過(guò)后的函數(shù)了,當(dāng) func(); 的時(shí)候也就是開(kāi)始執(zhí)行 _.bind 中的 bound 函數(shù)。bound 允許傳遞參數(shù)并且其參數(shù)會(huì)被 push 到 args 中,具體實(shí)現(xiàn)參看上面的簡(jiǎn)化代碼 args.concat(args_2)。這里我們有幾個(gè)需要注意的點(diǎn),其一是 callingContext instanceof boundFunc,之前我們講過(guò) instanceof 的神奇用法,在這里它用與判斷 bound 中的 this 的指向是否繼承于 bound。我們一定知道 this 指向的四個(gè)情況,如下:
var obj = {}; var func = function (){console.log(this);}; func(); new func(); obj.func = func; obj.func(); func.apply(["this is parameter"]); func.call(["this is parameter"]);
輸出結(jié)果為:
Window {external: Object, chrome: Object, document: document, alogObjectConfig: Object, alogObjectName: "alog"…} func {} Object {} ["this is parameter"] ["this is parameter"]
分別代表四種情況:
函數(shù)調(diào)用模式:指向 Global,瀏覽器客戶端即 window;
方法調(diào)用模式:指向?qū)ο蟊旧恚?/p>
構(gòu)造器調(diào)用模式:指向?yàn)樾聵?gòu)造的對(duì)象,繼承自原 Function 對(duì)象;
apply 或 call 調(diào)用模式:指向傳入的參數(shù)。
這里還有一些非常好的資料:this、Understanding JavaScript Function Invocation and "this",在這里我要說(shuō)一下我在推庫(kù)上看到一篇關(guān)于 this 的介紹文章說(shuō):“比較系統(tǒng)的分類(lèi)是《JavaScript語(yǔ)言精粹》中的,分為函數(shù)調(diào)用模式(this綁定全局對(duì)象window)和方法調(diào)用模式(this綁定調(diào)用方法的主體)”,我把《JavaScript語(yǔ)言精粹》這本書(shū)從頭到尾翻看了好幾遍,實(shí)際上它原文是這樣說(shuō)的:“在 JAVASCRIPT 中一共有4種調(diào)用模式:方法調(diào)用模式、函數(shù)調(diào)用模式、構(gòu)造器調(diào)用模式和 apply 調(diào)用模式。”,具體敘述在原書(shū)的P27~P30頁(yè),感興趣的朋友可以看下,在給大家看一個(gè)彩蛋,嚴(yán)格模式下的 this。緊接上文,當(dāng) bound 中的 this 的指向是否繼承于 bound 函數(shù)的時(shí)候說(shuō)明是使用了 new 關(guān)鍵字的構(gòu)造器調(diào)用模式調(diào)用了 _.bind 函數(shù),則繼續(xù)執(zhí)行 executeBound 函數(shù)中的 baseCreate 創(chuàng)建基本函數(shù)然后進(jìn)行一系列的操作,其實(shí)說(shuō)到底 baseCreate 的目的就是為了保證傳入?yún)?shù) Function 的 this 的干凈。
另外一個(gè)需要注意的地方是官網(wǎng)示例的暗示(特蛋疼的暗示),我擴(kuò)展了一下:
var func = function(){ return JSON.stringify(arguments) + ": " + this.name }; func = _.bind(func, {name: "moe"}, "hi"); func(); func = _.bind(func, {name: "moe2"}, "hi2"); func();
輸出結(jié)果:
"{"0":"hi"}: moe" "{"0":"hi","1":"hi2"}: moe"
可能有些不明就里的同學(xué)會(huì)問(wèn)這是為什么啊,怎么 this.name 的值沒(méi)有變化呢。實(shí)際上我們第一個(gè) _.bind 是正常的函數(shù)綁定,而第二個(gè) func = _.bind(func, {name: "moe2"}, "hi2"); 是將上一個(gè) _.bind 作為了 Function 參數(shù)傳入到了新的 _.bind 中,而本來(lái)的函數(shù) func 作為第一個(gè) _.bind 的 func 參數(shù)一直傳遞到第二個(gè) _.bind 中,但是中間的 this.name 卻被綁定到了第一個(gè) _.bind 上面而不是第一個(gè) _.bind 中的 func 上。有一點(diǎn)繞口。用個(gè)代碼介紹下,第二個(gè) _.bind 的情況是這樣子的:
func = _.bind(function( function(greeting){ return greeting + ": " + this.name; }, context, args ) { var length = arguments.length - 2; args = Array(length); for (var index = 0; index < length; index++) { args[index] = arguments[index + startIndex]; } if (!_.isFunction(func)) throw new TypeError("Bind must be called on a function"); var bound = function(args_2){ args_2 = Array(arguments.length); for (var index = 0; index < arguments.length; index++) { args_2[index] = arguments[index]; } (function(sourceFunc, boundFunc, context, callingContext, args) { if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args); var self = baseCreate(sourceFunc.prototype); var result = sourceFunc.apply(self, args); if (_.isObject(result)) return result; return self; })(func, bound, context, this, args.concat(args_2)); }; return bound; }, {name: "moe2"}, "hi2" );
所以 _.bind 一定要遵循正確的用法,不然真的出錯(cuò)了可能調(diào)試都不好發(fā)現(xiàn)問(wèn)題,多層回調(diào)嵌套的時(shí)候一層套一層,很麻煩。
_.partial = restArgs(function(func, boundArgs) { var placeholder = _.partial.placeholder; var bound = function() { var position = 0, length = boundArgs.length; var args = Array(length); for (var i = 0; i < length; i++) { args[i] = boundArgs[i] === placeholder ? arguments[position++] : boundArgs[i]; } while (position < arguments.length) args.push(arguments[position++]); return executeBound(func, bound, this, this, args); }; return bound; });
_.partial 函數(shù)的核心思想與 _.bind 相同,都是為了解決 this 指向的問(wèn)題,區(qū)別在于 _.partial 不需要對(duì) this 上的值做什么處理。用法上我覺(jué)得 _.partial 看上去更怪異一些,也許用來(lái)做一些特定的計(jì)算可能更合適些。
_.partial.placeholder = _;
設(shè)置 _.partial.placeholder 為 _。
_.bindAll = restArgs(function(obj, keys) { keys = flatten(keys, false, false); var index = keys.length; if (index < 1) throw new Error("bindAll must be passed function names"); while (index--) { var key = keys[index]; obj[key] = _.bind(obj[key], obj); } });
這里我們看到 _.bindAll 函數(shù)官網(wǎng)的示例就有點(diǎn)糊涂了:
var buttonView = { label : "underscore", onClick: function(){ console.log("clicked: " + this.label); }, onHover: function(){ console.log("hovering: " + this.label); } }; _.bindAll(buttonView, "onClick", "onHover"); buttonView.onClick(); clicked: underscore
我們當(dāng)然知道結(jié)果是 clicked: underscore,那么執(zhí)行 _.bindAll(buttonView, "onClick", "onHover"); 的意義在哪呢,所以說(shuō)這又是官網(wǎng)坑人的地方了,_.bindAll 的本意是將其傳入的第二個(gè)及以后的參數(shù)放到一個(gè)共同的上下文環(huán)境里面執(zhí)行,從而達(dá)到 this 指向其第一個(gè)參數(shù)的本身的目的,而官網(wǎng)的示例為方法調(diào)用模式,this 指向已經(jīng)是 Object 本身了所以看不到變化,但是我們?cè)跒g覽器控制臺(tái)查看的話應(yīng)該能知道 this 上多了 [[TargetFunction]]: function ()、[[BoundThis]]: Object、[[BoundArgs]]: Array[0] 三個(gè)參數(shù)并且 [[BoundThis]] 恰好是 Object。閑來(lái)無(wú)事這好看到有人也寫(xiě)了這個(gè)問(wèn)題并舉證了一個(gè)示例,詳見(jiàn) Understanding bind and bindAll in Backbone.js。我 cope 一下:
function Developer(skill) { this.skill = skill; this.says = function(){ console.log(this.skill + " rocks!"); } } var john = new Developer("Ruby"); _.bindAll(john, "says"); var func = john.says; func(); //Ruby rocks!
這個(gè)函數(shù)調(diào)用模式的示例正好答疑了 this 指向已經(jīng)被改變的這個(gè)問(wèn)題。
_.memoize = function(func, hasher) { var memoize = function(key) { var cache = memoize.cache; var address = "" + (hasher ? hasher.apply(this, arguments) : key); if (!_.has(cache, address)) cache[address] = func.apply(this, arguments); return cache[address]; }; memoize.cache = {}; return memoize; };
_.memoize 函數(shù)更像是一個(gè)可以緩存第一次執(zhí)行結(jié)果的遞歸函數(shù),我們從源碼中可以看到 memoize.cache = {}; 就是用來(lái)存儲(chǔ)計(jì)算結(jié)果的容器,這里面比較有意思的是 hasher 這個(gè)參數(shù),官網(wǎng)釋義: hashFunction,實(shí)際上就是通過(guò) hashFunction 對(duì)傳入的 key 值進(jìn)行處理然后放到 memoize.cache = {}; 中,至于怎么處理 hash 也好、md5 也好、或者什么其他的計(jì)算加密真值判斷增加對(duì)象等等都可以通過(guò) hasher 這個(gè)傳入的回調(diào)進(jìn)行擴(kuò)展。
————————— 疲憊的分割線 ———————————
這幾天北京總在下雨,身體特別的疲憊,狀態(tài)也不怎么好,所以今天才開(kāi)始繼續(xù)更新。
————————— END ———————————
_.delay = restArgs(function(func, wait, args) { return setTimeout(function() { return func.apply(null, args); }, wait); });
_.delay 函數(shù)用于處理定時(shí)器相關(guān)函數(shù),原理是通過(guò) setTimeout 進(jìn)行二次封裝,比較關(guān)鍵的就是 args 參數(shù)通過(guò) restArgs 函數(shù)處理為一個(gè)數(shù)組,方便了下一步的 func.apply(null, args); 傳值。
_.defer = _.partial(_.delay, _, 1);
_.defer 這個(gè)函數(shù)我們首先可以看到內(nèi)部應(yīng)用了 _.partial 并且中間傳入?yún)?shù) _,這意味著當(dāng) _.defer 執(zhí)行的時(shí)候傳入的參數(shù)會(huì)被補(bǔ)全到 _.partial 內(nèi)部 bound 中的 args[0] 位置,而此時(shí) args 的值為 [func, 1]并將它傳給 _.delay 函數(shù),即 _.delay.apply(null, args);,用著這種方式曲線的設(shè)置 setTimeout 函數(shù)的 wait = 1,目的就是處理代碼復(fù)用問(wèn)題,不然的話完全可以改裝一下 _.delay 函數(shù)可以更簡(jiǎn)單的實(shí)現(xiàn)這一功能。
_.throttle = function(func, wait, options) { var timeout, context, args, result; var previous = 0; if (!options) options = {}; var later = function() { previous = options.leading === false ? 0 : _.now(); timeout = null; result = func.apply(context, args); if (!timeout) context = args = null; }; var throttled = function() { var now = _.now(); if (!previous && options.leading === false) previous = now; var remaining = wait - (now - previous); context = this; args = arguments; if (remaining <= 0 || remaining > wait) { if (timeout) { clearTimeout(timeout); timeout = null; } previous = now; result = func.apply(context, args); if (!timeout) context = args = null; } else if (!timeout && options.trailing !== false) { timeout = setTimeout(later, remaining); } return result; }; throttled.cancel = function() { clearTimeout(timeout); previous = 0; timeout = context = args = null; }; return throttled; };
_.throttle 函數(shù)可以限制和控制其參數(shù) func 的執(zhí)行次數(shù)和執(zhí)行時(shí)間,思想就是通過(guò) wait、now、previous 和 remaining 進(jìn)行判斷然后分別執(zhí)行相應(yīng)的策略。
wait:使用 _.throttle 函數(shù)時(shí)傳入的時(shí)間標(biāo)識(shí),在每個(gè) wait 毫秒時(shí)間段內(nèi)最多且一定調(diào)用一次該函數(shù)。
now:使用 _.now() 函數(shù)獲取當(dāng)前時(shí)間戳。
previous:用來(lái)緩存函數(shù)執(zhí)行時(shí)的時(shí)間戳,用于后面與下一次執(zhí)行時(shí)的時(shí)間戳進(jìn)行相關(guān)判斷。
remaining:緩存 wait - (now - previous) 的差值。
我們?cè)诳垂倬W(wǎng)介紹可以知道 _.throttle 傳遞的 options 分四種情況(默認(rèn)是 {leading:false,trailing:false}):
{leading:true,trailing:true}:從實(shí)例化 _.throttle 的時(shí)間開(kāi)始到執(zhí)行實(shí)例化的函數(shù)的時(shí)間為止,中間的差值定義為 now - previous,進(jìn)而得出設(shè)定的時(shí)間 wait 與 now - previous 的差值 remaining,從而決定怎么執(zhí)行函數(shù)。參考 世紀(jì)之光 的很有趣的說(shuō)法,就是第一次可以立即執(zhí)行,第二次開(kāi)始將在每 wait 時(shí)間內(nèi)只允許執(zhí)行一次,為什么會(huì)第一次立即執(zhí)行呢,因?yàn)榇蠹以O(shè)置的 wait 一般都不會(huì)太大,所以頁(yè)面加載過(guò)程中一般已經(jīng)執(zhí)行了 _.throttle 的實(shí)例化,也就是說(shuō)其 remaining <= 0,而后面如果一直執(zhí)行函數(shù),那么就開(kāi)始 0 < remaining <= wait 模式了,
{leading:false,trailing:false}:這種情況下比較有意思的是 previous 這個(gè)參數(shù),在實(shí)例化 _.throttle 的時(shí)候,previous = 0,利用了 !0 === true 的特性使 _.throttle 內(nèi)部并沒(méi)有執(zhí)行回調(diào)函數(shù) func,所以第一次函數(shù)調(diào)用失敗,在第二次開(kāi)始 previous = now (now 為第一次調(diào)用的時(shí)間戳),所以它也分為兩種情況:
{leading:true,trailing:false}:這種情況下是沒(méi)有 setTimeout 函數(shù)的,因?yàn)?leading:true,所以 previous 初始化為 0,意味著第一次執(zhí)行函數(shù)會(huì)立即執(zhí)行,兒后面就要遵循 remaining <= 0 || remaining > wait 才能執(zhí)行,也就是說(shuō)只有第一執(zhí)行完畢后的時(shí)間超過(guò)了 wait 才能繼續(xù)調(diào)用函數(shù)才能執(zhí)行(調(diào)用是重點(diǎn)),以此類(lèi)推。
{leading:false,trailing:true}:這種情況由于 leading:false,所以每次 previous 都等于當(dāng)前調(diào)用函數(shù)時(shí)的時(shí)間戳,所以完美的不存在 remaining <= 0 || remaining > wait 的情況,由此只能通過(guò) setTimeout 執(zhí)行回調(diào),所以遵循通過(guò) setTimeout 函數(shù)設(shè)定時(shí)間為 remaining 毫秒后執(zhí)行 _.throttle 函數(shù)的回調(diào)函數(shù) func,用以達(dá)到在規(guī)定時(shí)間 wait 毫秒時(shí)執(zhí)行函數(shù)的目的,并且規(guī)定 wait 時(shí)間內(nèi)只執(zhí)行一次函數(shù)。
其實(shí)總結(jié)一下就是大概一下兩種都存在或者只存在其一的情況:
remaining <= 0:立即執(zhí)行 _.throttle 函數(shù)的回調(diào)函數(shù) func。
0 < remaining <= wait:通過(guò) setTimeout 函數(shù)設(shè)定時(shí)間為 remaining 毫秒后執(zhí)行 _.throttle 函數(shù)的回調(diào)函數(shù) func,用以達(dá)到在規(guī)定時(shí)間 wait 毫秒時(shí)執(zhí)行函數(shù)的目的,并且規(guī)定 wait 時(shí)間內(nèi)只執(zhí)行一次函數(shù)。
_.debounce = function(func, wait, immediate) { var timeout, result; var later = function(context, args) { timeout = null; if (args) result = func.apply(context, args); }; var debounced = restArgs(function(args) { if (timeout) clearTimeout(timeout); if (immediate) { var callNow = !timeout; timeout = setTimeout(later, wait); if (callNow) result = func.apply(this, args); } else { timeout = _.delay(later, wait, this, args); } return result; }); debounced.cancel = function() { clearTimeout(timeout); timeout = null; }; return debounced; };
_.debounce 更像是 _.delay 的方言版,當(dāng) immediate = true 的時(shí)候通過(guò) var callNow = !timeout = false 達(dá)到立即執(zhí)行回調(diào)函數(shù) func 的目的,并用 later 函數(shù)限制 規(guī)定 wait 時(shí)間內(nèi)不允許在調(diào)用函數(shù)(later 函數(shù)內(nèi)部 context = args = underfind,其實(shí)我們知道 var later = function(context, args) 這個(gè)條件是為 _.delay(later, wait, this, args) 準(zhǔn)備的)。
_.wrap = function(func, wrapper) { return _.partial(wrapper, func); };
_.wrap 的兩個(gè)參數(shù)理論上都要求是 Function,我們已經(jīng)知道 _.partial 是用來(lái)在 this 上下功夫的,雖然這里和 this 也沒(méi)什么太大關(guān)系,之所以這里應(yīng)用了 _.partial 是為了讓 func 作為 wrapper 的第一個(gè)參數(shù)執(zhí)行,并且通過(guò) executeBound 函數(shù)對(duì)函數(shù)調(diào)用模式和方法調(diào)用模式做處理。
_.negate = function(predicate) { return function() { return !predicate.apply(this, arguments); }; };
_.negate 用來(lái)做真值判斷。
_.compose = function() { var args = arguments; var start = args.length - 1; return function() { var i = start; var result = args[start].apply(this, arguments); while (i--) result = args[i].call(this, result); return result; }; };
_.compose 用于將函數(shù)執(zhí)行結(jié)果進(jìn)行傳遞,需要注意的是 var args = arguments; 中的 arguments 和 args[start].apply(this, arguments); 中的 arguments 并不相同就可以了。這個(gè)涉及到函數(shù)的執(zhí)行,當(dāng)每一個(gè)函數(shù)執(zhí)行的時(shí)候都會(huì)形成一個(gè)內(nèi)部的上下文執(zhí)行環(huán)境(傳說(shuō)叫 ExecutionContext,這個(gè)我還沒(méi)有考證過(guò)),在構(gòu)建環(huán)境的同時(shí)生成 arguments 變量和作用域鏈表等等,這里不像敘述了。
_.after = function(times, func) { return function() { if (--times < 1) { return func.apply(this, arguments); } }; };
_.after 接受兩個(gè)參數(shù),Number 參數(shù)用來(lái)限定 _.after 實(shí)例化函數(shù)的執(zhí)行次數(shù),說(shuō)白了就是只有當(dāng)?shù)?Number 次執(zhí)行實(shí)例化函數(shù)的時(shí)候才會(huì)繼續(xù)執(zhí)行 func 回調(diào),這個(gè)用來(lái)處理遍歷 _.each 時(shí)某些情況很有用。
_.before = function(times, func) { var memo; return function() { if (--times > 0) { memo = func.apply(this, arguments); } if (times <= 1) func = null; return memo; }; };
_.before,與 _.after 相反,只在規(guī)定 Number 參數(shù)的次數(shù)內(nèi)以此執(zhí)行 _.before,超過(guò)之后結(jié)束。
_.once = _.partial(_.before, 2);
_.once 創(chuàng)建一個(gè)只能調(diào)用一次的函數(shù)。到這里關(guān)于函數(shù)相關(guān)的源碼就結(jié)束了,說(shuō)心里話很多地方看得懂不一定說(shuō)的懂,說(shuō)的懂也不一定用的懂,就拿這個(gè) _.once 來(lái)講,它只用了 _.partial 和 _.before 來(lái)做文章,用 _.before 限定只能執(zhí)行一次還好理解,那么為什么一定要用 _.partial 坐下處理呢,其目的真的只是為了讓 2 作為 _.before 的第一個(gè)參數(shù)進(jìn)行傳遞過(guò)去并將 _.once 的傳參作為 arguments[1+] 傳入么,更深一層考慮,_.partial 函數(shù)是不是有處理過(guò) _.once 傳遞過(guò)來(lái)的函數(shù)的作用域鏈和 this 相關(guān)的情況呢。
_.restArgs = restArgs;
_.restArgs 將 restArgs 函數(shù)綁定到 _ 對(duì)象上。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/79653.html
摘要:組件的選擇命令行工具首先我們需要一個(gè)命令行工具來(lái)方便的執(zhí)行命令,這里我們選擇組件,如果不喜歡使用且有能力的人完全可以通過(guò)組件自己封裝執(zhí)行命令函數(shù)。 對(duì)于一個(gè)成熟的項(xiàng)目而言,一定需要一個(gè)注釋文檔生成工具,我們有很多可選的開(kāi)源項(xiàng)目,如jsdoc、yuidocjs 等等,擁有這些強(qiáng)大的工具我們完全可以勝任任何注釋方面的管理了么? 一個(gè)成熟的開(kāi)發(fā)者都會(huì)知道不管怎么樣的項(xiàng)目都會(huì)在不同的開(kāi)發(fā)條件下...
摘要:新出臺(tái)的則規(guī)定,包括六種原始類(lèi)型和,還有一種,詳見(jiàn)數(shù)據(jù)類(lèi)型和數(shù)據(jù)結(jié)構(gòu)。用于返回一個(gè)由給定對(duì)象的所有可枚舉自身屬性的屬性名組成的數(shù)組,。接下來(lái)判斷數(shù)字進(jìn)行相應(yīng)的操作,其中有和兩個(gè)方法,詳見(jiàn)和。 一直想寫(xiě)一篇這樣的文章,于是心動(dòng)不如行動(dòng),這里選擇的是 Underscore.js 1.8.3 版本,源碼注釋加在一起1625行。 Underscore.js 1.8.3 http://unde...
摘要:第四個(gè)判斷如果是對(duì)象執(zhí)行返回一個(gè)斷言函數(shù),用來(lái)判定傳入對(duì)象是否匹配指定鍵值屬性。都不匹配最后執(zhí)行,返回傳入的對(duì)象的屬性。設(shè)置的值并生成函數(shù),等同于,使具有屬性且有值則返回,否則返回,這是一個(gè)判斷函數(shù)。 在第二小章節(jié)里面我按照源碼順序介紹幾個(gè)方法,源碼緊接著第一章繼續(xù): var builtinIteratee; builtinIteratee,內(nèi)置的 Iteratee (迭代器)。...
摘要:接收三個(gè)參數(shù)分別為回調(diào)和,其中與是可選參數(shù)。官網(wǎng)釋義排序一個(gè)列表組成一個(gè)組,并且返回各組中的對(duì)象的數(shù)量的計(jì)數(shù)。類(lèi)似,但是不是返回列表的值,而是返回在該組中值的數(shù)目。 繼續(xù)前面的內(nèi)容,前文我們提到了很多方法的講解,其實(shí)到這里就已經(jīng)差不多了,因?yàn)榇蟛糠执a其實(shí)都是套路,一些基礎(chǔ)函數(shù)再靈活變化就可以組成很多實(shí)用的功能。 _.sortBy = function(obj, iteratee,...
摘要:傳入值進(jìn)行判斷以此決定函數(shù),將三個(gè)參數(shù)包括回調(diào)傳入中其中回調(diào)函數(shù)充當(dāng)?shù)鬟M(jìn)行真值檢測(cè),最后。是從一個(gè)中隨機(jī)返回值,并且返回值受限于這個(gè)參數(shù),如果沒(méi)有傳入或者傳入了則執(zhí)行語(yǔ)句,目的是將判斷處理之后返回單一值。 今天繼續(xù)上次的內(nèi)容,之前我們講到了 reduce 的用法,其實(shí)我覺(jué)得用法倒是其次的關(guān)鍵是作者實(shí)現(xiàn) reduce 過(guò)程中所靈活用到的函數(shù)處理方法,我們只要有心稍加總覺(jué)完全可以拿來(lái)主...
閱讀 1136·2021-11-22 15:33
閱讀 3442·2021-11-08 13:20
閱讀 1483·2021-09-22 10:55
閱讀 2115·2019-08-29 11:08
閱讀 846·2019-08-26 12:24
閱讀 3146·2019-08-23 17:15
閱讀 2303·2019-08-23 16:12
閱讀 2014·2019-08-23 16:09