最近在拜读只有1700行(含注释)代码的Underscore.js 1.9.1,记录一些东西

(参考https://underscorejs.org/underscore.jshttps://github.com/hanzichi/underscore-analysis

  1. void 0替代了undefined;因为在低版本ie中undefined可以被重新赋值,或者在局部作用域中也可以被重新赋值;所以undefined显得不那么靠谱,于是就用void 0替代了undefined,void运算符对表达式求值都会返回undefined;
  2. 数据类型判断,先看原声方法支持与否,不支持再用Object.prototype.toString.call方法进行判断;不过在 IE < 9 下对 arguments 调用 Object.prototype.toString.call,结果是 [object Object],这时可以用arguments.callee是否存在来判断;dom元素判断方法为存在且nodeType为1;
  3. 如果在对象中重写了原型上的不可枚举属性,那么for in是可以取到这个属性的;但是在低版本ie中是不会取到的,它们会被认定为不可枚举属性;可以用obj.propertyIsEnumerable(prop)来确定对象中指定的属性是否可以被for in循环枚举,但是通过原型链继承的属性除外;
  4. createAssigner(补)
  5. 判断是否相同(注意0 === -0,但不相同)
    /* 1 */
    if (a === b) return a !== 0 || 1 / a === 1 / b; /* 2 null undefined */
    if (a == null || b == null) return false; /* 3 NaN */
    if (a !== a) return b !== b; /* 4 primitive */
    var type = typeof a;
    if (type !== 'function' && type !== 'object' && typeof b != 'object') return false; /* 5 正则 和 String */
    return '' + a === '' + b; /* 6 Number */
    if (+a !== +a) return +b !== +b;
    return +a === 0 ? 1 / +a === 1 / b : +a === +b; /* 7 Date Boolean */
    return +a === +b; /* 8 Symbol */
    var SymbolProto = typeof Symbol !== 'undefined' ? Symbol.prototype : null;
    return SymbolProto.valueOf.call(a) === SymbolProto.valueOf.call(b);
  6. Object Functions(补)

  7. 位运算符&换算成二进制后按位与计算;不同于&&;
    // 判断偶数
    var isEven = function(num) {
    return !(num & 1);
    };
  8. 数组去重

    /* 1 一一比较 */
    function removeSame(arr){
    return arr.filter(function(item, index, arr){
    return arr.indexOf(item) === index;
    });
    } /* 2 */
    [...new Set(arr)] /* 3 */
    Array.from(new Set(arr));
  9. flatten
    // shallow为false深度展开,当shallow strict都为true可忽略非数组元素
    
    var flatten = function(input, shallow, strict, output) {
    output = output || [];
    var idx = output.length;
    for (var i = 0, length = getLength(input); i < length; i++) {
    var value = input[i];
    if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
    if (shallow) {
    var j = 0, len = value.length;
    while (j < len) output[idx++] = value[j++];
    } else {
    flatten(value, shallow, strict, output);
    idx = output.length;
    }
    } else if (!strict) {
    output[idx++] = value;
    }
    }
    return output;
    };
  10. _.compact _.difference  _.without(补)

  11. NaN和Number.NaN是一样的;只有Number.isNaN(NaN)才返回true,isNaN()会将参数现转换为数字类型;
    isNaN = function(obj) {
    Number.isNaN(Number(obj));
    } Number.isNaN = Number.isNaN || function(obj) {
    return typeof obj === "number" && isNaN(obj);
    } _.isNaN = function(obj) {
    return _.isNumber(obj) && isNaN(obj);
    };
  12. 类数组转为数组
    Array.prototype.slice.call(obj) 或 Array.from(obj)
    // 优化(传递arguments给任何参数,将导致Chrome和Node中使用的V8引擎跳过对其的优化,这也将使性能相当慢)
    
    var args = new Array(arguments.length);
    for(var i = 0; i < args.length; ++i) {
    args[i] = arguments[i];
    }
  13. 数组乱序
    /* 1 O(n^2)*/
    function shuffle(arr) {
    var result = [];
    while (arr.length) {
    var index = ~~(Math.random() * arr.length); // 两次按位取反,无论正负,去掉小数点后面的数
    result.push(arr[index]);
    arr.splice(index, 1);
    }
    return result;
    } /* 2 O(nlogn)*/
    function shuffle(arr) {
    return arr.sort(function(a, b) {
    return Math.random() - 0.5;
    });
    } /* 3 Fisher–Yates Shuffle 遍历数组 将其与之前的元素交换 O(n)*/
    function shuffle(arr){
    var len = arr.length;
    var shuffled = Array(len);
    for(var i=0, rand; i < len; i++){
    rand = ~~(Math.random()*(i+1));
    if(rand !== i){
    shuffled[i] = shuffled[rand];
    }
    shuffled[rand] = arr[i];
    }
    return shuffled;
    }
  14. Group(补)
  15. bind polyfill
    if (!Function.prototype.bind) {
    Function.prototype.bind = function(oThis) {
    if (typeof this !== 'function') {
    // closest thing possible to the ECMAScript 5
    // internal IsCallable function
    throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }
    var aArgs = Array.prototype.slice.call(arguments, 1),
    fToBind = this,
    fNOP = function() {},
    fBound = function() {
    return fToBind.apply(this instanceof fNOP
    ? this
    : oThis,
    // 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
    aArgs.concat(Array.prototype.slice.call(arguments)));
    };
    // 维护原型关系
    if (this.prototype) {
    // Function.prototype doesn't have a prototype property
    fNOP.prototype = this.prototype;
    }
    fBound.prototype = new fNOP();
    return fBound;
    };
    }
  16. 节流
    _.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;
    };
  17. 防抖
     _.debounce = function(func, wait, immediate) {
    var timeout, result; var later = function(context, args) {
    timeout = null;
    if (args) result = func.apply(context, args);
    }; var debounced = restArguments(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;
    };

读underscore的更多相关文章

  1. underscore源码阅读记录

    这几天有大神推荐读underscore源码,趁着项目测试的空白时间,看了一下. 整个underscore包括了常用的工具函数,下面以1.3.3源码为例分析一下. _.size = function(o ...

  2. 有哪些值得一读的优秀开源 JS 代码

    有哪些值得一读的优秀开源 JS 代码 采纳 首先,没有“必须”读的源代码(我发现我特喜欢说首先……),因为读源代码不是做功课,只有用到或是非常好奇才会去读,当成“日常”去做是没有意义的. 当然有些人会 ...

  3. underscore 源码解读之 bind 方法的实现

    自从进入七月以来,我的 underscore 源码解读系列 更新缓慢,再这样下去,今年更完的目标似乎要落空,赶紧写一篇压压惊. 前文 跟大家简单介绍了下 ES5 中的 bind 方法以及使用场景(没读 ...

  4. UnderScore源代码阅读1

    读一下underscore源代码,用于自己学习,个人理解,如果有不对的地方希望指正,谢谢 我觉着阅读的顺序按照从整体到局部,从架构到细节较好. 1.整体架构 (function() {}.call(t ...

  5. 一次发现underscore源码bug的经历以及对学术界『拿来主义』的思考

    事情是如何发生的 最近干了件事情,发现了 underscore 源码的一个 bug.这件事本身并没有什么可说的,但是过程值得我们深思,记录如下,各位看官仁者见仁智者见智. 平时有浏览园区首页文章的习惯 ...

  6. 停止使用循环 教你用underscore优雅的写代码

    你一天(一周)内写了多少个循环了? var i; for(i = 0; i < someArray.length; i++) {   var someThing = someArray[i]; ...

  7. `~!$^*()[]{}\|;:'",<>/?在英文怎么读?

    `~!$^*()[]{}\|;:'",<>/?在英文怎么读? 'exclam'='!' 'at'='@' 'numbersign'='#' 'dollar'='$' 'perce ...

  8. underscore.js源码解析(一)

    一直想针对一个框架的源码好好的学习一下编程思想和技巧,提高一下自己的水平,但是看过一些框架的源码,都感觉看的莫名其妙,看不太懂,最后找到这个underscore.js由于这个比较简短,一千多行,而且读 ...

  9. underscore.js源码解析(五)—— 完结篇

    最近公司各种上线,所以回家略感疲惫就懒得写了,这次我准备把剩下的所有方法全部分析完,可能篇幅过长...那么废话不多说让我们进入正题. 没看过前几篇的可以猛戳这里: underscore.js源码解析( ...

随机推荐

  1. SpringMVC中使用@ResponseBody注解将任意POJO对象返回值转换成json进行返回

    @ResponseBody 作用: 该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区. ...

  2. Win10安装软件时出现2502、2503错误代码的问题

    主要是权限不够,C:\Windows\temp先访问权限 找到该目录,选择temp文件夹,右键弹出快捷菜单,选择“管理员取得所有权”.确定,OK. 再安装软件OK.

  3. 国外DNS服务器总结

    国外12个免费的DNS DNS(即Domain Name System,域名系统),是因特网上作为域名和IP地址相互映射的一个分布式数据库,能够让用户更方便的访问互联网,而不用去记住能够被机器直接读取 ...

  4. Ubbeditor的使用

    简单介绍: 作为一种放在客户端文本编辑器,此时不能支持将JS.Html代码直接发送给服务器,这样将会给服务器带来极大的危险,比如UMEditor(富文本编辑器),它的使用需要关闭服务器端的代码检查的, ...

  5. ubuntu16.04下安装opencv-nonfree

    在写计算机视觉与导航技术的课程作业,是关于sift和surf特征的提取及匹配.因为opencv中都有直接的函数可以调用. 关于SIFT和SURF的特征在opencv的nonfree模块中,从字面意思就 ...

  6. 磁盘 I/O 性能监控的指标

    指标 1:每秒 I/O 数(IOPS 或 tps) 对于磁盘来说,一次磁盘的连续读或者连续写称为一次磁盘 I/O, 磁盘的 IOPS 就是每秒磁盘连续读次数和连续写次数之和.当传输小块不连续数据时,该 ...

  7. ubuntu打开txt乱码

    因为不支持中文 输入命令: iconv -f gbk -t utf8 filename.txt > filename.txt.utf8

  8. nodejs Async详解之三:集合操作

    Async提供了很多针对集合的函数,可以简化我们对集合进行异步操作时的步骤.如下: forEach:对集合中每个元素进行异步操作 map:对集合中的每个元素通过异步操作得到另一个值,得到新的集合 fi ...

  9. Django Rest Framework(3)-----APIView与Viewsets

    REST framework提供了一个APIView类,它是Django的View类的子类. REST framework主要的几种view以及他们之间的关系: mixins 到目前为止,我们使用的创 ...

  10. ref out 区别

    1.使用ref型参数时,传入的参数必须先被初始化.对out而言,必须在方法中对其完成初始化. 2.使用ref和out时,在方法的参数和执行方法时,都要加Ref或Out关键字.以满足匹配. 3.out适 ...