<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                > 原文:[http://yalishizhude.github.io](http://yalishizhude.github.io/2015/09/22/underscore-source/) > 作者:[亞里士朱德](http://yalishizhude.github.io/about/) > underscore 源碼版本 1.8.2 ## 起因 很多人向我推薦研究js,可以看看一些第三方js類庫的源碼,而源碼之中最好解讀也最簡短的就是underscore,它也是我平常比較喜歡的一個庫,因為它性價比高:體積小、能力強。打開一看,才1000多行,試著讀了一下,確實很值得一看,所以對精彩部分做了一下整理。 ## 閉包 整個函數在一個閉包中,避免污染全局變量。通過傳入this(其實就是window對象)來改變函數的作用域。和jquery的自執行函數其實是異曲同工之妙。這種傳入全局變量的方式一方面有利于代碼閱讀,另一方面方便壓縮。 underscore寫法: ~~~ (function(){ ... }.call(this)); ~~~ jquery寫法: ~~~ (function(window, undefined) { ... })(window); ~~~ ## 原型賦值 ~~~ 18 var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; ~~~ Array,Object,Function這些本質都是函數,獲取函數原型屬性prototype也是為了便于壓縮。簡單解釋一下,如果代碼中要擴展屬性,可能這樣寫 ~~~ Object.prototype.xxx = ... ~~~ 而這種代碼是不可壓縮的,`Object`,`prototype`這些名字改了瀏覽器就不認得了。 但是上面的代碼中創建了`ObjProto`之后,源生代碼經過壓縮之后,`ObjProto`就可能命名成a變量,那么原來的代碼就壓縮成 ~~~ a.xxx = ... ~~~ 一個小建議就是凡事一段代碼被使用兩次以上都建議定義變量(函數),有利于修改和壓縮代碼。 ## 格式 ~~~ 29 var nativeIsArray = Array.isArray, nativeKeys = Object.keys, nativeBind = FuncProto.bind, nativeCreate = Object.create; ~~~ 這種定義的方式省略了多余的var,格式也美觀,讓我想到了sublime中的一個插件alignment。 ## 數據判斷 ~~~ 1194 _.isElement = function(obj) { return !!(obj && obj.nodeType === 1); }; ~~~ 判斷是否為dom,dom的nodeType屬性值為1。這里用`!!`強轉為boolean值 ~~~ 1200 _.isArray = nativeIsArray || function(obj) { return toString.call(obj) === '[object Array]'; }; ~~~ 判斷是否為數組。由于Array.isArray函數是ECMAScript 5新增函數,所以為了兼容之前的版本,在原生判斷函數不存在的情況下,后面重寫了一個判斷函數。用call函數來改變作用域可以避免當obj沒有toString函數報錯的情況。 ~~~ 1205 _.isObject = function(obj) { var type = typeof obj; return type === 'function' || type === 'object' && !!obj; }; ~~~ 判斷是否為對象。先用typeof判斷數據類型。函數也屬于對象,但是由于typeof null也是object,所以用!!obj來區分這種情況。 ~~~ 1219 if (!_.isArguments(arguments)) { _.isArguments = function(obj) { return _.has(obj, 'callee'); }; } ~~~ 判斷是否為arguments,很簡單,arguments有個特有屬性callee。 ~~~ 1239 _.isNaN = function(obj) { return _.isNumber(obj) && obj !== +obj; }; ~~~ NaN這個值有兩個特點:1.它是一個數;2.不等于它自己。 ‘+’放在變量前面一般作用是把后面的變量變成一個數,在這里已經判斷為一個數仍加上’+’,是為了把`var num = new Number()`這種沒有值的數字也歸為NaN。 ~~~ 1244 _.isBoolean = function(obj) { return obj === true || obj === false || toString.call(obj) === '[object Boolean]'; }; ~~~ 是不是以為如果是布爾值不是true就是false?還有第3中情況`var b = new Boolean()`。b也是布爾值。 ~~~ 1254 _.isUndefined = function(obj) { return obj === void 0; }; ~~~ 用void 0來表示undefined,非常有意思的小技巧。不過常用方式還是if(xxx)來判斷是不是undefined。 `eq`是underscore的一個內置函數,代碼太長,不粘貼了。isEmpty調用了這個函數。整個思路由易到難,先用===比較簡單數據,然后用toString來判斷是否相等,最后用遞歸處理復雜的Array、Function和Object對象。 ~~~ 1091 if (a === b) return a !== 0 || 1 / a === 1 / b; ~~~ 這里為了區分’+0’和’-0’,因為這兩個數對計算結果是有影響的。 ~~~ 1098 var className = toString.call(a); if (className !== toString.call(b)) return false; switch (className) { // Strings, numbers, regular expressions, dates, and booleans are compared by value. case '[object RegExp]': // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i') case '[object String]': // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is // equivalent to `new String("5")`. return '' + a === '' + b; case '[object Number]': // `NaN`s are equivalent, but non-reflexive. // Object(NaN) is equivalent to NaN if (+a !== +a) return +b !== +b; // An `egal` comparison is performed for other numeric values. return +a === 0 ? 1 / +a === 1 / b : +a === +b; case '[object Date]': case '[object Boolean]': // Coerce dates and booleans to numeric primitive values. Dates are compared by their // millisecond representations. Note that invalid dates with millisecond representations // of `NaN` are not equivalent. return +a === +b; } ~~~ 這里是對簡單對象進行判斷,分為兩類,一類是`String`和`RegExp`,這種數據直接`toString`然后判斷。另一類是`Number`、`Date`和`Boolean`,通過轉換成數字判斷。 ~~~ 1150 aStack.push(a); bStack.push(b); if (areArrays) { length = a.length; if (length !== b.length) return false; while (length--) { if (!eq(a[length], b[length], aStack, bStack)) return false; } } else { var keys = _.keys(a), key; length = keys.length; if (_.keys(b).length !== length) return false; while (length--) { key = keys[length]; if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false; } } aStack.pop(); bStack.pop(); ~~~ 對于數組和對象只能用遞歸了,同時用aStack和bStack來暫存遞歸中的子對象。這里一個小技巧的就是先判斷數組/屬性的長度,如果不相等可以有效地減少遞歸。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看