读underscore
最近在拜读只有1700行(含注释)代码的Underscore.js 1.9.1,记录一些东西
(参考https://underscorejs.org/underscore.js,https://github.com/hanzichi/underscore-analysis)
- void 0替代了undefined;因为在低版本ie中undefined可以被重新赋值,或者在局部作用域中也可以被重新赋值;所以undefined显得不那么靠谱,于是就用void 0替代了undefined,void运算符对表达式求值都会返回undefined;
- 数据类型判断,先看原声方法支持与否,不支持再用Object.prototype.toString.call方法进行判断;不过在 IE < 9 下对 arguments 调用 Object.prototype.toString.call,结果是 [object Object],这时可以用arguments.callee是否存在来判断;dom元素判断方法为存在且nodeType为1;
- 如果在对象中重写了原型上的不可枚举属性,那么for in是可以取到这个属性的;但是在低版本ie中是不会取到的,它们会被认定为不可枚举属性;可以用obj.propertyIsEnumerable(prop)来确定对象中指定的属性是否可以被for in循环枚举,但是通过原型链继承的属性除外;
- createAssigner(补)
- 判断是否相同(注意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); Object Functions(补)
- 位运算符&换算成二进制后按位与计算;不同于&&;
// 判断偶数
var isEven = function(num) {
return !(num & 1);
}; 数组去重
/* 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));- 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;
}; _.compact _.difference _.without(补)
- 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);
}; - 类数组转为数组
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];
} - 数组乱序
/* 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;
} - Group(补)
- 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;
};
} - 节流
_.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;
}; - 防抖
_.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的更多相关文章
- underscore源码阅读记录
这几天有大神推荐读underscore源码,趁着项目测试的空白时间,看了一下. 整个underscore包括了常用的工具函数,下面以1.3.3源码为例分析一下. _.size = function(o ...
- 有哪些值得一读的优秀开源 JS 代码
有哪些值得一读的优秀开源 JS 代码 采纳 首先,没有“必须”读的源代码(我发现我特喜欢说首先……),因为读源代码不是做功课,只有用到或是非常好奇才会去读,当成“日常”去做是没有意义的. 当然有些人会 ...
- underscore 源码解读之 bind 方法的实现
自从进入七月以来,我的 underscore 源码解读系列 更新缓慢,再这样下去,今年更完的目标似乎要落空,赶紧写一篇压压惊. 前文 跟大家简单介绍了下 ES5 中的 bind 方法以及使用场景(没读 ...
- UnderScore源代码阅读1
读一下underscore源代码,用于自己学习,个人理解,如果有不对的地方希望指正,谢谢 我觉着阅读的顺序按照从整体到局部,从架构到细节较好. 1.整体架构 (function() {}.call(t ...
- 一次发现underscore源码bug的经历以及对学术界『拿来主义』的思考
事情是如何发生的 最近干了件事情,发现了 underscore 源码的一个 bug.这件事本身并没有什么可说的,但是过程值得我们深思,记录如下,各位看官仁者见仁智者见智. 平时有浏览园区首页文章的习惯 ...
- 停止使用循环 教你用underscore优雅的写代码
你一天(一周)内写了多少个循环了? var i; for(i = 0; i < someArray.length; i++) { var someThing = someArray[i]; ...
- `~!$^*()[]{}\|;:'",<>/?在英文怎么读?
`~!$^*()[]{}\|;:'",<>/?在英文怎么读? 'exclam'='!' 'at'='@' 'numbersign'='#' 'dollar'='$' 'perce ...
- underscore.js源码解析(一)
一直想针对一个框架的源码好好的学习一下编程思想和技巧,提高一下自己的水平,但是看过一些框架的源码,都感觉看的莫名其妙,看不太懂,最后找到这个underscore.js由于这个比较简短,一千多行,而且读 ...
- underscore.js源码解析(五)—— 完结篇
最近公司各种上线,所以回家略感疲惫就懒得写了,这次我准备把剩下的所有方法全部分析完,可能篇幅过长...那么废话不多说让我们进入正题. 没看过前几篇的可以猛戳这里: underscore.js源码解析( ...
随机推荐
- ThinkPHP流程控制!
IF判断: 在thinkphp 中不能使用 <> 这样的尖括号: <if condition='表达式'> <elseif condition='表达式'/> &l ...
- Oracle安装部署之RAC安装环境配置脚本
#!/bin/bash#Usage:Log on as the superuser('root'),and then execute the command:#./1preusers.sh group ...
- Tfs 2015 代理池配置笔记
Tfs的构建代理池其实是在代理服务器上开启一个TFSBuild的代理服务,配好相关的Tfs地址后,就能在Tfs管理界面看到了. 如果是Tfs服务和发布代理是同一台服务器,具体操作详见: 安装TFS20 ...
- linux 安装libevent
今天再ubuntu下安装libevent,下载源码 tar -xzvf libevent-1.4.15.tar.gz cd libevent-1.4.15 ./configure make make ...
- 【Python学习 】Python实现的FTP上传和下载功能
一.背景 最近公司的一些自动化操作需要使用Python来实现FTP的上传和下载功能.因此参考网上的例子,撸了一段代码来实现了该功能,下面做个记录. 二.ftplib介绍 Python中默认安装的ftp ...
- 【接口测试】接口概念及Json相关
一.接口相关概念 1.什么是接口? 接口:接口就是系统A程序中留的其他系统B访问系统A的接口(实际上是系统某个代码文件下某一个可访问的方法.).其他系统B可以调用这个方法a对系统A中的方法a进行访问从 ...
- editplus的常用快捷键
小编给大家整理了一些软件的快捷键.http://www.downza.cn/soft/187814.html 创建当前行的副本:Ctrl+J 反转选定文本的大小写:Ctrl+K 选择当前行:Ctrl+ ...
- JS操作符转化数字
在Node.js源代码里,随处可见使用各种符号处理字符串为数字的.可能由于不同人编写,使用的风格也各有不同. 基本上有下面几种. 将字符串转化为数字 + 将一个数字的字符串转化为数字很简单的一种做法就 ...
- Spark ListenerBus 和 MetricsSystem 体系分析
转载自:https://yq.aliyun.com/articles/60196 摘要: Spark 事件体系的中枢是ListenerBus,由该类接受Event并且分发给各个Listener.Met ...
- [css]浮动-清除浮动的3种方法
清除浮动的方法: 内墙法 注: 这是个奇淫技巧,没什么原理可言,记住即可 这个技巧又使得父box重新可以被子box撑开高度了. 隔墙法-适用于2个box之间上下排列 由于2个box高度依旧是0, 彼此 ...