動手DIY一個underscorejs庫及underscorejs源碼分析2

接着第一篇《動手DIY一個underscorejs庫及underscorejs源碼分析1》

所有代碼掛在我的github上。

1.兼容requirejs和seajs模塊化

  • requirejs
    在代碼的尾部加上
    if (typeof define == 'function' && define.amd) {
        //定義一個模塊並且起個名字
        define('_underscore', [], function() {
            return _;
        });
    }

使用測試:代碼請點我
demo3.html

<body>
    <script data-main="demo3" src="lib/require.js"></script>
</body>

demo3.js

define(function(require) {
    require(['../DIY/2/_underscore'], function() {
        console.log(_);
    });
});
  • 加上支持seajs的代碼
    if (typeof define == 'function' && define.amd) {
        define('_underscore', [], function() {
            return _;
        });
    } else if (typeof define == 'function' && define.cmd) { //seajs
        define(function(require, exports, module) {
            module.exports = _;
        });
    }

使用:
demo2.html

    <script src="lib/sea-debug.js"></script>
    <script>
        seajs.use('./demo2');
    </script>

demo2.js

define(function(require, exports, module) {
    var _ = require('../DIY/2/_underscore');
    console.info(_);
});

2.支持nodejs

root._ = _;

修改爲:

  if (typeof exports != 'undefined' && !exports.nodeType) {
    if (typeof module != 'undefined' && !module.nodeType && module.exports) {
      exports = module.exports = _;
    }
    exports._ = _;
  } else {
    root._ = _;
  }

3._.extend

使用:

    console.log(_.extend({name: 'moe'}, {age: 50}));
    //結果Object {name: "moe", age: 50}
    //類似與_.keys
    _.allKeys = function(obj) {
        if (!_.isObject(obj)) return [];
        var keys = [];
        for (var key in obj) keys.push(key);
        // Ahem, IE < 9.
        // if (hasEnumBug) collectNonEnumProps(obj, keys);
        return keys;
    };

主函數:

    var createAssigner = function(keysFunc, defaults) {
        return function(obj) {
            var length = arguments.length;
            if (defaults) obj = Object(obj);
            if (length < 2 || obj == null) return obj;
            for (var index = 1; index < length; index++) {
                var source = arguments[index],
                    keys = keysFunc(source),
                    l = keys.length;
                for (var i = 0; i < l; i++) {
                    var key = keys[i];
                    if (!defaults || obj[key] === void 0) obj[key] = source[key];
            //將參數(對象)放入到obj組合到一起
                }
            }
            return obj;
        };
    };
    _.extend = createAssigner(_.allKeys);
    _.extendOwn = _.assign = createAssigner(_.keys);

4.重要內部函數cb

    var builtinIteratee;
    //如果是函數則返回上面說到的回調函數;
    //如果是對象則返回一個能判斷對象是否相等的函數;
    //默認返回一個獲取對象屬性的函數
    var cb = function(value, context, argCount) {
        if (_.iteratee !== builtinIteratee) return _.iteratee(value, context);
        if (value == null) return _.identity; //默認的迭代器
        if (_.isFunction(value)) return optimizeCb(value, context, argCount);
        if (_.isObject(value)) return _.matcher(value);
        return _.property(value);
    };
    _.iteratee = builtinIteratee = function(value, context) {
        return cb(value, context, Infinity);
    };

4.1 _.identity

很簡單但是是默認的迭代器

    _.identity = function(value) {
        return value;
    };

測試很簡單

    var obj1 = {name:'zry'};
    console.log(obj1 === _.identity(obj1));//true

4.2 _.matcher

    _.matcher = _.matches = function(attrs) {
        attrs = _.extendOwn({}, attrs);
        return function(obj) {
            return _.isMatch(obj, attrs);
        };
    };
    //兩個對象是不是全等於。給定的對象是否匹配attrs指定鍵/值屬性
    _.isMatch = function(object, attrs) {
        var keys = _.keys(attrs),
            length = keys.length;
        if (object == null) return !length;
        var obj = Object(object);
        for (var i = 0; i < length; i++) {
            var key = keys[i];
            if (attrs[key] !== obj[key] || !(key in obj)) return false;
        }
        return true;

    };

測試:

    var obj2 = {selected: true, visible: true};
    var ready = _.isMatch(obj2,{selected: true, visible: true});
    //返回一個斷言函數,這個函數會給你一個斷言 可以用來辨別 
    //給定的對象是否匹配attrs指定鍵/值屬性
    console.log(ready);//true

4.3 _.property

property函數在第一篇博客中已經實現

    _.property = property;

5._.map

    _.map = _.collect = function(obj, iteratee, context) {
        iteratee = cb(iteratee, context);
        var keys = !isArrayLike(obj) && _.keys(obj),
            length = (keys || obj).length,
            results = Array(length);
        for (var index = 0; index < length; index++) {
            var currentKey = keys ? keys[index] : index;
            results[index] = iteratee(obj[currentKey], currentKey, obj);
            //返回的是(value,key,obj)
        }
        return results;
    };

6._.filter

    _.filter = _.select = function(obj, predicate, context) {
         var results = [];
        predicate = cb(predicate, context);
        _.each(obj, function(value, index, list) {
            if (predicate(value, index, list)) results.push(value);
        });
        return results;
    };

測試:

var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });//[2,4,6]

7.兩個常用的工具函數_.escape,_.unescape`

7.1 _.escape

要過濾的字符串

    var escapeMap = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#x27;',
        '`': '&#x60;'
    };

主函數

    var createEscaper = function(map) {
        var escaper = function(match) {//match 匹配的子串
            return map[match];
        };
        var source = '(?:' + _.keys(map).join('|') + ')';
        var testRegexp = RegExp(source);
        var replaceRegexp = RegExp(source, 'g');
        return function(string) {
            string = string == null ? '' : '' + string;
            return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
        };
    };

注意值了的string.replace函數第二個參數是個函數,那麼返回的數據第一個是match(匹配的子串)

變量名 代表的值
match 匹配的子串。(對應於上述的$&。)
p1,p2, … 假如replace()方法的第一個參數是一個RegExp對象,則代表第n個括號匹配的字符串。(對應於上述的1 2等。)
offset 匹配到的子字符串在原字符串中的偏移量。(比如,如果原字符串是“abcd”,匹配到的子字符串時“bc”,那麼這個參數將是1)
string 被匹配的原字符串。
_.escape = createEscaper(escapeMap);

測試:

console.log(_.escape('Curly, Larry & Moe')//Curly, Larry &amp; Moe

7.2 _.unescape

反轉要過濾的字符串

    _.invert = function(obj) {
        var result = {};
        var keys = _.keys(obj);
        for (var i = 0, length = keys.length; i < length; i++) {
            result[obj[keys[i]]] = keys[i];
        }
        return result;
    };
    var unescapeMap = _.invert(escapeMap);
    _.unescape = createEscaper(unescapeMap);

測試:

console.log(_.unescape('Curly, Larry &amp; Moe'));//Curly, Larry & Moe

參考閱讀:
- http://underscorejs.org/
- underscorejs中文:http://www.bootcss.com/p/underscore/
- UnderscoreJS精巧而強大工具包
- JS高手進階之路:underscore源碼經典

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章