工具汇总

_.noConflict

_.noConflict(): 将 _ 对象的所有权交还。

源码

_.noConflict = function () {
    // 回复原来的_指代的对象
    root._ = previousUnderscore;
    // 返回underscore对象
    return this;
};

假定在我们的工程中,已经 占据_ 对象,那么,之后我们引入 underscore,_ 就会被 underscore 夺走:

_ = {
    owner: 'wxj'
};

// 引入underscore后

console.log(_.owner); // => undefined

_.noConflict 能够返回被 underscore 占据的 _,并重新制定 underscore 对象:

var underscore = _.noConflict();

console.log(_.owner); // => 'wxj'

_.identity

_.identity(value):返回 value 本身。

源码

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

很多没接触过 FP 编程的开发者看到这个方法会很诧异,要获得值本身的话,直接用 value 不就好,干嘛还有包一层函数?假定有这样一个情景,我们想要复制一个数组:

var arr = [1,2,3,4,5];
var dstArr = arr.map((item, index) => {
    return item;
});

而借助于 _.identity 方法,我们可以这样做:

var arr = [1,2,3,4,5];
var dstArr = arr.map(_.identity);

_.constant

_.constant(value):返回一个函数,该函数将返回 value 本身。

源码

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

似乎比 _.identity 更加过分,更加匪夷所思,因为 _.constant 又包了一层。但我们注意到,_.constant 内部形成了什么?对的,一个闭包,他将为我们缓存住当时的 value,最终返回的所谓 常量 不过就是当时缓存的值:

var a = 2;
var getConstA = _.constant(a);

a = 3;
getConstA(); // => 2

_.noop

_.noop:保存了一个空函数的引用。

源码

_.noop = function () {
};

_.noop 指向了一个空函数引用,避免了创建空函数时不必要的开销,也节省了可能存在的判断开销:

var a = {
    doSomething: null;
};
a.doSomething = function() {console.log("doing");}
// 某个业务需要的地方,需要额外判断
_.isFunction(a.doSomething) && a.doSomething();
// 现在
var a = {
     doSomething: _.noop
};
a.doSomething = function() {console.log("doing");}
// 不再需要判断
a.doSomething();

_.propertyOf

_.propertyOf(obj):返回一个属性获得函数,该函数能够获得 obj 的属性。

源码

_.propertyOf = function (obj) {
    return obj == null ? function () {} : function (key) {
        return obj[key];
    };
};

可能又有人觉得大材小用了,要获得对象属性直接用 . 操作符不就好了吗,比如 obj.name。考虑一个场景,我们想要获得一个对象所有的值,传统的做法会是:

var student = {
    name: 'wxj',
    age: 18
};
var values = _.keys(student).map((key) => student[key]); // ['wxj', 18]

借助于 _.propertyOf,将可以这样做:

getStudentProp = _.propertyOf(student);
var values = _.keys(student).map(getStudentProp);

_.times

_.times(n, iteratee):执行函数 iteratee n 次,返回保存了每次执行结果的数组。

源码

_.times = function (n, iteratee, context) {
    var accum = Array(Math.max(0, n));
    iteratee = optimizeCb(iteratee, context, 1);
    for (var i = 0; i < n; i++) accum[i] = iteratee(i);
    return accum;
};

从源码中可以看到,iteratee 将会是一个迭代函数,并且其第一个参数将会被传入当前迭代的索引值。

用例

function getIndex(index) {
    return index;
}

var indexes = _.times(3, getIndex);
// => [0,1,2]

_.random

_.random(min, max):返回 [min,max] 之间的随机数,如果没有传递 max,则返回 [0,min] 之间的随机数。

源码

_.random = function (min, max) {
    // 如果没有设定右边界, 则返回[0, min]之间的随机数
    if (max == null) {
        max = min;
        min = 0;
    }
    return min + Math.floor(Math.random() * (max - min + 1));
};

用例

console.log(_.random(0,9)); // => 6
console.log(_.random(5)); // => 3

_.now

_.now():方法返回自 1970 年 1 月 1 日 00:00:00 UTC 到当前时间的毫秒数。

源码

_.now = Date.now || function () {
    return new Date().getTime();
};

该方法会优先尝试使用 ES5.1 提供的 Date.now() 方法。

用例

var now = _.now(); // => 1482133330807
var nowDate = new Date(now); // => Mon Dec 19 2016 15:42:10 GMT+0800 (CST)

_.result

_.result(obj, prop, fallback):如果 propobj 的成员方法,则调用之,否则获得 prop 属性。若 obj.propundefined,可以传递一个 fallback 做为后置处理。

源码

_.result = function (object, prop, fallback) {
    var value = object == null ? void 0 : object[prop];
    if (value === void 0) {
        value = fallback;
    }
    return _.isFunction(value) ? value.call(object) : value;
}

用例

var student = {
    name: 'wxj',
    sayHello: function () {
        console.log('hello');
    }
}
_.result(student, 'sayHello'); // => 'hello'
_.result(student, 'name'); // => 'wxj'
_.result(student, age, 13); // => 13

_.uniqueId

_.uniqueId(prefix): 根据传入的 prefix,生成唯一 ID。

源码

var idCounter = 0;

/**
 * 根据传入的prefix,产生全局唯一的id
 * @param {string} prefix id前缀
 */
_.uniqueId = function (prefix) {
    var id = ++idCounter + '';
    return prefix ? prefix + id : id;
};

可以看到,该id产生器的起点为1;

用例

var prefix = "wxj";
_.uniqueId(prefix); // => wxj1
_.uniqueId(prefix); // => wxj2

createEscaper

underscore 中提供了 _.escape(string)_.unescape(string) 来对 HTML 字符串进行逃逸 / 反逃逸,他们都由内部函数 createEscaper(map) 进行创建:

// 定义一系列需要逃逸的html字符
var escapeMap = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#x27;',
    '`': '&#x60;'
};

var createEscaper = function (map) {
    var escaper = function (match) {
        // 每次捕获通过map中创建的映射进行替换
        return map[match];
    };
    // Regexes for identifying a key that needs to be escaped.
    // 动态创建正则表达式,不捕获
    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;
    };
};

createEscaper 接受一个映射表 map 参数,该映射表反映的是 待转义字符转义后字符 的映射关系,之后,createEscaper 会动态创建匹配测试正则 testRegexp 及替换正则 replaceRegexp,最终返回的转义函数将利用这两个正则完成 HTML 字符的转义或者反转义。

createEscaper 源码中我们也看到了,String.prototype.replace(regexp|substr, newSubStr|function) 的第二个参数不仅能够接受字符串对匹配的到字符子串进行 直接替换,还能接受函数进行 间接替换,该函数接受的一个参数,其代表的是匹配到的字符子串。

_.escape

_.escape(string):对 string 进行 HTML 字符逃逸。

源码

/**
 * 转义html特殊字符
 * @param {string} string 待转义字符
 */
_.escape = createEscaper(escapeMap);

用例

var html = '<a href="http://yoyoyohamapi.me">吴小蛆的博客</a>';
var escaped = _.escape(html);
// => '&lt;a href=&quot;http://yoyoyohamapi.me&quot;&gt;吴小蛆的博客&lt;/a&gt;'

_.unescape

_.unescape(string):对 string 进行 HTML 字符反逃逸。

源码

/**
 * 取消转义
 * @param {string} string 待取消转义字符
 */
_.unescape = createEscaper(unescapeMap);

用例

var html = '<a href="http://yoyoyohamapi.me">吴小蛆的博客</a>';
var unescaped = _.unescape(escaped);
// => '<a href="http://yoyoyohamapi.me">吴小蛆的博客</a>'

results matching ""

    No results matching ""