摘要:上篇文章講述了的基本結構搭建,本文繼續講鏈式調用與混入。獲得一個經包裹后的實例標識當前實例支持鏈式調用小試牛刀返回的為一個實例對象,后面的方法判斷屬性是否為為的話再調用一次方法再返回原來實例即可。
上篇文章講述了 underscore 的基本結構搭建,本文繼續講鏈式調用與混入。
如果你還沒看過第一篇文章,請點擊 “underscore 誕生記(一)—— 基本結構搭建”
鏈式調用在 JQuery 中,我們經常使用到鏈式調用,如:
$(".div") .css("color", "red") .show();
那么在 underscore 中,是否支持鏈式調用呢?答案是支持的,只不過默認不開啟鏈式調用罷了。
想要實現鏈式調用,通常我們會在支持鏈式調用的函數中返回對象本身:
let car = { run(name) { console.log(`${name}老司機開車啦喂!`); return this; }, stop() { console.log("車停了"); }, }; car.run("奔馳").stop(); // 奔馳老司機開車啦喂! // 車停了
那么在每個 _ 方法下都 return this , 顯然不大優雅缺乏可控性!嘗試著寫個通用方法 chain() 開啟鏈式調用。
_.chain = function(obj) { // 獲得一個經underscore包裹后的實例 var instance = _(obj); // 標識當前實例支持鏈式調用 instance._chain = true; return instance; }; // 小試牛刀 _.chain([1, 2, 3]); /* { _chain: true, _wrapped: [1, 2, 3] } */
返回的為一個實例對象,后面的方法判斷 _chain 屬性是否為 true,為 true 的話再調用一次 chain() 方法再返回原來實例即可。我們在之前用于給 prototype 復制方法的 each() 函數加入判斷吧
var ArrayProto = Array.prototype; var push = ArrayProto.push; _.each(_.functions(_), function(name) { var func = _[name]; _.prototype[name] = function() { var args = [this._wrapped]; // args = [this._wrapped, arguments[0], arguments[1]...], 相當于用 this._wrapped 代替 obj 實現 push.apply(args, arguments); return this._chain ? _(func.apply(_, args)).chain() : func.apply(_, args); }; });
有點冗長,將 return this._chain ? _(func.apply(_, args)).chain() : func.apply(_, args); 改造下,
// 判斷是否需要鏈式調用 var chainResult = function(instance, obj) { return instance._chain ? _(obj).chain() : obj; }; var ArrayProto = Array.prototype; var push = ArrayProto.push; _.each(_.functions(_), function(name) { var func = _[name]; _.prototype[name] = function() { var args = [this._wrapped]; // args = [this._wrapped, arguments[0], arguments[1]...], 相當于用 this._wrapped 代替 obj 實現 push.apply(args, arguments); return chainResult(this, func.apply(_, args)); }; });
好了,試試看效果:
_.chain([1, 2, 3]) .each(function(item) { console.log(item); }) .each(function(item) { console.log(item); }); // 1 2 3 1 2 3 // {_wrapped: [1,2,3], _chain: true}混入(mixin)
underscore 很強大,功能也很齊全,但有時候也不能滿足所有人的需求。我們想創建一些方法,讓它掛載在 _ 上,這樣我們全局也可以調用到這些方法,作為一款強大的方法庫,也應該提供這種接口,讓用戶自定添加方法,ok, let us do it !
我們先定義一個 mixin 方法
_.mixin = function(obj) {}; // `obj` 為一個類似 `_` 的對象。傳入的這個對象,也需要遍歷一次,并且復制方法于 prototype 屬性上。詳細代碼如下: _.mixin = function(obj) { _.each(_.functions(obj), function(name) { var func = (_[name] = obj[name]); _.prototype[name] = function() { var args = [this._wrapped]; push.apply(args, arguments); // args = [this._wrapped, arguments[0], arguments[1]...], 相當于用 this._wrapped 代替 obj 實現 return chainResult(this, func.apply(_, args)); }; }); return _; };
看到這里,你會發現,我們在方法的最后遍歷賦值給_.prototype方法,其實就是一次mixin() 的調用.
_.each(_.functions(_), function(name) { var func = _[name]; _.prototype[name] = function() { var args = [this._wrapped]; // args = [this._wrapped, arguments[0], arguments[1]...], 相當于用 this._wrapped 代替 obj 實現 push.apply(args, arguments); return func.apply(_, args); }; }); // 簡化為 _.mixin(_);最終代碼
(function() { // root 為掛載對象,為 self 或 global 或 this 或 {} var root = (typeof self == "object" && self.self === self && self) || (typeof global == "object" && global.global === global && global) || this || {}; var _ = function(obj) { // 如果傳入的是實例后對象,返回它 if (obj instanceof _) return obj; // 如果還沒有實例化,new _(obj) if (!(this instanceof _)) return new _(obj); this._wrapped = obj; }; // 最大數值 var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1; var ArrayProto = Array.prototype; var push = ArrayProto.push; // 判斷是否為數組 var isArrayLike = function(collection) { var length = collection.length; return ( typeof length == "number" && length >= 0 && length <= MAX_ARRAY_INDEX ); }; // 判斷是否需要鏈式調用 var chainResult = function(instance, obj) { return instance._chain ? _(obj).chain() : obj; }; root._ = _; _.VERSION = "1.9.1"; // 給我們的 underscore 一個版本號吧 /** * 字符串倒裝 */ _.reverse = function(string) { return string .split("") .reverse() .join(""); }; /** * 判斷是否為 function */ _.isFunction = function(obj) { return typeof obj == "function" || false; }; // 鏈式調用方法 _.chain = function(obj) { // 獲得一個經underscore包裹后的實例 var instance = _(obj); // 標識當前實例支持鏈式調用 instance._chain = true; return instance; }; /** * 獲取_的所有屬性函數名 */ _.functions = function(obj) { var names = []; for (var key in obj) { if (_.isFunction(obj[key])) names.push(key); } return names.sort(); }; /** * 數組或對象遍歷方法,并返回修改后的對象或數組 * @param iteratee 回調函數 * @param context 回調函數中this的指向 */ _.map = function(obj, iteratee, context) { var length = obj.length, results = Array(length); for (var index = 0; index < length; index++) { results[index] = iteratee.call(context, obj[index], index, obj); } return results; }; /** * 數組或對象遍歷方法 */ _.each = function(obj, callback) { var length, i = 0; if (isArrayLike(obj)) { // 數組 length = obj.length; for (; i < length; i++) { // 這里隱式的調用了一次 callback.call(obj[i], obj[i], i); if (callback.call(obj[i], obj[i], i) === false) { break; } } } else { // 對象 for (i in obj) { if (callback.call(obj[i], obj[i], i) === false) { break; } } } return obj; }; /* * 混入方法 mixin */ _.mixin = function(obj) { _.each(_.functions(obj), function(name) { var func = (_[name] = obj[name]); _.prototype[name] = function() { var args = [this._wrapped]; push.apply(args, arguments); // args = [this._wrapped, arguments[0], arguments[1]...], 相當于用 this._wrapped 代替 obj 實現 return chainResult(this, func.apply(_, args)); }; }); return _; }; _.mixin(_); })();未完待續,靜待下篇
前端進階小書(advanced_front_end)
前端每日一題(daily-question)
webpack4 搭建 Vue 應用(createVue)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/103983.html
摘要:譯立即執行函數表達式處理支持瀏覽器環境微信小程序。學習整體架構,利于打造屬于自己的函數式編程類庫。下一篇文章可能是學習的源碼整體架構。也可以加微信,注明來源,拉您進前端視野交流群。 前言 上一篇文章寫了jQuery整體架構,學習 jQuery 源碼整體架構,打造屬于自己的 js 類庫 雖然看過挺多underscore.js分析類的文章,但總感覺少點什么。這也許就是紙上得來終覺淺,絕知此...
摘要:目前通行的模塊規范主要集中在和,因此為了讓定義的庫能夠適用于各種規范。在框架的定義時需檢測使用環境并兼容各種規范。服務端規范,檢測是否存在,滿足時通過將暴露出來,不滿足則通過對象暴露出來。前者回調函數處理的是值和下標,后者處理的是值和屬性。 本文為博主原創文章,轉載請注明出處 https://www.cnblogs.com/kidfl... underscore作為開發中比較常用的一個...
摘要:在上篇文章整體架構分析中,我們講過上面的方法有兩種掛載方式,一個是掛載到構造函數上以的形式直接調用在后文上統稱構造函數調用,另一種則是掛到上以的形式被實例調用在后文上統稱原型調用。 underscore源碼分析之基礎方法 本文是underscore源碼剖析系列的第二篇,主要介紹underscore中一些基礎方法的實現。 mixin 在上篇文章underscore整體架構分析中,我們講...
摘要:支持形式的調用這其實是非常經典的無構造,其實就是一個構造函數,的結果就是一個對象實例,該實例有個屬性,屬性值是。 前言 終于,樓主的「Underscore 源碼解讀系列」underscore-analysis 即將進入尾聲,關注下 timeline 會發現樓主最近加快了解讀速度。十一月,多事之秋,最近好多事情搞的樓主心力憔悴,身心俱疲,也想盡快把這個系列完結掉,也好了卻一件心事。 本文...
摘要:我們都知道可以鏈式調用,比如我們寫個簡單的模擬鏈式調用之所以能實現鏈式調用,關鍵就在于通過,返回調用對象。系列預計寫八篇左右,重點介紹中的代碼架構鏈式調用內部函數模板引擎等內容,旨在幫助大家閱讀源碼,以及寫出自己的。 前言 本文接著上篇《underscore 系列之如何寫自己的 underscore》,閱讀本篇前,希望你已經閱讀了上一篇。 jQuery 我們都知道 jQuery 可以鏈...
閱讀 2241·2021-11-23 09:51
閱讀 1073·2021-11-22 15:35
閱讀 4831·2021-11-22 09:34
閱讀 1597·2021-10-08 10:13
閱讀 3018·2021-07-22 17:35
閱讀 2520·2019-08-30 15:56
閱讀 3079·2019-08-29 18:44
閱讀 3089·2019-08-29 15:32